]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Hi, all
[postgresql] / src / bin / pg_dump / pg_dump.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *        pg_dump is an utility for dumping out a postgres database
5  * into a script file.
6  *
7  *      pg_dump will read the system catalogs in a database and
8  *      dump out a script that reproduces
9  *      the schema of the database in terms of
10  *                user-defined types
11  *                user-defined functions
12  *                tables
13  *                indices
14  *                aggregates
15  *                operators
16  *                ACL - grant/revoke
17  *
18  * the output script is SQL that is understood by PostgreSQL
19  *
20  * Copyright (c) 1994, Regents of the University of California
21  *
22  *
23  * IDENTIFICATION
24  *        $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.127 1999/12/27 15:42:43 momjian Exp $
25  *
26  * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
27  *
28  *       Applied 'insert string' patch from "Marc G. Fournier" <scrappy@ki.net>
29  *       Added '-t table' option
30  *       Added '-a' option
31  *       Added '-da' option
32  *
33  * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
34  *
35  *       - Fixed dumpTable output to output lengths for char and varchar types!
36  *       - Added single. quote to twin single quote expansion for 'insert' string
37  *         mode.
38  *
39  * Modifications - 7/26/96 - asussman@vidya.com
40  *
41  *       - Fixed ouput lengths for char and varchar type where the length is variable (-1)
42  *
43  * Modifications - 6/1/97 - igor@sba.miami.edu
44  * - Added functions to free allocated memory used for retrieving
45  *       indices,tables,inheritance,types,functions and aggregates.
46  *       No more leaks reported by Purify.
47  *
48  *
49  * Modifications - 1/26/98 - pjlobo@euitt.upm.es
50  *               - Added support for password authentication
51  *-------------------------------------------------------------------------
52  */
53
54 #include <unistd.h>                             /* for getopt() */
55 #include <ctype.h>
56
57 #include "postgres.h"
58
59 #ifdef HAVE_GETOPT_H
60 #include <getopt.h>
61 #endif
62 #ifdef HAVE_TERMIOS_H
63 #include <termios.h>
64 #endif
65
66 #include "access/attnum.h"
67 #include "access/htup.h"
68 #include "catalog/pg_index.h"
69 #include "catalog/pg_language.h"
70 #include "catalog/pg_trigger.h"
71 #include "catalog/pg_type.h"
72
73 #include "libpq-fe.h"
74 #ifndef HAVE_STRDUP
75 #include "strdup.h"
76 #endif
77
78 #include "pg_dump.h"
79
80 static void dumpSequence(FILE *fout, TableInfo tbinfo);
81 static void dumpACL(FILE *fout, TableInfo tbinfo);
82 static void dumpTriggers(FILE *fout, const char *tablename,
83                          TableInfo *tblinfo, int numTables);
84 static void dumpRules(FILE *fout, const char *tablename,
85                   TableInfo *tblinfo, int numTables);
86 static char *checkForQuote(const char *s);
87 static void clearTableInfo(TableInfo *, int);
88 static void dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
89                         TypeInfo *tinfo, int numTypes);
90 static int      findLastBuiltinOid(void);
91 static bool isViewRule(char *relname);
92 static void setMaxOid(FILE *fout);
93
94 static void AddAcl(char *aclbuf, const char *keyword);
95 static char *GetPrivileges(const char *s);
96 static void becomeUser(FILE *fout, const char *username);
97
98 extern char *optarg;
99 extern int      optind,
100                         opterr;
101
102 /* global decls */
103 bool            g_verbose;                      /* User wants verbose narration of our
104                                                                  * activities. */
105 int                     g_last_builtin_oid; /* value of the last builtin oid */
106 FILE       *g_fout;                             /* the script file */
107 PGconn     *g_conn;                             /* the database connection */
108
109 bool            force_quotes;           /* User wants to suppress double-quotes */
110 bool            dumpData;                       /* dump data using proper insert strings */
111 bool            attrNames;                      /* put attr names into insert strings */
112 bool            schemaOnly;
113 bool            dataOnly;
114 bool            aclsSkip;
115 bool            dropSchema;
116
117 char            g_opaque_type[10];      /* name for the opaque type */
118
119 /* placeholders for the delimiters for comments */
120 char            g_comment_start[10];
121 char            g_comment_end[10];
122
123
124 static void
125 usage(const char *progname)
126 {
127         fprintf(stderr,
128                 "\nUsage: %s [options] dbname\n\n", progname);
129
130 #ifdef HAVE_GETOPT_LONG
131         fprintf(stderr,
132         
133         "    -a, --data-only         dump out only the data, no schema\n"
134         "    -c, --clean             clean(drop) schema prior to create\n"
135         "    -d, --insert-proper     dump data as proper insert strings\n"
136         "    -D, --insert-attr       dump data as inserts with attribute names\n"
137         "    -f, --out file          script output filename\n"
138         "    -h, --host hostname     server host name\n"
139         "    -n, --no-quotes         suppress most quotes around identifiers\n"
140         "    -N, --quotes            enable most quotes around identifiers\n"
141         "    -o, --oids              dump object id's (oids)\n"
142         "    -p, --port port         server port number\n"
143         "    -s, --schema-only       dump out only the schema, no data\n"
144         "    -t, --table table       dump for this table only\n"
145         "    -u, --password          use password authentication\n"
146         "    -v, --verbose           verbose\n"
147         "    -x, --no-acl            do not dump ACL's (grant/revoke)\n"
148         "    -?, --help              show this help message\n"
149         
150         ); /* fprintf */
151 #else
152         fprintf(stderr,
153         
154         "    -a                      dump out only the data, no schema\n"
155         "    -c                      clean(drop) schema prior to create\n"
156         "    -d                      dump data as proper insert strings\n"
157         "    -D                      dump data as inserts with attribute names\n"
158         "    -f filename             script output filename\n"
159         "    -h hostname             server host name\n"
160         "    -n                      suppress most quotes around identifiers\n"
161         "    -N                      enable most quotes around identifiers\n"
162         "    -o                      dump object id's (oids)\n"
163         "    -p port                 server port number\n"
164         "    -s                      dump out only the schema, no data\n"
165         "    -t table                dump for this table only\n"
166         "    -u                      use password authentication\n"
167         "    -v                      verbose\n"
168         "    -x                      do not dump ACL's (grant/revoke)\n"
169         "    -?                      show this help message\n"
170         
171         ); /* fprintf */
172 #endif
173         
174         fprintf(stderr,
175                 "\nIf dbname is not supplied, then the DATABASE environment variable value is used.\n\n");
176
177         exit(1);
178 }
179
180 static void
181 exit_nicely(PGconn *conn)
182 {
183         PQfinish(conn);
184         exit(1);
185 }
186
187
188 /*
189  * isViewRule
190  *                              Determine if the relation is a VIEW
191  *
192  */
193 static bool
194 isViewRule(char *relname)
195 {
196         PGresult   *res;
197         int                     ntups;
198         PQExpBuffer     query = createPQExpBuffer();
199
200         appendPQExpBuffer(query, "select relname from pg_class, pg_rewrite ");
201         appendPQExpBuffer(query, "where pg_class.oid = ev_class ");
202         appendPQExpBuffer(query, "and pg_rewrite.ev_type = '1' ");
203         appendPQExpBuffer(query, "and rulename = '_RET%s'", relname);
204
205         res = PQexec(g_conn, query->data);
206         if (!res ||
207                 PQresultStatus(res) != PGRES_TUPLES_OK)
208         {
209                 fprintf(stderr, "isViewRule(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
210                 exit_nicely(g_conn);
211         }
212
213         ntups = PQntuples(res);
214
215         PQclear(res);
216         return ntups > 0 ? TRUE : FALSE;
217 }
218
219 #define COPYBUFSIZ              8192
220
221
222 static void
223 dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
224 {
225
226         PGresult   *res;
227         char            query[255];
228         int                     ret;
229         bool            copydone;
230         char            copybuf[COPYBUFSIZ];
231
232         if (oids == true)
233         {
234                 fprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
235                                 fmtId(classname, force_quotes));
236                 sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
237                                 fmtId(classname, force_quotes));
238         }
239         else
240         {
241                 fprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
242                 sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
243         }
244         res = PQexec(g_conn, query);
245         if (!res ||
246                 PQresultStatus(res) == PGRES_FATAL_ERROR)
247         {
248                 fprintf(stderr, "SQL query to dump the contents of Table '%s' "
249                                 "did not execute.  Explanation from backend: '%s'.\n"
250                                 "The query was: '%s'.\n",
251                                 classname, PQerrorMessage(g_conn), query);
252                 exit_nicely(g_conn);
253         }
254         else
255         {
256                 if (PQresultStatus(res) != PGRES_COPY_OUT)
257                 {
258                         fprintf(stderr, "SQL query to dump the contents of Table '%s' "
259                                         "executed abnormally.\n"
260                                         "PQexec() returned status %d when %d was expected.\n"
261                                         "The query was: '%s'.\n",
262                                   classname, PQresultStatus(res), PGRES_COPY_OUT, query);
263                         exit_nicely(g_conn);
264                 }
265                 else
266                 {
267                         copydone = false;
268                         while (!copydone)
269                         {
270                                 ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
271
272                                 if (copybuf[0] == '\\' &&
273                                         copybuf[1] == '.' &&
274                                         copybuf[2] == '\0')
275                                 {
276                                         copydone = true;        /* don't print this... */
277                                 }
278                                 else
279                                 {
280                                         fputs(copybuf, fout);
281                                         switch (ret)
282                                         {
283                                                 case EOF:
284                                                         copydone = true;
285                                                         /* FALLTHROUGH */
286                                                 case 0:
287                                                         fputc('\n', fout);
288                                                         break;
289                                                 case 1:
290                                                         break;
291                                         }
292                                 }
293                         }
294                         fprintf(fout, "\\.\n");
295                 }
296                 ret = PQendcopy(g_conn);
297                 if (ret != 0)
298                 {
299                         fprintf(stderr, "SQL query to dump the contents of Table '%s' "
300                                         "did not execute correctly.  After we read all the "
301                                  "table contents from the backend, PQendcopy() failed.  "
302                                         "Explanation from backend: '%s'.\n"
303                                         "The query was: '%s'.\n",
304                                         classname, PQerrorMessage(g_conn), query);
305                         PQclear(res);
306                         exit_nicely(g_conn);
307                 }
308         }
309 }
310
311
312
313 static void
314 dumpClasses_dumpData(FILE *fout, const char *classname)
315 {
316         PGresult        *res;
317         PQExpBuffer     q = createPQExpBuffer();
318         int                     tuple;
319         int                     field;
320         const char      *expsrc;
321
322         appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
323         res = PQexec(g_conn, q->data);
324         if (!res ||
325                 PQresultStatus(res) != PGRES_TUPLES_OK)
326         {
327                 fprintf(stderr, "dumpClasses(): command failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
328                 exit_nicely(g_conn);
329         }
330         for (tuple = 0; tuple < PQntuples(res); tuple++)
331         {
332                 fprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
333                 if (attrNames == true)
334                 {
335                         resetPQExpBuffer(q);
336                         appendPQExpBuffer(q, "(");
337                         for (field = 0; field < PQnfields(res); field++)
338                         {
339                                 if (field > 0)
340                                         appendPQExpBuffer(q, ",");
341                                 appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
342                         }
343                         appendPQExpBuffer(q, ") ");
344                         fprintf(fout, "%s", q->data);
345                 }
346                 fprintf(fout, "VALUES (");
347                 for (field = 0; field < PQnfields(res); field++)
348                 {
349                         if (field > 0)
350                                 fprintf(fout, ",");
351                         if (PQgetisnull(res, tuple, field))
352                         {
353                                 fprintf(fout, "NULL");
354                                 continue;
355                         }
356                         switch (PQftype(res, field))
357                         {
358                                 case INT2OID:
359                                 case INT4OID:
360                                 case OIDOID:            /* int types */
361                                 case FLOAT4OID:
362                                 case FLOAT8OID:         /* float types */
363                                         /* These types are printed without quotes */
364                                         fprintf(fout, "%s",
365                                                         PQgetvalue(res, tuple, field));
366                                         break;
367                                 default:
368                                         /*
369                                          * All other types are printed as string literals,
370                                          * with appropriate escaping of special
371                                          * characters. Quote mark ' goes to '' per SQL
372                                          * standard, other stuff goes to \ sequences.
373                                          */
374                                         putc('\'', fout);
375                                         expsrc = PQgetvalue(res, tuple, field);
376                                         while (*expsrc)
377                                         {
378                                                 char            ch = *expsrc++;
379
380                                                 if (ch == '\\' || ch == '\'')
381                                                 {
382                                                         putc(ch, fout);                 /* double these */
383                                                         putc(ch, fout);
384                                                 }
385                                                 else if (ch < '\040')
386                                                 {
387                                                         /* generate octal escape for control chars */
388                                                         putc('\\', fout);
389                                                         putc(((ch >> 6) & 3) + '0', fout);
390                                                         putc(((ch >> 3) & 7) + '0', fout);
391                                                         putc((ch & 7) + '0', fout);
392                                                 }
393                                                 else
394                                                         putc(ch, fout);
395                                         }
396                                         putc('\'', fout);
397                                         break;
398                         }
399                 }
400                 fprintf(fout, ");\n");
401         }
402         PQclear(res);
403 }
404
405
406
407 /*
408  * DumpClasses -
409  *        dump the contents of all the classes.
410  */
411 static void
412 dumpClasses(const TableInfo *tblinfo, const int numTables, FILE *fout,
413                         const char *onlytable, const bool oids)
414 {
415
416         int                     i;
417         char       *all_only;
418
419         if (onlytable == NULL)
420                 all_only = "all";
421         else
422                 all_only = "only";
423
424         if (g_verbose)
425                 fprintf(stderr, "%s dumping out the contents of %s %d table%s/sequence%s %s\n",
426                                 g_comment_start, all_only,
427                                 (onlytable == NULL) ? numTables : 1,
428                                 (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
429                                 g_comment_end);
430
431         /* Dump SEQUENCEs first (if dataOnly) */
432         if (dataOnly)
433         {
434                 for (i = 0; i < numTables; i++)
435                 {
436                         if (!(tblinfo[i].sequence))
437                                 continue;
438                         if (!onlytable || (!strcmp(tblinfo[i].relname, onlytable)))
439                         {
440                                 if (g_verbose)
441                                         fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
442                                          g_comment_start, tblinfo[i].relname, g_comment_end);
443                                 becomeUser(fout, tblinfo[i].usename);
444                                 dumpSequence(fout, tblinfo[i]);
445                         }
446                 }
447         }
448
449         for (i = 0; i < numTables; i++)
450         {
451                 const char *classname = tblinfo[i].relname;
452
453                 /* Skip VIEW relations */
454                 if (isViewRule(tblinfo[i].relname))
455                         continue;
456
457                 if (tblinfo[i].sequence)/* already dumped */
458                         continue;
459
460                 if (!onlytable || (!strcmp(classname, onlytable)))
461                 {
462                         if (g_verbose)
463                                 fprintf(stderr, "%s dumping out the contents of Table '%s' %s\n",
464                                                 g_comment_start, classname, g_comment_end);
465
466                         becomeUser(fout, tblinfo[i].usename);
467
468                         if (!dumpData)
469                                 dumpClasses_nodumpData(fout, classname, oids);
470                         else
471                                 dumpClasses_dumpData(fout, classname);
472                 }
473         }
474 }
475
476
477 static void
478 prompt_for_password(char *username, char *password)
479 {
480         char            buf[512];
481         int                     length;
482
483 #ifdef HAVE_TERMIOS_H
484         struct termios t_orig,
485                                 t;
486
487 #endif
488
489         printf("Username: ");
490         fgets(username, 100, stdin);
491         length = strlen(username);
492         /* skip rest of the line */
493         if (length > 0 && username[length - 1] != '\n')
494         {
495                 do
496                 {
497                         fgets(buf, 512, stdin);
498                 } while (buf[strlen(buf) - 1] != '\n');
499         }
500         if (length > 0 && username[length - 1] == '\n')
501                 username[length - 1] = '\0';
502
503         printf("Password: ");
504 #ifdef HAVE_TERMIOS_H
505         tcgetattr(0, &t);
506         t_orig = t;
507         t.c_lflag &= ~ECHO;
508         tcsetattr(0, TCSADRAIN, &t);
509 #endif
510         fgets(password, 100, stdin);
511 #ifdef HAVE_TERMIOS_H
512         tcsetattr(0, TCSADRAIN, &t_orig);
513 #endif
514
515         length = strlen(password);
516         /* skip rest of the line */
517         if (length > 0 && password[length - 1] != '\n')
518         {
519                 do
520                 {
521                         fgets(buf, 512, stdin);
522                 } while (buf[strlen(buf) - 1] != '\n');
523         }
524         if (length > 0 && password[length - 1] == '\n')
525                 password[length - 1] = '\0';
526
527         printf("\n\n");
528 }
529
530
531 int
532 main(int argc, char **argv)
533 {
534         int                     c;
535         const char *progname;
536         const char *filename = NULL;
537         const char *dbname = NULL;
538         const char *pghost = NULL;
539         const char *pgport = NULL;
540         char       *tablename = NULL;
541         bool            oids = false;
542         TableInfo  *tblinfo;
543         int                     numTables;
544         char            connect_string[512] = "";
545         char            tmp_string[128];
546         char            username[100];
547         char            password[100];
548         bool            use_password = false;
549
550 #ifdef HAVE_GETOPT_LONG
551         static struct option long_options[] = {
552                 {"data-only", no_argument, NULL, 'a'},
553                 {"clean", no_argument, NULL, 'c'},
554                 {"insert-proper",no_argument, NULL, 'd'},
555                 {"insert-attr", no_argument, NULL, 'D'},
556                 {"out", required_argument, NULL, 'f'},
557                 {"to-file", required_argument, NULL, 'f'},
558                 {"host", required_argument, NULL, 'h'},
559                 {"no-quotes", no_argument, NULL, 'n'},
560                 {"quotes", no_argument, NULL, 'N'},
561                 {"oids", no_argument, NULL, 'o'},
562                 {"port", required_argument, NULL, 'p'},
563                 {"schema-only", no_argument, NULL, 's'},
564                 {"table", required_argument, NULL, 't'},
565                 {"password", no_argument, NULL, 'u'},
566                 {"verbose", no_argument, NULL, 'v'},
567                 {"no-acl", no_argument, NULL, 'x'},
568                 {"help", no_argument, NULL, '?'},
569         };        
570         int             optindex;
571 #endif
572
573         g_verbose = false;
574         force_quotes = true;
575         dropSchema = false;
576
577         strcpy(g_comment_start, "-- ");
578         g_comment_end[0] = '\0';
579         strcpy(g_opaque_type, "opaque");
580
581         dataOnly = schemaOnly = dumpData = attrNames = false;
582
583         progname = *argv;
584
585 #ifdef HAVE_GETOPT_LONG
586         while ((c = getopt_long(argc, argv, "acdDf:h:nNop:st:uvxz?", long_options, &optindex)) != -1)
587 #else
588         while ((c = getopt(argc, argv, "acdDf:h:nNop:st:uvxz?")) != -1)
589 #endif
590         {
591                 switch (c)
592                 {
593                         case 'a':                       /* Dump data only */
594                                 dataOnly = true;
595                                 break;
596                         case 'c':                       /* clean (i.e., drop) schema prior to
597                                                                  * create */
598                                 dropSchema = true;
599                                 break;
600                         case 'd':                       /* dump data as proper insert strings */
601                                 dumpData = true;
602                                 break;
603                         case 'D':                       /* dump data as proper insert strings with
604                                                                  * attr names */
605                                 dumpData = true;
606                                 attrNames = true;
607                                 break;
608                         case 'f':                       /* output file name */
609                                 filename = optarg;
610                                 break;
611                         case 'h':                       /* server host */
612                                 pghost = optarg;
613                                 break;
614                         case 'n':                       /* Do not force double-quotes on
615                                                                  * identifiers */
616                                 force_quotes = false;
617                                 break;
618                         case 'N':                       /* Force double-quotes on identifiers */
619                                 force_quotes = true;
620                                 break;
621                         case 'o':                       /* Dump oids */
622                                 oids = true;
623                                 break;
624                         case 'p':                       /* server port */
625                                 pgport = optarg;
626                                 break;
627                         case 's':                       /* dump schema only */
628                                 schemaOnly = true;
629                                 break;
630                         case 't':                       /* Dump data for this table only */
631                                 {
632                                         int                     i;
633
634                                         tablename = strdup(optarg);
635
636                                         /*
637                                          * quoted string? Then strip quotes and preserve
638                                          * case...
639                                          */
640                                         if (tablename[0] == '"')
641                                         {
642                                                 strcpy(tablename, &tablename[1]);
643                                                 if (*(tablename + strlen(tablename) - 1) == '"')
644                                                         *(tablename + strlen(tablename) - 1) = '\0';
645                                         }
646                                         /* otherwise, convert table name to lowercase... */
647                                         else
648                                         {
649                                                 for (i = 0; tablename[i]; i++)
650                                                         if (isascii((unsigned char) tablename[i]) &&
651                                                                 isupper(tablename[i]))
652                                                                 tablename[i] = tolower(tablename[i]);
653                                         }
654                                 }
655                                 break;
656                         case 'u':
657                                 use_password = true;
658                                 break;
659                         case 'v':                       /* verbose */
660                                 g_verbose = true;
661                                 break;
662                         case 'x':                       /* skip ACL dump */
663                                 aclsSkip = true;
664                                 break;
665                         case 'z':                       /* Old ACL option bjm 1999/05/27 */
666                                 fprintf(stderr,
667                                  "%s: The -z option(dump ACLs) is now the default, continuing.\n",
668                                         progname);
669                                 break;
670                         case '?':       
671                         default:
672                                 usage(progname);
673                                 break;
674                 }
675         }
676
677         if (dumpData == true && oids == true)
678         {
679                 fprintf(stderr,
680                          "%s: INSERT's can not set oids, so INSERT and OID options can not be used together.\n",
681                                 progname);
682                 exit(2);
683         }
684                 
685         /* open the output file */
686         if (filename == NULL)
687                 g_fout = stdout;
688         else
689         {
690 #ifndef __CYGWIN32__
691                 g_fout = fopen(filename, "w");
692 #else
693                 g_fout = fopen(filename, "wb");
694 #endif
695                 if (g_fout == NULL)
696                 {
697                         fprintf(stderr,
698                                  "%s: could not open output file named %s for writing\n",
699                                         progname, filename);
700                         exit(2);
701                 }
702         }
703
704         /* find database */
705         if (!(dbname = argv[optind]) &&
706                 !(dbname = getenv("DATABASE")))
707         {
708                 fprintf(stderr, "%s: no database name specified\n", progname);
709                 exit(2);
710         }
711
712         /* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
713         if (pghost != NULL)
714         {
715                 sprintf(tmp_string, "host=%s ", pghost);
716                 strcat(connect_string, tmp_string);
717         }
718         if (pgport != NULL)
719         {
720                 sprintf(tmp_string, "port=%s ", pgport);
721                 strcat(connect_string, tmp_string);
722         }
723         if (dbname != NULL)
724         {
725                 sprintf(tmp_string, "dbname=%s ", dbname);
726                 strcat(connect_string, tmp_string);
727         }
728         if (use_password)
729         {
730                 prompt_for_password(username, password);
731                 strcat(connect_string, "authtype=password ");
732                 sprintf(tmp_string, "user=%s ", username);
733                 strcat(connect_string, tmp_string);
734                 sprintf(tmp_string, "password=%s ", password);
735                 strcat(connect_string, tmp_string);
736                 MemSet(tmp_string, 0, sizeof(tmp_string));
737                 MemSet(password, 0, sizeof(password));
738         }
739         g_conn = PQconnectdb(connect_string);
740         MemSet(connect_string, 0, sizeof(connect_string));
741         /* check to see that the backend connection was successfully made */
742         if (PQstatus(g_conn) == CONNECTION_BAD)
743         {
744                 fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
745                 fprintf(stderr, "%s\n", PQerrorMessage(g_conn));
746                 exit_nicely(g_conn);
747         }
748
749         /*
750          * Start serializable transaction to dump consistent data
751          */
752         {
753                 PGresult   *res;
754
755                 res = PQexec(g_conn, "begin");
756                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
757                 {
758                         fprintf(stderr, "BEGIN command failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
759                         exit_nicely(g_conn);
760                 }
761                 PQclear(res);
762                 res = PQexec(g_conn, "set transaction isolation level serializable");
763                 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
764                 {
765                         fprintf(stderr, "SET TRANSACTION command failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
766                         exit_nicely(g_conn);
767                 }
768                 PQclear(res);
769         }
770
771         g_last_builtin_oid = findLastBuiltinOid();
772
773         if (oids == true)
774                 setMaxOid(g_fout);
775         if (!dataOnly)
776         {
777                 if (g_verbose)
778                         fprintf(stderr, "%s last builtin oid is %u %s\n",
779                                         g_comment_start, g_last_builtin_oid, g_comment_end);
780                 tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip);
781         }
782         else
783                 tblinfo = dumpSchema(NULL, &numTables, tablename, aclsSkip);
784
785         if (!schemaOnly)
786                 dumpClasses(tblinfo, numTables, g_fout, tablename, oids);
787
788         if (!dataOnly)                          /* dump indexes and triggers at the end
789                                                                  * for performance */
790         {
791                 dumpSchemaIdx(g_fout, tablename, tblinfo, numTables);
792                 dumpTriggers(g_fout, tablename, tblinfo, numTables);
793                 dumpRules(g_fout, tablename, tblinfo, numTables);
794         }
795
796         fflush(g_fout);
797         if (g_fout != stdout)
798                 fclose(g_fout);
799
800         clearTableInfo(tblinfo, numTables);
801         PQfinish(g_conn);
802         exit(0);
803 }
804
805 /*
806  * getTypes:
807  *        read all base types in the system catalogs and return them in the
808  * TypeInfo* structure
809  *
810  *      numTypes is set to the number of types read in
811  *
812  */
813 TypeInfo   *
814 getTypes(int *numTypes)
815 {
816         PGresult   *res;
817         int                     ntups;
818         int                     i;
819         PQExpBuffer     query = createPQExpBuffer();
820         TypeInfo   *tinfo;
821
822         int                     i_oid;
823         int                     i_typowner;
824         int                     i_typname;
825         int                     i_typlen;
826         int                     i_typprtlen;
827         int                     i_typinput;
828         int                     i_typoutput;
829         int                     i_typreceive;
830         int                     i_typsend;
831         int                     i_typelem;
832         int                     i_typdelim;
833         int                     i_typdefault;
834         int                     i_typrelid;
835         int                     i_typbyval;
836         int                     i_usename;
837
838         /* find all base types */
839
840         /*
841          * we include even the built-in types because those may be used as
842          * array elements by user-defined types
843          */
844
845         /*
846          * we filter out the built-in types when we dump out the types
847          */
848
849         appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
850                   "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
851                   "typdefault, typrelid, typbyval, usename from pg_type, pg_user "
852                         "where typowner = usesysid");
853
854         res = PQexec(g_conn, query->data);
855         if (!res ||
856                 PQresultStatus(res) != PGRES_TUPLES_OK)
857         {
858                 fprintf(stderr, "getTypes(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
859                 exit_nicely(g_conn);
860         }
861
862         ntups = PQntuples(res);
863
864         tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
865
866         i_oid = PQfnumber(res, "oid");
867         i_typowner = PQfnumber(res, "typowner");
868         i_typname = PQfnumber(res, "typname");
869         i_typlen = PQfnumber(res, "typlen");
870         i_typprtlen = PQfnumber(res, "typprtlen");
871         i_typinput = PQfnumber(res, "typinput");
872         i_typoutput = PQfnumber(res, "typoutput");
873         i_typreceive = PQfnumber(res, "typreceive");
874         i_typsend = PQfnumber(res, "typsend");
875         i_typelem = PQfnumber(res, "typelem");
876         i_typdelim = PQfnumber(res, "typdelim");
877         i_typdefault = PQfnumber(res, "typdefault");
878         i_typrelid = PQfnumber(res, "typrelid");
879         i_typbyval = PQfnumber(res, "typbyval");
880         i_usename = PQfnumber(res, "usename");
881
882         for (i = 0; i < ntups; i++)
883         {
884                 tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
885                 tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
886                 tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
887                 tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
888                 tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
889                 tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
890                 tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
891                 tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
892                 tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
893                 tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
894                 tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
895                 tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
896                 tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
897                 tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
898
899                 if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
900                         tinfo[i].passedbyvalue = 0;
901                 else
902                         tinfo[i].passedbyvalue = 1;
903
904                 /*
905                  * check for user-defined array types, omit system generated ones
906                  */
907                 if ((strcmp(tinfo[i].typelem, "0") != 0) &&
908                         tinfo[i].typname[0] != '_')
909                         tinfo[i].isArray = 1;
910                 else
911                         tinfo[i].isArray = 0;
912         }
913
914         *numTypes = ntups;
915
916         PQclear(res);
917
918         return tinfo;
919 }
920
921 /*
922  * getOperators:
923  *        read all operators in the system catalogs and return them in the
924  * OprInfo* structure
925  *
926  *      numOprs is set to the number of operators read in
927  *
928  *
929  */
930 OprInfo    *
931 getOperators(int *numOprs)
932 {
933         PGresult        *res;
934         int                     ntups;
935         int                     i;
936         PQExpBuffer     query = createPQExpBuffer();
937
938         OprInfo    *oprinfo;
939
940         int                     i_oid;
941         int                     i_oprname;
942         int                     i_oprkind;
943         int                     i_oprcode;
944         int                     i_oprleft;
945         int                     i_oprright;
946         int                     i_oprcom;
947         int                     i_oprnegate;
948         int                     i_oprrest;
949         int                     i_oprjoin;
950         int                     i_oprcanhash;
951         int                     i_oprlsortop;
952         int                     i_oprrsortop;
953         int                     i_usename;
954
955         /*
956          * find all operators, including builtin operators, filter out
957          * system-defined operators at dump-out time
958          */
959
960         appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
961                         "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
962                         "oprcanhash, oprlsortop, oprrsortop, usename "
963                         "from pg_operator, pg_user "
964                         "where oprowner = usesysid");
965
966         res = PQexec(g_conn, query->data);
967         if (!res ||
968                 PQresultStatus(res) != PGRES_TUPLES_OK)
969         {
970                 fprintf(stderr, "getOperators(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
971                 exit_nicely(g_conn);
972         }
973
974         ntups = PQntuples(res);
975         *numOprs = ntups;
976
977         oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
978
979         i_oid = PQfnumber(res, "oid");
980         i_oprname = PQfnumber(res, "oprname");
981         i_oprkind = PQfnumber(res, "oprkind");
982         i_oprcode = PQfnumber(res, "oprcode");
983         i_oprleft = PQfnumber(res, "oprleft");
984         i_oprright = PQfnumber(res, "oprright");
985         i_oprcom = PQfnumber(res, "oprcom");
986         i_oprnegate = PQfnumber(res, "oprnegate");
987         i_oprrest = PQfnumber(res, "oprrest");
988         i_oprjoin = PQfnumber(res, "oprjoin");
989         i_oprcanhash = PQfnumber(res, "oprcanhash");
990         i_oprlsortop = PQfnumber(res, "oprlsortop");
991         i_oprrsortop = PQfnumber(res, "oprrsortop");
992         i_usename = PQfnumber(res, "usename");
993
994         for (i = 0; i < ntups; i++)
995         {
996                 oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
997                 oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
998                 oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
999                 oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
1000                 oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
1001                 oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
1002                 oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
1003                 oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
1004                 oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
1005                 oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
1006                 oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
1007                 oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
1008                 oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
1009                 oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1010         }
1011
1012         PQclear(res);
1013
1014         return oprinfo;
1015 }
1016
1017 void
1018 clearTypeInfo(TypeInfo *tp, int numTypes)
1019 {
1020         int                     i;
1021
1022         for (i = 0; i < numTypes; ++i)
1023         {
1024                 if (tp[i].oid)
1025                         free(tp[i].oid);
1026                 if (tp[i].typowner)
1027                         free(tp[i].typowner);
1028                 if (tp[i].typname)
1029                         free(tp[i].typname);
1030                 if (tp[i].typlen)
1031                         free(tp[i].typlen);
1032                 if (tp[i].typprtlen)
1033                         free(tp[i].typprtlen);
1034                 if (tp[i].typinput)
1035                         free(tp[i].typinput);
1036                 if (tp[i].typoutput)
1037                         free(tp[i].typoutput);
1038                 if (tp[i].typreceive)
1039                         free(tp[i].typreceive);
1040                 if (tp[i].typsend)
1041                         free(tp[i].typsend);
1042                 if (tp[i].typelem)
1043                         free(tp[i].typelem);
1044                 if (tp[i].typdelim)
1045                         free(tp[i].typdelim);
1046                 if (tp[i].typdefault)
1047                         free(tp[i].typdefault);
1048                 if (tp[i].typrelid)
1049                         free(tp[i].typrelid);
1050                 if (tp[i].usename)
1051                         free(tp[i].usename);
1052         }
1053         free(tp);
1054 }
1055
1056 void
1057 clearFuncInfo(FuncInfo *fun, int numFuncs)
1058 {
1059         int                     i,
1060                                 a;
1061
1062         if (!fun)
1063                 return;
1064         for (i = 0; i < numFuncs; ++i)
1065         {
1066                 if (fun[i].oid)
1067                         free(fun[i].oid);
1068                 if (fun[i].proname)
1069                         free(fun[i].proname);
1070                 if (fun[i].usename)
1071                         free(fun[i].usename);
1072                 for (a = 0; a < 8; ++a)
1073                         if (fun[i].argtypes[a])
1074                                 free(fun[i].argtypes[a]);
1075                 if (fun[i].prorettype)
1076                         free(fun[i].prorettype);
1077                 if (fun[i].prosrc)
1078                         free(fun[i].prosrc);
1079                 if (fun[i].probin)
1080                         free(fun[i].probin);
1081         }
1082         free(fun);
1083 }
1084
1085 static void
1086 clearTableInfo(TableInfo *tblinfo, int numTables)
1087 {
1088         int                     i,
1089                                 j;
1090
1091         for (i = 0; i < numTables; ++i)
1092         {
1093
1094                 if (tblinfo[i].oid)
1095                         free(tblinfo[i].oid);
1096                 if (tblinfo[i].relacl)
1097                         free(tblinfo[i].relacl);
1098                 if (tblinfo[i].usename)
1099                         free(tblinfo[i].usename);
1100
1101                 if (tblinfo[i].relname)
1102                         free(tblinfo[i].relname);
1103
1104                 if (tblinfo[i].sequence)
1105                         continue;
1106
1107                 /* Process Attributes */
1108                 for (j = 0; j < tblinfo[i].numatts; j++)
1109                 {
1110                         if (tblinfo[i].attnames[j])
1111                                 free(tblinfo[i].attnames[j]);
1112                         if (tblinfo[i].typnames[j])
1113                                 free(tblinfo[i].typnames[j]);
1114                 }
1115                 if (tblinfo[i].atttypmod)
1116                         free((int *) tblinfo[i].atttypmod);
1117                 if (tblinfo[i].inhAttrs)
1118                         free((int *) tblinfo[i].inhAttrs);
1119                 if (tblinfo[i].attnames)
1120                         free(tblinfo[i].attnames);
1121                 if (tblinfo[i].typnames)
1122                         free(tblinfo[i].typnames);
1123                 if (tblinfo[i].notnull)
1124                         free(tblinfo[i].notnull);
1125         if (tblinfo[i].primary_key)
1126             free(tblinfo[i].primary_key);
1127         }
1128         free(tblinfo);
1129 }
1130
1131 void
1132 clearInhInfo(InhInfo *inh, int numInherits)
1133 {
1134         int                     i;
1135
1136         if (!inh)
1137                 return;
1138         for (i = 0; i < numInherits; ++i)
1139         {
1140                 if (inh[i].inhrelid)
1141                         free(inh[i].inhrelid);
1142                 if (inh[i].inhparent)
1143                         free(inh[i].inhparent);
1144         }
1145         free(inh);
1146 }
1147
1148 void
1149 clearOprInfo(OprInfo *opr, int numOprs)
1150 {
1151         int                     i;
1152
1153         if (!opr)
1154                 return;
1155         for (i = 0; i < numOprs; ++i)
1156         {
1157                 if (opr[i].oid)
1158                         free(opr[i].oid);
1159                 if (opr[i].oprname)
1160                         free(opr[i].oprname);
1161                 if (opr[i].oprkind)
1162                         free(opr[i].oprkind);
1163                 if (opr[i].oprcode)
1164                         free(opr[i].oprcode);
1165                 if (opr[i].oprleft)
1166                         free(opr[i].oprleft);
1167                 if (opr[i].oprright)
1168                         free(opr[i].oprright);
1169                 if (opr[i].oprcom)
1170                         free(opr[i].oprcom);
1171                 if (opr[i].oprnegate)
1172                         free(opr[i].oprnegate);
1173                 if (opr[i].oprrest)
1174                         free(opr[i].oprrest);
1175                 if (opr[i].oprjoin)
1176                         free(opr[i].oprjoin);
1177                 if (opr[i].oprcanhash)
1178                         free(opr[i].oprcanhash);
1179                 if (opr[i].oprlsortop)
1180                         free(opr[i].oprlsortop);
1181                 if (opr[i].oprrsortop)
1182                         free(opr[i].oprrsortop);
1183                 if (opr[i].usename)
1184                         free(opr[i].usename);
1185         }
1186         free(opr);
1187 }
1188
1189 void
1190 clearIndInfo(IndInfo *ind, int numIndices)
1191 {
1192         int                     i,
1193                                 a;
1194
1195         if (!ind)
1196                 return;
1197         for (i = 0; i < numIndices; ++i)
1198         {
1199                 if (ind[i].indexrelname)
1200                         free(ind[i].indexrelname);
1201                 if (ind[i].indrelname)
1202                         free(ind[i].indrelname);
1203                 if (ind[i].indamname)
1204                         free(ind[i].indamname);
1205                 if (ind[i].indproc)
1206                         free(ind[i].indproc);
1207                 if (ind[i].indisunique)
1208                         free(ind[i].indisunique);
1209                 for (a = 0; a < INDEX_MAX_KEYS; ++a)
1210                 {
1211                         if (ind[i].indkey[a])
1212                                 free(ind[i].indkey[a]);
1213                         if (ind[i].indclass[a])
1214                                 free(ind[i].indclass[a]);
1215                 }
1216         }
1217         free(ind);
1218 }
1219
1220 void
1221 clearAggInfo(AggInfo *agginfo, int numArgs)
1222 {
1223         int                     i;
1224
1225         if (!agginfo)
1226                 return;
1227         for (i = 0; i < numArgs; ++i)
1228         {
1229                 if (agginfo[i].oid)
1230                         free(agginfo[i].oid);
1231                 if (agginfo[i].aggname)
1232                         free(agginfo[i].aggname);
1233                 if (agginfo[i].aggtransfn1)
1234                         free(agginfo[i].aggtransfn1);
1235                 if (agginfo[i].aggtransfn2)
1236                         free(agginfo[i].aggtransfn2);
1237                 if (agginfo[i].aggfinalfn)
1238                         free(agginfo[i].aggfinalfn);
1239                 if (agginfo[i].aggtranstype1)
1240                         free(agginfo[i].aggtranstype1);
1241                 if (agginfo[i].aggbasetype)
1242                         free(agginfo[i].aggbasetype);
1243                 if (agginfo[i].aggtranstype2)
1244                         free(agginfo[i].aggtranstype2);
1245                 if (agginfo[i].agginitval1)
1246                         free(agginfo[i].agginitval1);
1247                 if (agginfo[i].agginitval2)
1248                         free(agginfo[i].agginitval2);
1249                 if (agginfo[i].usename)
1250                         free(agginfo[i].usename);
1251         }
1252         free(agginfo);
1253 }
1254
1255 /*
1256  * getAggregates:
1257  *        read all the user-defined aggregates in the system catalogs and
1258  * return them in the AggInfo* structure
1259  *
1260  * numAggs is set to the number of aggregates read in
1261  *
1262  *
1263  */
1264 AggInfo    *
1265 getAggregates(int *numAggs)
1266 {
1267         PGresult   *res;
1268         int                     ntups;
1269         int                     i;
1270         PQExpBuffer     query = createPQExpBuffer();
1271         AggInfo    *agginfo;
1272
1273         int                     i_oid;
1274         int                     i_aggname;
1275         int                     i_aggtransfn1;
1276         int                     i_aggtransfn2;
1277         int                     i_aggfinalfn;
1278         int                     i_aggtranstype1;
1279         int                     i_aggbasetype;
1280         int                     i_aggtranstype2;
1281         int                     i_agginitval1;
1282         int                     i_agginitval2;
1283         int                     i_usename;
1284
1285         /* find all user-defined aggregates */
1286
1287         appendPQExpBuffer(query,
1288                         "SELECT pg_aggregate.oid, aggname, aggtransfn1, aggtransfn2, "
1289                         "aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, "
1290                   "agginitval1, agginitval2, usename from pg_aggregate, pg_user "
1291                         "where aggowner = usesysid");
1292
1293         res = PQexec(g_conn, query->data);
1294         if (!res ||
1295                 PQresultStatus(res) != PGRES_TUPLES_OK)
1296         {
1297                 fprintf(stderr, "getAggregates(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1298                 exit_nicely(g_conn);
1299         }
1300
1301         ntups = PQntuples(res);
1302         *numAggs = ntups;
1303
1304         agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
1305
1306         i_oid = PQfnumber(res, "oid");
1307         i_aggname = PQfnumber(res, "aggname");
1308         i_aggtransfn1 = PQfnumber(res, "aggtransfn1");
1309         i_aggtransfn2 = PQfnumber(res, "aggtransfn2");
1310         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1311         i_aggtranstype1 = PQfnumber(res, "aggtranstype1");
1312         i_aggbasetype = PQfnumber(res, "aggbasetype");
1313         i_aggtranstype2 = PQfnumber(res, "aggtranstype2");
1314         i_agginitval1 = PQfnumber(res, "agginitval1");
1315         i_agginitval2 = PQfnumber(res, "agginitval2");
1316         i_usename = PQfnumber(res, "usename");
1317
1318         for (i = 0; i < ntups; i++)
1319         {
1320                 agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1321                 agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1322                 agginfo[i].aggtransfn1 = strdup(PQgetvalue(res, i, i_aggtransfn1));
1323                 agginfo[i].aggtransfn2 = strdup(PQgetvalue(res, i, i_aggtransfn2));
1324                 agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1325                 agginfo[i].aggtranstype1 = strdup(PQgetvalue(res, i, i_aggtranstype1));
1326                 agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1327                 agginfo[i].aggtranstype2 = strdup(PQgetvalue(res, i, i_aggtranstype2));
1328                 agginfo[i].agginitval1 = strdup(PQgetvalue(res, i, i_agginitval1));
1329                 agginfo[i].agginitval2 = strdup(PQgetvalue(res, i, i_agginitval2));
1330                 agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1331         }
1332
1333         PQclear(res);
1334
1335         return agginfo;
1336 }
1337
1338 /*
1339  * getFuncs:
1340  *        read all the user-defined functions in the system catalogs and
1341  * return them in the FuncInfo* structure
1342  *
1343  * numFuncs is set to the number of functions read in
1344  *
1345  *
1346  */
1347 FuncInfo   *
1348 getFuncs(int *numFuncs)
1349 {
1350         PGresult        *res;
1351         int                     ntups;
1352         int                     i;
1353         PQExpBuffer     query = createPQExpBuffer();
1354         FuncInfo        *finfo;
1355
1356         int                     i_oid;
1357         int                     i_proname;
1358         int                     i_prolang;
1359         int                     i_pronargs;
1360         int                     i_proargtypes;
1361         int                     i_prorettype;
1362         int                     i_proretset;
1363         int                     i_prosrc;
1364         int                     i_probin;
1365         int                     i_usename;
1366
1367         /* find all user-defined funcs */
1368
1369         appendPQExpBuffer(query,
1370                         "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1371                         "proretset, proargtypes, prosrc, probin, usename "
1372                         "from pg_proc, pg_user "
1373                         "where pg_proc.oid > '%u'::oid and proowner = usesysid",
1374                         g_last_builtin_oid);
1375
1376         res = PQexec(g_conn, query->data);
1377         if (!res ||
1378                 PQresultStatus(res) != PGRES_TUPLES_OK)
1379         {
1380                 fprintf(stderr, "getFuncs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1381                 exit_nicely(g_conn);
1382         }
1383
1384         ntups = PQntuples(res);
1385
1386         *numFuncs = ntups;
1387
1388         finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));
1389
1390         i_oid = PQfnumber(res, "oid");
1391         i_proname = PQfnumber(res, "proname");
1392         i_prolang = PQfnumber(res, "prolang");
1393         i_pronargs = PQfnumber(res, "pronargs");
1394         i_proargtypes = PQfnumber(res, "proargtypes");
1395         i_prorettype = PQfnumber(res, "prorettype");
1396         i_proretset = PQfnumber(res, "proretset");
1397         i_prosrc = PQfnumber(res, "prosrc");
1398         i_probin = PQfnumber(res, "probin");
1399         i_usename = PQfnumber(res, "usename");
1400
1401         for (i = 0; i < ntups; i++)
1402         {
1403                 finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1404                 finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
1405
1406                 finfo[i].prosrc = checkForQuote(PQgetvalue(res, i, i_prosrc));
1407                 finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
1408
1409                 finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
1410                 finfo[i].retset = (strcmp(PQgetvalue(res, i, i_proretset), "t") == 0);
1411                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
1412                 finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
1413
1414                 finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1415
1416                 parseArgTypes(finfo[i].argtypes, PQgetvalue(res, i, i_proargtypes));
1417
1418                 finfo[i].dumped = 0;
1419         }
1420
1421         PQclear(res);
1422
1423         return finfo;
1424
1425 }
1426
1427 /*
1428  * getTables
1429  *        read all the user-defined tables (no indices, no catalogs)
1430  * in the system catalogs return them in the TableInfo* structure
1431  *
1432  * numTables is set to the number of tables read in
1433  *
1434  *
1435  */
1436 TableInfo  *
1437 getTables(int *numTables, FuncInfo *finfo, int numFuncs)
1438 {
1439         PGresult        *res;
1440         int                     ntups;
1441         int                     i;
1442         PQExpBuffer     query = createPQExpBuffer();
1443         TableInfo       *tblinfo;
1444
1445         int                     i_oid;
1446         int                     i_relname;
1447         int                     i_relkind;
1448         int                     i_relacl;
1449         int                     i_usename;
1450         int                     i_relchecks;
1451         int                     i_reltriggers;
1452     int         i_relhasindex;
1453
1454         /*
1455          * find all the user-defined tables (no indices and no catalogs),
1456          * ordering by oid is important so that we always process the parent
1457          * tables before the child tables when traversing the tblinfo*
1458          *
1459          * we ignore tables that are not type 'r' (ordinary relation)
1460          * or 'S' (sequence) --- in particular, Large Object relations
1461          * (type 'l') are ignored.
1462          */
1463
1464         appendPQExpBuffer(query,
1465                         "SELECT pg_class.oid, relname, relkind, relacl, usename, "
1466                         "relchecks, reltriggers, relhasindex "
1467                         "from pg_class, pg_user "
1468                         "where relowner = usesysid and "
1469                         "(relkind = 'r' or relkind = 'S') and relname !~ '^pg_' "
1470                         "order by oid");
1471
1472         res = PQexec(g_conn, query->data);
1473         if (!res ||
1474                 PQresultStatus(res) != PGRES_TUPLES_OK)
1475         {
1476                 fprintf(stderr, "getTables(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1477                 exit_nicely(g_conn);
1478         }
1479
1480         ntups = PQntuples(res);
1481
1482         *numTables = ntups;
1483
1484         tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));
1485
1486         i_oid = PQfnumber(res, "oid");
1487         i_relname = PQfnumber(res, "relname");
1488         i_relkind = PQfnumber(res, "relkind");
1489         i_relacl = PQfnumber(res, "relacl");
1490         i_usename = PQfnumber(res, "usename");
1491         i_relchecks = PQfnumber(res, "relchecks");
1492         i_reltriggers = PQfnumber(res, "reltriggers");
1493         i_relhasindex = PQfnumber(res, "relhasindex");
1494
1495         for (i = 0; i < ntups; i++)
1496         {
1497                 tblinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1498                 tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
1499                 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
1500                 tblinfo[i].sequence = (strcmp(PQgetvalue(res, i, i_relkind), "S") == 0);
1501                 tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1502                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
1503                 tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
1504
1505                 /*
1506                  * Exclude inherited CHECKs from CHECK constraints total. If a
1507                  * constraint matches by name and condition with a constraint
1508                  * belonging to a parent class, we assume it was inherited.
1509                  */
1510                 if (tblinfo[i].ncheck > 0)
1511                 {
1512                         PGresult   *res2;
1513                         int                     ntups2;
1514
1515                         if (g_verbose)
1516                                 fprintf(stderr, "%s excluding inherited CHECK constraints "
1517                                                 "for relation: '%s' %s\n",
1518                                                 g_comment_start,
1519                                                 tblinfo[i].relname,
1520                                                 g_comment_end);
1521
1522                         resetPQExpBuffer(query);
1523                         appendPQExpBuffer(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
1524                                         "where rcrelid = '%s'::oid "
1525                                         " and rcrelid = i.inhrelid"
1526                                         " and exists "
1527                                         "  (select * from pg_relcheck as c "
1528                                         "    where c.rcname = pg_relcheck.rcname "
1529                                         "      and c.rcsrc = pg_relcheck.rcsrc "
1530                                         "      and c.rcrelid = i.inhparent) ",
1531                                         tblinfo[i].oid);
1532                         res2 = PQexec(g_conn, query->data);
1533                         if (!res2 ||
1534                                 PQresultStatus(res2) != PGRES_TUPLES_OK)
1535                         {
1536                                 fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1537                                 exit_nicely(g_conn);
1538                         }
1539                         ntups2 = PQntuples(res2);
1540                         tblinfo[i].ncheck -= ntups2;
1541                         if (tblinfo[i].ncheck < 0)
1542                         {
1543                                 fprintf(stderr, "getTables(): found more inherited CHECKs than total for "
1544                                                 "relation %s\n",
1545                                                 tblinfo[i].relname);
1546                                 exit_nicely(g_conn);
1547                         }
1548                         PQclear(res2);
1549                 }
1550
1551                 /* Get non-inherited CHECK constraints, if any */
1552                 if (tblinfo[i].ncheck > 0)
1553                 {
1554                         PGresult   *res2;
1555                         int                     i_rcname,
1556                                                 i_rcsrc;
1557                         int                     ntups2;
1558                         int                     i2;
1559
1560                         if (g_verbose)
1561                                 fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %s\n",
1562                                                 g_comment_start,
1563                                                 tblinfo[i].relname,
1564                                                 g_comment_end);
1565
1566                         resetPQExpBuffer(query);
1567                         appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
1568                                         "where rcrelid = '%s'::oid "
1569                                         "   and not exists "
1570                                         "  (select * from pg_relcheck as c, pg_inherits as i "
1571                                         "   where i.inhrelid = pg_relcheck.rcrelid "
1572                                         "     and c.rcname = pg_relcheck.rcname "
1573                                         "     and c.rcsrc = pg_relcheck.rcsrc "
1574                                         "     and c.rcrelid = i.inhparent) ",
1575                                         tblinfo[i].oid);
1576                         res2 = PQexec(g_conn, query->data);
1577                         if (!res2 ||
1578                                 PQresultStatus(res2) != PGRES_TUPLES_OK)
1579                         {
1580                                 fprintf(stderr, "getTables(): SELECT (for CHECK) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1581                                 exit_nicely(g_conn);
1582                         }
1583                         ntups2 = PQntuples(res2);
1584                         if (ntups2 != tblinfo[i].ncheck)
1585                         {
1586                                 fprintf(stderr, "getTables(): relation '%s': %d CHECKs were expected, but got %d\n",
1587                                                 tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
1588                                 exit_nicely(g_conn);
1589                         }
1590                         i_rcname = PQfnumber(res2, "rcname");
1591                         i_rcsrc = PQfnumber(res2, "rcsrc");
1592                         tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
1593                         for (i2 = 0; i2 < ntups2; i2++)
1594                         {
1595                                 const char *name = PQgetvalue(res2, i2, i_rcname);
1596                                 const char *expr = PQgetvalue(res2, i2, i_rcsrc);
1597
1598                                 resetPQExpBuffer(query);
1599                                 if (name[0] != '$')
1600                                         appendPQExpBuffer(query, "CONSTRAINT %s ", fmtId(name, force_quotes));
1601                                 appendPQExpBuffer(query, "CHECK (%s)", expr);
1602                                 tblinfo[i].check_expr[i2] = strdup(query->data);
1603                         }
1604                         PQclear(res2);
1605                 }
1606                 else
1607                         tblinfo[i].check_expr = NULL;
1608
1609         /* Get primary key */
1610         if (strcmp(PQgetvalue(res, i, i_relhasindex), "t")==0)
1611         {
1612             PGresult * res2;
1613             char str[INDEX_MAX_KEYS * NAMEDATALEN + 3] = "";
1614             int j;
1615
1616                         resetPQExpBuffer(query);
1617             appendPQExpBuffer(query,
1618                     "SELECT a.attname "
1619                     "FROM pg_index i, pg_class c, pg_attribute a "
1620                     "WHERE i.indisprimary AND i.indrelid = %s "
1621                     "  AND i.indexrelid = c.oid AND a.attnum > 0 AND a.attrelid = c.oid "
1622                     "ORDER BY a.attnum ",
1623                     tblinfo[i].oid);
1624             res2 = PQexec(g_conn, query->data);
1625                         if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
1626                         {
1627                                 fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) failed.  Explanation from backend: %s",
1628                         PQerrorMessage(g_conn));
1629                                 exit_nicely(g_conn);
1630                         }
1631             
1632             for (j = 0; j < PQntuples(res2); j++)
1633             {
1634                 if (strlen(str)>0)
1635                     strcat(str, ", ");
1636                 strcat(str, fmtId(PQgetvalue(res2, j, 0), force_quotes));
1637             }
1638
1639             if (strlen(str)>0) {
1640                 tblinfo[i].primary_key = strdup(str);
1641                 if (tblinfo[i].primary_key == NULL) {
1642                     perror("strdup");
1643                     exit(1);
1644                 }
1645             }
1646             else
1647                 tblinfo[i].primary_key = NULL;
1648         }
1649         else
1650             tblinfo[i].primary_key = NULL;
1651
1652                 /* Get Triggers */
1653                 if (tblinfo[i].ntrig > 0)
1654                 {
1655                         PGresult   *res2;
1656                         int                     i_tgname,
1657                                                 i_tgfoid,
1658                                                 i_tgtype,
1659                                                 i_tgnargs,
1660                                                 i_tgargs;
1661                         int                     ntups2;
1662                         int                     i2;
1663
1664                         if (g_verbose)
1665                                 fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
1666                                                 g_comment_start,
1667                                                 tblinfo[i].relname,
1668                                                 g_comment_end);
1669
1670                         resetPQExpBuffer(query);
1671                         appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs "
1672                                         "from pg_trigger "
1673                                         "where tgrelid = '%s'::oid ",
1674                                         tblinfo[i].oid);
1675                         res2 = PQexec(g_conn, query->data);
1676                         if (!res2 ||
1677                                 PQresultStatus(res2) != PGRES_TUPLES_OK)
1678                         {
1679                                 fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1680                                 exit_nicely(g_conn);
1681                         }
1682                         ntups2 = PQntuples(res2);
1683                         if (ntups2 != tblinfo[i].ntrig)
1684                         {
1685                                 fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
1686                                                 tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
1687                                 exit_nicely(g_conn);
1688                         }
1689                         i_tgname = PQfnumber(res2, "tgname");
1690                         i_tgfoid = PQfnumber(res2, "tgfoid");
1691                         i_tgtype = PQfnumber(res2, "tgtype");
1692                         i_tgnargs = PQfnumber(res2, "tgnargs");
1693                         i_tgargs = PQfnumber(res2, "tgargs");
1694                         tblinfo[i].triggers = (char **) malloc(ntups2 * sizeof(char *));
1695                         resetPQExpBuffer(query);
1696                         for (i2 = 0; i2 < ntups2; i2++)
1697                         {
1698                                 const char *tgfunc = PQgetvalue(res2, i2, i_tgfoid);
1699                                 int2            tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
1700                                 int                     tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
1701                                 const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
1702                                 const char *p;
1703                                 char            farg[MAX_QUERY_SIZE];
1704                                 int                     findx;
1705
1706                                 for (findx = 0; findx < numFuncs; findx++)
1707                                 {
1708                                         if (strcmp(finfo[findx].oid, tgfunc) == 0 &&
1709                                                 finfo[findx].nargs == 0 &&
1710                                                 strcmp(finfo[findx].prorettype, "0") == 0)
1711                                                 break;
1712                                 }
1713                                 if (findx == numFuncs)
1714                                 {
1715                                         fprintf(stderr, "getTables(): relation '%s': cannot find function with oid %s for trigger %s\n",
1716                                                         tblinfo[i].relname, tgfunc, PQgetvalue(res2, i2, i_tgname));
1717                                         exit_nicely(g_conn);
1718                                 }
1719                                 tgfunc = finfo[findx].proname;
1720
1721 #if 0
1722                                 /* XXX - how to emit this DROP TRIGGER? */
1723                                 if (dropSchema)
1724                                 {
1725                                         resetPQExpBuffer(query);
1726                                         appendPQExpBuffer(query, "DROP TRIGGER %s ON %s;\n",
1727                                          fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes),
1728                                                         fmtId(tblinfo[i].relname, force_quotes));
1729                                         fputs(query->data, fout);
1730                                 }
1731 #endif
1732
1733                                 resetPQExpBuffer(query);
1734                                 appendPQExpBuffer(query, "CREATE TRIGGER %s ", fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
1735                                 /* Trigger type */
1736                                 findx = 0;
1737                                 if (TRIGGER_FOR_BEFORE(tgtype))
1738                                         appendPQExpBuffer(query, "BEFORE");
1739                                 else
1740                                         appendPQExpBuffer(query, "AFTER");
1741                                 if (TRIGGER_FOR_INSERT(tgtype))
1742                                 {
1743                                         appendPQExpBuffer(query, " INSERT");
1744                                         findx++;
1745                                 }
1746                                 if (TRIGGER_FOR_DELETE(tgtype))
1747                                 {
1748                                         if (findx > 0)
1749                                                 appendPQExpBuffer(query, " OR DELETE");
1750                                         else
1751                                                 appendPQExpBuffer(query, " DELETE");
1752                                         findx++;
1753                                 }
1754                                 if (TRIGGER_FOR_UPDATE(tgtype))
1755                                 {
1756                                         if (findx > 0)
1757                                                 appendPQExpBuffer(query, " OR UPDATE");
1758                                         else
1759                                                 appendPQExpBuffer(query, " UPDATE");
1760                                 }
1761                                 appendPQExpBuffer(query, " ON %s FOR EACH ROW EXECUTE PROCEDURE %s (",
1762                                         fmtId(tblinfo[i].relname, force_quotes), tgfunc);
1763                                 for (findx = 0; findx < tgnargs; findx++)
1764                                 {
1765                                         const char         *s;
1766                     char           *d;
1767
1768                                         for (p = tgargs;;)
1769                                         {
1770                                                 p = strchr(p, '\\');
1771                                                 if (p == NULL)
1772                                                 {
1773                                                         fprintf(stderr, "getTables(): relation '%s': bad argument string (%s) for trigger '%s'\n",
1774                                                                         tblinfo[i].relname,
1775                                                                         PQgetvalue(res2, i2, i_tgargs),
1776                                                                         PQgetvalue(res2, i2, i_tgname));
1777                                                         exit_nicely(g_conn);
1778                                                 }
1779                                                 p++;
1780                                                 if (*p == '\\')
1781                                                 {
1782                                                         p++;
1783                                                         continue;
1784                                                 }
1785                                                 if (p[0] == '0' && p[1] == '0' && p[2] == '0')
1786                                                         break;
1787                                         }
1788                                         p--;
1789                                         for (s = tgargs, d = &(farg[0]); s < p;)
1790                                         {
1791                                                 if (*s == '\'')
1792                                                         *d++ = '\\';
1793                                                 *d++ = *s++;
1794                                         }
1795                                         *d = 0;
1796                                         appendPQExpBuffer(query, "'%s'%s", farg,
1797                                                         (findx < tgnargs - 1) ? ", " : "");
1798                                         tgargs = p + 4;
1799                                 }
1800                                 appendPQExpBuffer(query, ");\n");
1801                                 tblinfo[i].triggers[i2] = strdup(query->data);
1802                         }
1803                         PQclear(res2);
1804                 }
1805                 else
1806                         tblinfo[i].triggers = NULL;
1807         }
1808
1809         PQclear(res);
1810
1811         return tblinfo;
1812
1813 }
1814
1815 /*
1816  * getInherits
1817  *        read all the inheritance information
1818  * from the system catalogs return them in the InhInfo* structure
1819  *
1820  * numInherits is set to the number of tables read in
1821  *
1822  *
1823  */
1824 InhInfo    *
1825 getInherits(int *numInherits)
1826 {
1827         PGresult        *res;
1828         int                     ntups;
1829         int                     i;
1830         PQExpBuffer     query = createPQExpBuffer();
1831         InhInfo         *inhinfo;
1832
1833         int                     i_inhrelid;
1834         int                     i_inhparent;
1835
1836         /* find all the inheritance information */
1837
1838         appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
1839
1840         res = PQexec(g_conn, query->data);
1841         if (!res ||
1842                 PQresultStatus(res) != PGRES_TUPLES_OK)
1843         {
1844                 fprintf(stderr, "getInherits(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1845                 exit_nicely(g_conn);
1846         }
1847
1848         ntups = PQntuples(res);
1849
1850         *numInherits = ntups;
1851
1852         inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
1853
1854         i_inhrelid = PQfnumber(res, "inhrelid");
1855         i_inhparent = PQfnumber(res, "inhparent");
1856
1857         for (i = 0; i < ntups; i++)
1858         {
1859                 inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
1860                 inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
1861         }
1862
1863         PQclear(res);
1864         return inhinfo;
1865 }
1866
1867 /*
1868  * getTableAttrs -
1869  *        for each table in tblinfo, read its attributes types and names
1870  *
1871  * this is implemented in a very inefficient way right now, looping
1872  * through the tblinfo and doing a join per table to find the attrs and their
1873  * types
1874  *
1875  *      modifies tblinfo
1876  */
1877 void
1878 getTableAttrs(TableInfo *tblinfo, int numTables)
1879 {
1880         int                     i,
1881                                 j;
1882         PQExpBuffer     q = createPQExpBuffer();
1883         int                     i_attname;
1884         int                     i_typname;
1885         int                     i_atttypmod;
1886         int                     i_attnotnull;
1887         int                     i_atthasdef;
1888         PGresult        *res;
1889         int                     ntups;
1890
1891         for (i = 0; i < numTables; i++)
1892         {
1893
1894                 if (tblinfo[i].sequence)
1895                         continue;
1896
1897                 /* find all the user attributes and their types */
1898                 /* we must read the attribute names in attribute number order! */
1899
1900                 /*
1901                  * because we will use the attnum to index into the attnames array
1902                  * later
1903                  */
1904                 if (g_verbose)
1905                         fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
1906                                         g_comment_start,
1907                                         tblinfo[i].relname,
1908                                         g_comment_end);
1909
1910                 resetPQExpBuffer(q);
1911                 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
1912                                 "a.attnotnull, a.atthasdef "
1913                                 "from pg_attribute a, pg_type t "
1914                                 "where a.attrelid = '%s'::oid and a.atttypid = t.oid "
1915                                 "and a.attnum > 0 order by attnum",
1916                                 tblinfo[i].oid);
1917                 res = PQexec(g_conn, q->data);
1918                 if (!res ||
1919                         PQresultStatus(res) != PGRES_TUPLES_OK)
1920                 {
1921                         fprintf(stderr, "getTableAttrs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1922                         exit_nicely(g_conn);
1923                 }
1924
1925                 ntups = PQntuples(res);
1926
1927                 i_attname = PQfnumber(res, "attname");
1928                 i_typname = PQfnumber(res, "typname");
1929                 i_atttypmod = PQfnumber(res, "atttypmod");
1930                 i_attnotnull = PQfnumber(res, "attnotnull");
1931                 i_atthasdef = PQfnumber(res, "atthasdef");
1932
1933                 tblinfo[i].numatts = ntups;
1934                 tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
1935                 tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
1936                 tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
1937                 tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
1938                 tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
1939                 tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
1940                 tblinfo[i].parentRels = NULL;
1941                 tblinfo[i].numParents = 0;
1942                 for (j = 0; j < ntups; j++)
1943                 {
1944                         tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
1945                         tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
1946                         tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
1947                         tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
1948                                                                                  * flagInhAttrs() */
1949                         tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
1950                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
1951                         {
1952                                 PGresult   *res2;
1953
1954                                 if (g_verbose)
1955                                         fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
1956                                                         g_comment_start,
1957                                                         tblinfo[i].attnames[j],
1958                                                         g_comment_end);
1959
1960                                 resetPQExpBuffer(q);
1961                                 appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
1962                                                 "where adrelid = '%s'::oid and adnum = %d ",
1963                                                 tblinfo[i].oid, j + 1);
1964                                 res2 = PQexec(g_conn, q->data);
1965                                 if (!res2 ||
1966                                         PQresultStatus(res2) != PGRES_TUPLES_OK)
1967                                 {
1968                                         fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1969                                         exit_nicely(g_conn);
1970                                 }
1971                                 tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
1972                                 PQclear(res2);
1973                         }
1974                         else
1975                                 tblinfo[i].adef_expr[j] = NULL;
1976                 }
1977                 PQclear(res);
1978         }
1979 }
1980
1981
1982 /*
1983  * getIndices
1984  *        read all the user-defined indices information
1985  * from the system catalogs return them in the InhInfo* structure
1986  *
1987  * numIndices is set to the number of indices read in
1988  *
1989  *
1990  */
1991 IndInfo    *
1992 getIndices(int *numIndices)
1993 {
1994         int                     i;
1995         PQExpBuffer     query = createPQExpBuffer();
1996         PGresult   *res;
1997         int                     ntups;
1998         IndInfo    *indinfo;
1999
2000         int                     i_indexrelname;
2001         int                     i_indrelname;
2002         int                     i_indamname;
2003         int                     i_indproc;
2004         int                     i_indkey;
2005         int                     i_indclass;
2006         int                     i_indisunique;
2007
2008         /*
2009          * find all the user-defined indices. We do not handle partial
2010          * indices.
2011          *
2012          * Notice we skip indices on inversion objects (relkind 'l')
2013          *
2014          * this is a 4-way join !!
2015          */
2016
2017         appendPQExpBuffer(query,
2018             "SELECT t1.relname as indexrelname, t2.relname as indrelname, "
2019                         "i.indproc, i.indkey, i.indclass, "
2020                         "a.amname as indamname, i.indisunique "
2021                         "from pg_index i, pg_class t1, pg_class t2, pg_am a "
2022                         "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
2023                         "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
2024                         "and t2.relname !~ '^pg_' and t2.relkind != 'l' and not i.indisprimary",
2025                         g_last_builtin_oid);
2026
2027         res = PQexec(g_conn, query->data);
2028         if (!res ||
2029                 PQresultStatus(res) != PGRES_TUPLES_OK)
2030         {
2031                 fprintf(stderr, "getIndices(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2032                 exit_nicely(g_conn);
2033         }
2034
2035         ntups = PQntuples(res);
2036
2037         *numIndices = ntups;
2038
2039         indinfo = (IndInfo *) malloc(ntups * sizeof(IndInfo));
2040
2041         i_indexrelname = PQfnumber(res, "indexrelname");
2042         i_indrelname = PQfnumber(res, "indrelname");
2043         i_indamname = PQfnumber(res, "indamname");
2044         i_indproc = PQfnumber(res, "indproc");
2045         i_indkey = PQfnumber(res, "indkey");
2046         i_indclass = PQfnumber(res, "indclass");
2047         i_indisunique = PQfnumber(res, "indisunique");
2048
2049         for (i = 0; i < ntups; i++)
2050         {
2051                 indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
2052                 indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
2053                 indinfo[i].indamname = strdup(PQgetvalue(res, i, i_indamname));
2054                 indinfo[i].indproc = strdup(PQgetvalue(res, i, i_indproc));
2055                 parseArgTypes((char **) indinfo[i].indkey,
2056                                           (const char *) PQgetvalue(res, i, i_indkey));
2057                 parseArgTypes((char **) indinfo[i].indclass,
2058                                           (const char *) PQgetvalue(res, i, i_indclass));
2059                 indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
2060         }
2061         PQclear(res);
2062         return indinfo;
2063 }
2064
2065 /*
2066  * dumpTypes
2067  *        writes out to fout the queries to recreate all the user-defined types
2068  *
2069  */
2070 void
2071 dumpTypes(FILE *fout, FuncInfo *finfo, int numFuncs,
2072                   TypeInfo *tinfo, int numTypes)
2073 {
2074         int                     i;
2075         PQExpBuffer     q = createPQExpBuffer();
2076         int                     funcInd;
2077
2078         for (i = 0; i < numTypes; i++)
2079         {
2080
2081                 /* skip all the builtin types */
2082                 if (atoi(tinfo[i].oid) < g_last_builtin_oid)
2083                         continue;
2084
2085                 /* skip relation types */
2086                 if (atoi(tinfo[i].typrelid) != 0)
2087                         continue;
2088
2089                 /* skip all array types that start w/ underscore */
2090                 if ((tinfo[i].typname[0] == '_') &&
2091                         (strcmp(tinfo[i].typinput, "array_in") == 0))
2092                         continue;
2093
2094                 /*
2095                  * before we create a type, we need to create the input and output
2096                  * functions for it, if they haven't been created already
2097                  */
2098                 funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
2099                 if (funcInd != -1)
2100                         dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2101
2102                 funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
2103                 if (funcInd != -1)
2104                         dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2105
2106                 becomeUser(fout, tinfo[i].usename);
2107
2108                 if (dropSchema)
2109                 {
2110                         resetPQExpBuffer(q);
2111                         appendPQExpBuffer(q, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
2112                         fputs(q->data, fout);
2113                 }
2114
2115                 resetPQExpBuffer(q);
2116                 appendPQExpBuffer(q,
2117                                 "CREATE TYPE %s "
2118                                 "( internallength = %s, externallength = %s, input = %s, "
2119                                 "output = %s, send = %s, receive = %s, default = '%s'",
2120                                 fmtId(tinfo[i].typname, force_quotes),
2121                                 tinfo[i].typlen,
2122                                 tinfo[i].typprtlen,
2123                                 tinfo[i].typinput,
2124                                 tinfo[i].typoutput,
2125                                 tinfo[i].typsend,
2126                                 tinfo[i].typreceive,
2127                                 tinfo[i].typdefault);
2128
2129                 if (tinfo[i].isArray)
2130                 {
2131                         char       *elemType;
2132
2133                         elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem);
2134
2135                         appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
2136                                         elemType, tinfo[i].typdelim);
2137                 }
2138                 if (tinfo[i].passedbyvalue)
2139                         appendPQExpBuffer(q, ",passedbyvalue);\n");
2140                 else
2141                         appendPQExpBuffer(q, ");\n");
2142
2143                 fputs(q->data, fout);
2144         }
2145 }
2146
2147 /*
2148  * dumpProcLangs
2149  *                writes out to fout the queries to recreate user-defined procedural languages
2150  *
2151  */
2152 void
2153 dumpProcLangs(FILE *fout, FuncInfo *finfo, int numFuncs,
2154                           TypeInfo *tinfo, int numTypes)
2155 {
2156         PGresult        *res;
2157         PQExpBuffer     query = createPQExpBuffer();
2158         int                     ntups;
2159         int                     i_lanname;
2160         int                     i_lanpltrusted;
2161         int                     i_lanplcallfoid;
2162         int                     i_lancompiler;
2163         char            *lanname;
2164         char            *lancompiler;
2165         const char      *lanplcallfoid;
2166         int                     i,
2167                                 fidx;
2168
2169         appendPQExpBuffer(query, "SELECT * FROM pg_language "
2170                         "WHERE lanispl "
2171                         "ORDER BY oid");
2172         res = PQexec(g_conn, query->data);
2173         if (!res ||
2174                 PQresultStatus(res) != PGRES_TUPLES_OK)
2175         {
2176                 fprintf(stderr, "dumpProcLangs(): SELECT failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2177                 exit_nicely(g_conn);
2178         }
2179         ntups = PQntuples(res);
2180
2181         i_lanname = PQfnumber(res, "lanname");
2182         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
2183         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
2184         i_lancompiler = PQfnumber(res, "lancompiler");
2185
2186         for (i = 0; i < ntups; i++)
2187         {
2188                 lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
2189                 for (fidx = 0; fidx < numFuncs; fidx++)
2190                 {
2191                         if (!strcmp(finfo[fidx].oid, lanplcallfoid))
2192                                 break;
2193                 }
2194                 if (fidx >= numFuncs)
2195                 {
2196                         fprintf(stderr, "dumpProcLangs(): handler procedure for language %s not found\n", PQgetvalue(res, i, i_lanname));
2197                         exit_nicely(g_conn);
2198                 }
2199
2200                 dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
2201
2202                 lanname = checkForQuote(PQgetvalue(res, i, i_lanname));
2203                 lancompiler = checkForQuote(PQgetvalue(res, i, i_lancompiler));
2204
2205                 if (dropSchema)
2206                         fprintf(fout, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
2207
2208                 fprintf(fout, "CREATE %sPROCEDURAL LANGUAGE '%s' "
2209                                 "HANDLER %s LANCOMPILER '%s';\n",
2210                 (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
2211                                 lanname,
2212                                 fmtId(finfo[fidx].proname, force_quotes),
2213                                 lancompiler);
2214
2215                 free(lanname);
2216                 free(lancompiler);
2217         }
2218
2219         PQclear(res);
2220
2221 }
2222
2223 /*
2224  * dumpFuncs
2225  *        writes out to fout the queries to recreate all the user-defined functions
2226  *
2227  */
2228 void
2229 dumpFuncs(FILE *fout, FuncInfo *finfo, int numFuncs,
2230                   TypeInfo *tinfo, int numTypes)
2231 {
2232         int                     i;
2233
2234         for (i = 0; i < numFuncs; i++)
2235                 dumpOneFunc(fout, finfo, i, tinfo, numTypes);
2236 }
2237
2238 /*
2239  * dumpOneFunc:
2240  *        dump out only one function,  the index of which is given in the third
2241  *      argument
2242  *
2243  */
2244
2245 static void
2246 dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
2247                         TypeInfo *tinfo, int numTypes)
2248 {
2249         PQExpBuffer     q = createPQExpBuffer();
2250         int                     j;
2251         char            *func_def;
2252         char            func_lang[NAMEDATALEN + 1];
2253
2254         if (finfo[i].dumped)
2255                 return;
2256         else
2257                 finfo[i].dumped = 1;
2258
2259         becomeUser(fout, finfo[i].usename);
2260
2261         if (finfo[i].lang == INTERNALlanguageId)
2262         {
2263                 func_def = finfo[i].prosrc;
2264                 strcpy(func_lang, "INTERNAL");
2265         }
2266         else if (finfo[i].lang == ClanguageId)
2267         {
2268                 func_def = finfo[i].probin;
2269                 strcpy(func_lang, "C");
2270         }
2271         else if (finfo[i].lang == SQLlanguageId)
2272         {
2273                 func_def = finfo[i].prosrc;
2274                 strcpy(func_lang, "SQL");
2275         }
2276         else
2277         {
2278                 PGresult   *res;
2279                 int                     nlangs;
2280                 int                     i_lanname;
2281                 char            query[256];
2282
2283                 sprintf(query, "SELECT lanname FROM pg_language "
2284                                 "WHERE oid = %u",
2285                                 finfo[i].lang);
2286                 res = PQexec(g_conn, query);
2287                 if (!res ||
2288                         PQresultStatus(res) != PGRES_TUPLES_OK)
2289                 {
2290                         fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2291                         exit_nicely(g_conn);
2292                 }
2293                 nlangs = PQntuples(res);
2294
2295                 if (nlangs != 1)
2296                 {
2297                         fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
2298                         exit_nicely(g_conn);
2299                 }
2300
2301                 i_lanname = PQfnumber(res, "lanname");
2302
2303                 func_def = finfo[i].prosrc;
2304                 strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
2305
2306                 PQclear(res);
2307
2308         }
2309
2310         if (dropSchema)
2311         {
2312                 resetPQExpBuffer(q);
2313                 appendPQExpBuffer(q, "DROP FUNCTION %s (", fmtId(finfo[i].proname, force_quotes));
2314                 for (j = 0; j < finfo[i].nargs; j++)
2315                 {
2316                         char       *typname;
2317
2318                         typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
2319                         appendPQExpBuffer(q, "%s%s",
2320                                         (j > 0) ? "," : "",
2321                                         fmtId(typname, false));
2322                 }
2323                 appendPQExpBuffer(q, ");\n");
2324                 fputs(q->data, fout);
2325         }
2326
2327         resetPQExpBuffer(q);
2328         appendPQExpBuffer(q, "CREATE FUNCTION %s (", fmtId(finfo[i].proname, force_quotes));
2329         for (j = 0; j < finfo[i].nargs; j++)
2330         {
2331                 char       *typname;
2332
2333                 typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
2334                 appendPQExpBuffer(q, "%s%s",
2335                                 (j > 0) ? "," : "",
2336                                 fmtId(typname, false));
2337         }
2338         appendPQExpBuffer(q, " ) RETURNS %s%s AS '%s' LANGUAGE '%s';\n",
2339                         (finfo[i].retset) ? " SETOF " : "",
2340                         fmtId(findTypeByOid(tinfo, numTypes, finfo[i].prorettype), false),
2341                         func_def, func_lang);
2342
2343         fputs(q->data, fout);
2344
2345 }
2346
2347 /*
2348  * dumpOprs
2349  *        writes out to fout the queries to recreate all the user-defined operators
2350  *
2351  */
2352 void
2353 dumpOprs(FILE *fout, OprInfo *oprinfo, int numOperators,
2354                  TypeInfo *tinfo, int numTypes)
2355 {
2356         int                     i;
2357         PQExpBuffer     q = createPQExpBuffer();
2358         PQExpBuffer     leftarg = createPQExpBuffer();
2359         PQExpBuffer     rightarg = createPQExpBuffer();
2360         PQExpBuffer     commutator = createPQExpBuffer();
2361         PQExpBuffer     negator = createPQExpBuffer();
2362         PQExpBuffer     restrictor = createPQExpBuffer();
2363         PQExpBuffer     join = createPQExpBuffer();
2364         PQExpBuffer     sort1 = createPQExpBuffer();
2365         PQExpBuffer     sort2 = createPQExpBuffer();
2366
2367         for (i = 0; i < numOperators; i++)
2368         {
2369
2370                 resetPQExpBuffer(leftarg);
2371                 resetPQExpBuffer(rightarg);
2372                 resetPQExpBuffer(commutator);
2373                 resetPQExpBuffer(negator);
2374                 resetPQExpBuffer(restrictor);
2375                 resetPQExpBuffer(join);
2376                 resetPQExpBuffer(sort1);
2377                 resetPQExpBuffer(sort2);
2378
2379                 /* skip all the builtin oids */
2380                 if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
2381                         continue;
2382
2383                 /*
2384                  * some operator are invalid because they were the result of user
2385                  * defining operators before commutators exist
2386                  */
2387                 if (strcmp(oprinfo[i].oprcode, "-") == 0)
2388                         continue;
2389
2390                 /*
2391                  * right unary means there's a left arg and left unary means
2392                  * there's a right arg
2393                  */
2394                 if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
2395                         strcmp(oprinfo[i].oprkind, "b") == 0)
2396                 {
2397                         appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ",
2398                                         fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false));
2399                 }
2400                 if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
2401                         strcmp(oprinfo[i].oprkind, "b") == 0)
2402                 {
2403                         appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ",
2404                                         fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
2405                 }
2406                 if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
2407                         appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ",
2408                                  findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));
2409
2410                 if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
2411                         appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ",
2412                           findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate));
2413
2414                 if (!(strcmp(oprinfo[i].oprrest, "-") == 0))
2415                         appendPQExpBuffer(restrictor, ",\n\tRESTRICT = %s ", oprinfo[i].oprrest);
2416
2417                 if (!(strcmp(oprinfo[i].oprjoin, "-") == 0))
2418                         appendPQExpBuffer(join, ",\n\tJOIN = %s ", oprinfo[i].oprjoin);
2419
2420                 if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
2421                         appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ",
2422                          findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop));
2423
2424                 if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
2425                         appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ",
2426                          findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop));
2427
2428                 becomeUser(fout, oprinfo[i].usename);
2429
2430                 if (dropSchema)
2431                 {
2432                         resetPQExpBuffer(q);
2433                         appendPQExpBuffer(q, "DROP OPERATOR %s (%s, %s);\n", oprinfo[i].oprname,
2434                                         fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false),
2435                                         fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
2436                         fputs(q->data, fout);
2437                 }
2438
2439                 resetPQExpBuffer(q);
2440                 appendPQExpBuffer(q,
2441                                 "CREATE OPERATOR %s "
2442                                 "(PROCEDURE = %s %s%s%s%s%s%s%s%s%s);\n",
2443                                 oprinfo[i].oprname,
2444                                 oprinfo[i].oprcode,
2445                                 leftarg->data,
2446                                 rightarg->data,
2447                                 commutator->data,
2448                                 negator->data,
2449                                 restrictor->data,
2450                   (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
2451                                 join->data,
2452                                 sort1->data,
2453                                 sort2->data);
2454
2455                 fputs(q->data, fout);
2456         }
2457 }
2458
2459 /*
2460  * dumpAggs
2461  *        writes out to fout the queries to create all the user-defined aggregates
2462  *
2463  */
2464 void
2465 dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
2466                  TypeInfo *tinfo, int numTypes)
2467 {
2468         int                     i;
2469         PQExpBuffer     q = createPQExpBuffer();
2470         PQExpBuffer     sfunc1 = createPQExpBuffer();
2471         PQExpBuffer     sfunc2 = createPQExpBuffer();
2472         PQExpBuffer     basetype = createPQExpBuffer();
2473         PQExpBuffer     finalfunc = createPQExpBuffer();
2474         char            comma1[2],
2475                                 comma2[2];
2476
2477         for (i = 0; i < numAggs; i++)
2478         {
2479
2480                 resetPQExpBuffer(sfunc1);
2481                 resetPQExpBuffer(sfunc2);
2482                 resetPQExpBuffer(basetype);
2483                 resetPQExpBuffer(finalfunc);
2484
2485                 /* skip all the builtin oids */
2486                 if (atoi(agginfo[i].oid) < g_last_builtin_oid)
2487                         continue;
2488
2489                 appendPQExpBuffer(basetype,
2490                                 "BASETYPE = %s, ",
2491                                 fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
2492
2493                 if (!(strcmp(agginfo[i].aggtransfn1, "-") == 0))
2494                 {
2495                         appendPQExpBuffer(sfunc1,
2496                                         "SFUNC1 = %s, STYPE1 = %s",
2497                                         agginfo[i].aggtransfn1,
2498                                         fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype1), false));
2499                         if (agginfo[i].agginitval1)
2500                                 appendPQExpBuffer(sfunc1, ", INITCOND1 = '%s'",
2501                                                 agginfo[i].agginitval1);
2502
2503                 }
2504
2505                 if (!(strcmp(agginfo[i].aggtransfn2, "-") == 0))
2506                 {
2507                         appendPQExpBuffer(sfunc2,
2508                                         "SFUNC2 = %s, STYPE2 = %s",
2509                                         agginfo[i].aggtransfn2,
2510                                         fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype2), false));
2511                         if (agginfo[i].agginitval2)
2512                                 appendPQExpBuffer(sfunc2, ", INITCOND2 = '%s'",
2513                                                 agginfo[i].agginitval2);
2514                 }
2515
2516                 if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
2517                         appendPQExpBuffer(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
2518                 if (sfunc1->data[0] != '\0' && sfunc2->data[0] != '\0')
2519                 {
2520                         comma1[0] = ',';
2521                         comma1[1] = '\0';
2522                 }
2523                 else
2524                         comma1[0] = '\0';
2525
2526                 if (finalfunc->data[0] != '\0' && (sfunc1->data[0] != '\0' || sfunc2->data[0] != '\0'))
2527                 {
2528                         comma2[0] = ',';
2529                         comma2[1] = '\0';
2530                 }
2531                 else
2532                         comma2[0] = '\0';
2533
2534                 becomeUser(fout, agginfo[i].usename);
2535
2536                 if (dropSchema)
2537                 {
2538                         resetPQExpBuffer(q);
2539                         appendPQExpBuffer(q, "DROP AGGREGATE %s %s;\n", agginfo[i].aggname,
2540                                         fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
2541                         fputs(q->data, fout);
2542                 }
2543
2544                 resetPQExpBuffer(q);
2545                 appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );\n",
2546                                 agginfo[i].aggname,
2547                                 basetype->data,
2548                                 sfunc1->data,
2549                                 comma1,
2550                                 sfunc2->data,
2551                                 comma2,
2552                                 finalfunc->data);
2553
2554                 fputs(q->data, fout);
2555         }
2556 }
2557
2558 /*
2559  * These are some support functions to fix the acl problem of pg_dump
2560  *
2561  * Matthew C. Aycock 12/02/97
2562  */
2563
2564 /* Append a keyword to a keyword list, inserting comma if needed.
2565  * Caller must make aclbuf big enough for all possible keywords.
2566  */
2567 static void
2568 AddAcl(char *aclbuf, const char *keyword)
2569 {
2570         if (*aclbuf)
2571                 strcat(aclbuf, ",");
2572         strcat(aclbuf, keyword);
2573 }
2574
2575 /*
2576  * This will take a string of 'arwR' and return a malloced,
2577  * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
2578  */
2579 static char *
2580 GetPrivileges(const char *s)
2581 {
2582         char            aclbuf[100];
2583
2584         aclbuf[0] = '\0';
2585
2586         if (strchr(s, 'a'))
2587                 AddAcl(aclbuf, "INSERT");
2588
2589         if (strchr(s, 'w'))
2590                 AddAcl(aclbuf, "UPDATE,DELETE");
2591
2592         if (strchr(s, 'r'))
2593                 AddAcl(aclbuf, "SELECT");
2594
2595         if (strchr(s, 'R'))
2596                 AddAcl(aclbuf, "RULE");
2597
2598         /* Special-case when they're all there */
2599         if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
2600                 return strdup("ALL");
2601
2602         return strdup(aclbuf);
2603 }
2604
2605 /*
2606  * dumpACL:
2607  *        Write out grant/revoke information
2608  *        Called for sequences and tables
2609  */
2610
2611 static void
2612 dumpACL(FILE *fout, TableInfo tbinfo)
2613 {
2614         const char *acls = tbinfo.relacl;
2615         char       *aclbuf,
2616                            *tok,
2617                            *eqpos,
2618                            *priv;
2619
2620         if (strlen(acls) == 0)
2621                 return;                                 /* table has default permissions */
2622
2623         /*
2624          * Revoke Default permissions for PUBLIC. Is this actually necessary,
2625          * or is it just a waste of time?
2626          */
2627         fprintf(fout,
2628                         "REVOKE ALL on %s from PUBLIC;\n",
2629                         fmtId(tbinfo.relname, force_quotes));
2630
2631         /* Make a working copy of acls so we can use strtok */
2632         aclbuf = strdup(acls);
2633
2634         /* Scan comma-separated ACL items */
2635         for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
2636         {
2637                 /*
2638                  * Token may start with '{' and/or '"'.  Actually only the start
2639                  * of the string should have '{', but we don't verify that.
2640                  */
2641                 if (*tok == '{')
2642                         tok++;
2643                 if (*tok == '"')
2644                         tok++;
2645
2646                 /* User name is string up to = in tok */
2647                 eqpos = strchr(tok, '=');
2648                 if (!eqpos)
2649                 {
2650                         fprintf(stderr, "Could not parse ACL list for '%s'...Exiting!\n",
2651                                         tbinfo.relname);
2652                         exit_nicely(g_conn);
2653                 }
2654
2655                 /*
2656                  * Parse the privileges (right-hand side).      Skip if there are
2657                  * none.
2658                  */
2659                 priv = GetPrivileges(eqpos + 1);
2660                 if (*priv)
2661                 {
2662                         fprintf(fout,
2663                                         "GRANT %s on %s to ",
2664                                         priv, fmtId(tbinfo.relname, force_quotes));
2665
2666                         /*
2667                          * Note: fmtId() can only be called once per printf, so don't
2668                          * try to merge printing of username into the above printf.
2669                          */
2670                         if (eqpos == tok)
2671                         {
2672                                 /* Empty left-hand side means "PUBLIC" */
2673                                 fprintf(fout, "PUBLIC;\n");
2674                         }
2675                         else
2676                         {
2677                                 *eqpos = '\0';  /* it's ok to clobber aclbuf */
2678                                 if (strncmp(tok, "group ", strlen("group ")) == 0)
2679                                         fprintf(fout, "GROUP %s;\n",
2680                                                         fmtId(tok + strlen("group "), force_quotes));
2681                                 else
2682                                         fprintf(fout, "%s;\n", fmtId(tok, force_quotes));
2683                         }
2684                 }
2685                 free(priv);
2686         }
2687
2688         free(aclbuf);
2689 }
2690
2691
2692 /*
2693  * dumpTables:
2694  *        write out to fout all the user-define tables
2695  */
2696
2697 void
2698 dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
2699                    InhInfo *inhinfo, int numInherits,
2700                    TypeInfo *tinfo, int numTypes, const char *tablename,
2701                    const bool aclsSkip)
2702 {
2703         int                     i,
2704                                 j,
2705                                 k;
2706         PQExpBuffer     q = createPQExpBuffer();
2707         char            *serialSeq = NULL;              /* implicit sequence name created
2708                                                                                  * by SERIAL datatype */
2709         const char *serialSeqSuffix = "_id_seq";        /* suffix for implicit
2710                                                                                                  * SERIAL sequences */
2711         char      **parentRels;         /* list of names of parent relations */
2712         int                     numParents;
2713         int                     actual_atts;    /* number of attrs in this CREATE statment */
2714         int32           tmp_typmod;
2715         int                     precision;
2716         int                     scale;
2717
2718
2719         /* First - dump SEQUENCEs */
2720         if (tablename)
2721         {
2722                 serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
2723                 strcpy(serialSeq, tablename);
2724                 strcat(serialSeq, serialSeqSuffix);
2725         }
2726         for (i = 0; i < numTables; i++)
2727         {
2728                 if (!(tblinfo[i].sequence))
2729                         continue;
2730                 if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
2731                         || (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
2732                 {
2733                         becomeUser(fout, tblinfo[i].usename);
2734                         dumpSequence(fout, tblinfo[i]);
2735                         if (!aclsSkip)
2736                                 dumpACL(fout, tblinfo[i]);
2737                 }
2738         }
2739         if (tablename)
2740                 free(serialSeq);
2741
2742         for (i = 0; i < numTables; i++)
2743         {
2744                 if (tblinfo[i].sequence)/* already dumped */
2745                         continue;
2746
2747                 if (!tablename || (!strcmp(tblinfo[i].relname, tablename)))
2748                 {
2749
2750                         /* Skip VIEW relations */
2751
2752                         /*
2753                          * if (isViewRule(tblinfo[i].relname)) continue;
2754                          */
2755
2756                         parentRels = tblinfo[i].parentRels;
2757                         numParents = tblinfo[i].numParents;
2758
2759                         becomeUser(fout, tblinfo[i].usename);
2760
2761                         if (dropSchema)
2762                         {
2763                                 resetPQExpBuffer(q);
2764                                 appendPQExpBuffer(q, "DROP TABLE %s;\n", fmtId(tblinfo[i].relname, force_quotes));
2765                                 fputs(q->data, fout);
2766                         }
2767
2768                         resetPQExpBuffer(q);
2769                         appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
2770                         actual_atts = 0;
2771                         for (j = 0; j < tblinfo[i].numatts; j++)
2772                         {
2773                                 if (tblinfo[i].inhAttrs[j] == 0)
2774                                 {
2775                                         if (actual_atts > 0)
2776                                                 appendPQExpBuffer(q, ",\n\t");
2777                                         appendPQExpBuffer(q, "%s ",
2778                                                         fmtId(tblinfo[i].attnames[j], force_quotes));
2779
2780                                         /* Show lengths on bpchar and varchar */
2781                                         if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
2782                                         {
2783                                                 int                     len = (tblinfo[i].atttypmod[j] - VARHDRSZ);
2784
2785                                                 appendPQExpBuffer(q, "character");
2786                                                 if (len > 1)
2787                                                         appendPQExpBuffer(q, "(%d)",
2788                                                                         tblinfo[i].atttypmod[j] - VARHDRSZ);
2789                                         }
2790                                         else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
2791                                         {
2792                                                 appendPQExpBuffer(q, "character varying");
2793                                                 if (tblinfo[i].atttypmod[j] != -1)
2794                                                 {
2795                                                         appendPQExpBuffer(q, "(%d)",
2796                                                                         tblinfo[i].atttypmod[j] - VARHDRSZ);
2797                                                 }
2798                                         }
2799                                         else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
2800                                         {
2801                                                 appendPQExpBuffer(q, "numeric");
2802                                                 if (tblinfo[i].atttypmod[j] != -1)
2803                                                 {
2804                                                         tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
2805                                                         precision = (tmp_typmod >> 16) & 0xffff;
2806                                                         scale = tmp_typmod & 0xffff;
2807                                                         appendPQExpBuffer(q, "(%d,%d)",
2808                                                                         precision, scale);
2809                                                 }
2810                                         }
2811
2812                                         /*
2813                                          * char is an internal single-byte data type; Let's
2814                                          * make sure we force it through with quotes. - thomas
2815                                          * 1998-12-13
2816                                          */
2817                                         else if (!strcmp(tblinfo[i].typnames[j], "char"))
2818                                         {
2819                                                 appendPQExpBuffer(q, "%s",
2820                                                                 fmtId(tblinfo[i].typnames[j], true));
2821                                         }
2822                                         else
2823                                         {
2824                                                 appendPQExpBuffer(q, "%s",
2825                                                                 fmtId(tblinfo[i].typnames[j], false));
2826                                         }
2827                                         if (tblinfo[i].adef_expr[j] != NULL)
2828                                                 appendPQExpBuffer(q, " DEFAULT %s",
2829                                                                 tblinfo[i].adef_expr[j]);
2830                                         if (tblinfo[i].notnull[j])
2831                                                 appendPQExpBuffer(q, " NOT NULL");
2832                                         actual_atts++;
2833                                 }
2834                         }
2835
2836                         /* put the CONSTRAINTS inside the table def */
2837                         for (k = 0; k < tblinfo[i].ncheck; k++)
2838                         {
2839                                 if (actual_atts + k > 0)
2840                                         appendPQExpBuffer(q, ",\n\t");
2841                                 appendPQExpBuffer(q, "%s",
2842                                                 tblinfo[i].check_expr[k]);
2843                         }
2844
2845             /* PRIMARY KEY */
2846             if (tblinfo[i].primary_key) {
2847                 if (actual_atts + tblinfo[i].ncheck > 0)
2848                     appendPQExpBuffer(q, ",\n\t");
2849                 appendPQExpBuffer(q, "PRIMARY KEY (%s)", tblinfo[i].primary_key);
2850             }
2851
2852             appendPQExpBuffer(q, "\n)");
2853
2854                         if (numParents > 0)
2855                         {
2856                                 appendPQExpBuffer(q, "\ninherits (");
2857                                 for (k = 0; k < numParents; k++)
2858                                 {
2859                                         appendPQExpBuffer(q, "%s%s",
2860                                                         (k > 0) ? ", " : "",
2861                                                         fmtId(parentRels[k], force_quotes));
2862                                 }
2863                                 appendPQExpBuffer(q, ")");
2864                         }
2865
2866                         appendPQExpBuffer(q, ";\n");
2867                         fputs(q->data, fout);
2868                         if (!aclsSkip)
2869                                 dumpACL(fout, tblinfo[i]);
2870
2871                 }
2872         }
2873 }
2874
2875 /*
2876  * dumpIndices:
2877  *        write out to fout all the user-define indices
2878  */
2879 void
2880 dumpIndices(FILE *fout, IndInfo *indinfo, int numIndices,
2881                         TableInfo *tblinfo, int numTables, const char *tablename)
2882 {
2883         int                     i,
2884                                 k;
2885         int                     tableInd;
2886         PQExpBuffer     attlist = createPQExpBuffer();
2887         char       *classname[INDEX_MAX_KEYS];
2888         char       *funcname;           /* the name of the function to comput the
2889                                                                  * index key from */
2890         int                     indkey,
2891                                 indclass;
2892         int                     nclass;
2893
2894         PQExpBuffer     q = createPQExpBuffer(),
2895                                 id1 = createPQExpBuffer(),
2896                                 id2 = createPQExpBuffer();
2897         PGresult   *res;
2898
2899         for (i = 0; i < numIndices; i++)
2900         {
2901                 tableInd = findTableByName(tblinfo, numTables,
2902                                                                    indinfo[i].indrelname);
2903                 if (tableInd < 0)
2904                 {
2905                         fprintf(stderr, "failed sanity check, table %s was not found\n",
2906                                         indinfo[i].indrelname);
2907                         exit(2);
2908                 }
2909
2910                 if (strcmp(indinfo[i].indproc, "0") == 0)
2911                         funcname = NULL;
2912                 else
2913                 {
2914
2915                         /*
2916                          * the funcname is an oid which we use to find the name of the
2917                          * pg_proc.  We need to do this because getFuncs() only reads
2918                          * in the user-defined funcs not all the funcs.  We might not
2919                          * find what we want by looking in FuncInfo*
2920                          */
2921                         resetPQExpBuffer(q);
2922                         appendPQExpBuffer(q,
2923                                         "SELECT proname from pg_proc "
2924                                         "where pg_proc.oid = '%s'::oid",
2925                                         indinfo[i].indproc);
2926                         res = PQexec(g_conn, q->data);
2927                         if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2928                         {
2929                                 fprintf(stderr, "dumpIndices(): SELECT (funcname) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2930                                 exit_nicely(g_conn);
2931                         }
2932                         funcname = strdup(PQgetvalue(res, 0,
2933                                                                                  PQfnumber(res, "proname")));
2934                         PQclear(res);
2935                 }
2936
2937                 /* convert opclass oid(s) into names */
2938                 for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
2939                 {
2940                         indclass = atoi(indinfo[i].indclass[nclass]);
2941                         if (indclass == 0)
2942                                 break;
2943                         resetPQExpBuffer(q);
2944                         appendPQExpBuffer(q,
2945                                         "SELECT opcname from pg_opclass "
2946                                         "where pg_opclass.oid = '%u'::oid",
2947                                         indclass);
2948                         res = PQexec(g_conn, q->data);
2949                         if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2950                         {
2951                                 fprintf(stderr, "dumpIndices(): SELECT (classname) failed.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2952                                 exit_nicely(g_conn);
2953                         }
2954                         classname[nclass] = strdup(PQgetvalue(res, 0,
2955                                                                                          PQfnumber(res, "opcname")));
2956                         PQclear(res);
2957                 }
2958
2959                 if (funcname && nclass != 1)
2960                 {
2961                         fprintf(stderr, "dumpIndices(): Must be exactly one OpClass "
2962                                         "for functional index %s\n", indinfo[i].indexrelname);
2963                         exit_nicely(g_conn);
2964                 }
2965
2966                 /* convert attribute numbers into attribute list */
2967                 resetPQExpBuffer(attlist);
2968                 for (k = 0; k < INDEX_MAX_KEYS; k++)
2969                 {
2970                         char       *attname;
2971
2972                         indkey = atoi(indinfo[i].indkey[k]);
2973                         if (indkey == InvalidAttrNumber)
2974                                 break;
2975                         indkey--;
2976                         if (indkey == ObjectIdAttributeNumber - 1)
2977                                 attname = "oid";
2978                         else
2979                                 attname = tblinfo[tableInd].attnames[indkey];
2980                         if (funcname)
2981                                 appendPQExpBuffer(attlist, "%s%s",
2982                                          (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
2983                         else
2984                         {
2985                                 if (k >= nclass)
2986                                 {
2987                                         fprintf(stderr, "dumpIndices(): OpClass not found for "
2988                                                         "attribute '%s' of index '%s'\n",
2989                                                         attname, indinfo[i].indexrelname);
2990                                         exit_nicely(g_conn);
2991                                 }
2992                                 resetPQExpBuffer(id1);
2993                                 resetPQExpBuffer(id2);
2994                                 appendPQExpBuffer(id1, fmtId(attname, force_quotes));
2995                                 appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
2996                                 appendPQExpBuffer(attlist, "%s%s %s",
2997                                                 (k == 0) ? "" : ", ", id1->data, id2->data);
2998                                 free(classname[k]);
2999                         }
3000                 }
3001
3002                 if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
3003                 {
3004
3005                         /*
3006                          * We make the index belong to the owner of its table, which
3007                          * is not necessarily right but should answer 99% of the time.
3008                          * Would have to add owner name to IndInfo to do it right.
3009                          */
3010                         becomeUser(fout, tblinfo[tableInd].usename);
3011
3012                         resetPQExpBuffer(id1);
3013                         resetPQExpBuffer(id2);
3014                         appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
3015                         appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
3016
3017                         if (dropSchema)
3018                         {
3019                                 resetPQExpBuffer(q);
3020                                 appendPQExpBuffer(q, "DROP INDEX %s;\n", id1->data);
3021                                 fputs(q->data, fout);
3022                         }
3023
3024                         fprintf(fout, "CREATE %s INDEX %s on %s using %s (",
3025                           (strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
3026                                         id1->data,
3027                                         id2->data,
3028                                         indinfo[i].indamname);
3029                         if (funcname)
3030                         {
3031                                 /* need 2 printf's here cuz fmtId has static return area */
3032                                 fprintf(fout, " %s", fmtId(funcname, false));
3033                                 fprintf(fout, " (%s) %s );\n", attlist->data, fmtId(classname[0], force_quotes));
3034                                 free(funcname);
3035                                 free(classname[0]);
3036                         }
3037                         else
3038                                 fprintf(fout, " %s );\n", attlist->data);
3039                 }
3040         }
3041
3042 }
3043
3044 /*
3045  * dumpTuples
3046  *        prints out the tuples in ASCII representation. The output is a valid
3047  *        input to COPY FROM stdin.
3048  *
3049  *        We only need to do this for POSTGRES 4.2 databases since the
3050  *        COPY TO statment doesn't escape newlines properly. It's been fixed
3051  *        in PostgreSQL.
3052  *
3053  * the attrmap passed in tells how to map the attributes copied in to the
3054  * attributes copied out
3055  */
3056 #ifdef NOT_USED
3057 void
3058 dumpTuples(PGresult *res, FILE *fout, int *attrmap)
3059 {
3060         int                     j,
3061                                 k;
3062         int                     m,
3063                                 n;
3064         char      **outVals = NULL; /* values to copy out */
3065
3066         n = PQntuples(res);
3067         m = PQnfields(res);
3068
3069         if (m > 0)
3070         {
3071
3072                 /*
3073                  * Print out the tuples but only print tuples with at least 1
3074                  * field.
3075                  */
3076                 outVals = (char **) malloc(m * sizeof(char *));
3077
3078                 for (j = 0; j < n; j++)
3079                 {
3080                         for (k = 0; k < m; k++)
3081                                 outVals[attrmap[k]] = PQgetvalue(res, j, k);
3082                         for (k = 0; k < m; k++)
3083                         {
3084                                 char       *pval = outVals[k];
3085
3086                                 if (k != 0)
3087                                         fputc('\t', fout);      /* delimiter for attribute */
3088
3089                                 if (pval)
3090                                 {
3091                                         while (*pval != '\0')
3092                                         {
3093                                                 /* escape tabs, newlines and backslashes */
3094                                                 if (*pval == '\t' || *pval == '\n' || *pval == '\\')
3095                                                         fputc('\\', fout);
3096                                                 fputc(*pval, fout);
3097                                                 pval++;
3098                                         }
3099                                 }
3100                         }
3101                         fputc('\n', fout);      /* delimiter for a tuple */
3102                 }
3103                 free(outVals);
3104         }
3105 }
3106
3107 #endif
3108
3109 /*
3110  * setMaxOid -
3111  * find the maximum oid and generate a COPY statement to set it
3112 */
3113
3114 static void
3115 setMaxOid(FILE *fout)
3116 {
3117         PGresult   *res;
3118         Oid                     max_oid;
3119
3120         res = PQexec(g_conn, "CREATE TABLE pgdump_oid (dummy int4)");
3121         if (!res ||
3122                 PQresultStatus(res) != PGRES_COMMAND_OK)
3123         {
3124                 fprintf(stderr, "Can not create pgdump_oid table.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3125                 exit_nicely(g_conn);
3126         }
3127         PQclear(res);
3128         res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
3129         if (!res ||
3130                 PQresultStatus(res) != PGRES_COMMAND_OK)
3131         {
3132                 fprintf(stderr, "Can not insert into pgdump_oid table.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3133                 exit_nicely(g_conn);
3134         }
3135         max_oid = atol(PQoidStatus(res));
3136         if (max_oid == 0)
3137         {
3138                 fprintf(stderr, "Invalid max id in setMaxOid\n");
3139                 exit_nicely(g_conn);
3140         }
3141         PQclear(res);
3142         res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
3143         if (!res ||
3144                 PQresultStatus(res) != PGRES_COMMAND_OK)
3145         {
3146                 fprintf(stderr, "Can not drop pgdump_oid table.  Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3147                 exit_nicely(g_conn);
3148         }
3149         PQclear(res);
3150         if (g_verbose)
3151                 fprintf(stderr, "%s maximum system oid is %u %s\n",
3152                                 g_comment_start, max_oid, g_comment_end);
3153         fprintf(fout, "CREATE TABLE pgdump_oid (dummy int4);\n");
3154         fprintf(fout, "COPY pgdump_oid WITH OIDS FROM stdin;\n");
3155         fprintf(fout, "%-d\t0\n", max_oid);
3156         fprintf(fout, "\\.\n");
3157         fprintf(fout, "DROP TABLE pgdump_oid;\n");
3158 }
3159
3160 /*
3161  * findLastBuiltInOid -
3162  * find the last built in oid
3163  * we do this by looking up the oid of 'template1' in pg_database,
3164  * this is probably not foolproof but comes close
3165 */
3166
3167 static int
3168 findLastBuiltinOid(void)
3169 {
3170         PGresult   *res;
3171         int                     ntups;
3172         int                     last_oid;
3173
3174         res = PQexec(g_conn,
3175                           "SELECT oid from pg_database where datname = 'template1'");
3176         if (res == NULL ||
3177                 PQresultStatus(res) != PGRES_TUPLES_OK)
3178         {
3179                 fprintf(stderr,"pg_dump error in finding the template1 database.");
3180                 fprintf(stderr,"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3181                 exit_nicely(g_conn);
3182         }
3183         ntups = PQntuples(res);
3184         if (ntups < 1)
3185         {
3186                 fprintf(stderr,"pg_dump: couldn't find the template1 database.\n");
3187                 fprintf(stderr,"There is no 'template1' entry in the 'pg_database' table.\n");
3188                 exit_nicely(g_conn);
3189         }
3190         if (ntups > 1)
3191         {
3192                 fprintf(stderr,"pg_dump: found more than one template1 database.\n");
3193                 fprintf(stderr,"There is more than one 'template1' entry in the 'pg_database' table\n");
3194                 exit_nicely(g_conn);
3195         }
3196         last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
3197         PQclear(res);
3198         return last_oid;
3199 }
3200
3201
3202 /*
3203  * checkForQuote:
3204  *        checks a string for quote characters and quotes them
3205  */
3206 static char *
3207 checkForQuote(const char *s)
3208 {
3209         char       *r;
3210         char            c;
3211         char       *result;
3212
3213         int                     j = 0;
3214
3215         r = malloc(strlen(s) * 3 + 1);          /* definitely long enough */
3216
3217         while ((c = *s) != '\0')
3218         {
3219
3220                 if (c == '\'')
3221                 {
3222                         r[j++] = '\'';          /* quote the single quotes */
3223                 }
3224                 r[j++] = c;
3225                 s++;
3226         }
3227         r[j] = '\0';
3228
3229         result = strdup(r);
3230         free(r);
3231
3232         return result;
3233
3234 }
3235
3236
3237 static void
3238 dumpSequence(FILE *fout, TableInfo tbinfo)
3239 {
3240         PGresult        *res;
3241         int4            last,
3242                                 incby,
3243                                 maxv,
3244                                 minv,
3245                                 cache;
3246         char            cycled,
3247                                 called;
3248     const char  *t;
3249         PQExpBuffer     query = createPQExpBuffer();
3250
3251         appendPQExpBuffer(query,
3252                         "SELECT sequence_name, last_value, increment_by, max_value, "
3253                         "min_value, cache_value, is_cycled, is_called from %s",
3254                         fmtId(tbinfo.relname, force_quotes));
3255
3256         res = PQexec(g_conn, query->data);
3257         if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
3258         {
3259                 fprintf(stderr, "dumpSequence(%s): SELECT failed.  Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
3260                 exit_nicely(g_conn);
3261         }
3262
3263         if (PQntuples(res) != 1)
3264         {
3265                 fprintf(stderr, "dumpSequence(%s): %d (!= 1) tuples returned by SELECT\n",
3266                                 tbinfo.relname, PQntuples(res));
3267                 exit_nicely(g_conn);
3268         }
3269
3270         if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
3271         {
3272                 fprintf(stderr, "dumpSequence(%s): different sequence name "
3273                                 "returned by SELECT: %s\n",
3274                                 tbinfo.relname, PQgetvalue(res, 0, 0));
3275                 exit_nicely(g_conn);
3276         }
3277
3278
3279         last = atoi(PQgetvalue(res, 0, 1));
3280         incby = atoi(PQgetvalue(res, 0, 2));
3281         maxv = atoi(PQgetvalue(res, 0, 3));
3282         minv = atoi(PQgetvalue(res, 0, 4));
3283         cache = atoi(PQgetvalue(res, 0, 5));
3284         t = PQgetvalue(res, 0, 6);
3285         cycled = *t;
3286         t = PQgetvalue(res, 0, 7);
3287         called = *t;
3288
3289         PQclear(res);
3290
3291         if (dropSchema)
3292         {
3293                 resetPQExpBuffer(query);
3294                 appendPQExpBuffer(query, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
3295                 fputs(query->data, fout);
3296         }
3297
3298         resetPQExpBuffer(query);
3299         appendPQExpBuffer(query,
3300                         "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
3301                         "minvalue %d  cache %d %s;\n",
3302          fmtId(tbinfo.relname, force_quotes), last, incby, maxv, minv, cache,
3303                         (cycled == 't') ? "cycle" : "");
3304
3305         fputs(query->data, fout);
3306
3307         if (called == 'f')
3308                 return;                                 /* nothing to do more */
3309
3310         resetPQExpBuffer(query);
3311         appendPQExpBuffer(query, "SELECT nextval ('%s');\n", fmtId(tbinfo.relname, force_quotes));
3312         fputs(query->data, fout);
3313
3314 }
3315
3316
3317 static void
3318 dumpTriggers(FILE *fout, const char *tablename,
3319                          TableInfo *tblinfo, int numTables)
3320 {
3321         int                     i,
3322                                 j;
3323
3324         if (g_verbose)
3325                 fprintf(stderr, "%s dumping out triggers %s\n",
3326                                 g_comment_start, g_comment_end);
3327
3328         for (i = 0; i < numTables; i++)
3329         {
3330                 if (tablename && strcmp(tblinfo[i].relname, tablename))
3331                         continue;
3332                 for (j = 0; j < tblinfo[i].ntrig; j++)
3333                 {
3334                         becomeUser(fout, tblinfo[i].usename);
3335                         fputs(tblinfo[i].triggers[j], fout);
3336                 }
3337         }
3338 }
3339
3340
3341 static void
3342 dumpRules(FILE *fout, const char *tablename,
3343                   TableInfo *tblinfo, int numTables)
3344 {
3345         PGresult   *res;
3346         int                     nrules;
3347         int                     i,
3348                                 t;
3349         PQExpBuffer     query = createPQExpBuffer();
3350
3351         int                     i_definition;
3352
3353         if (g_verbose)
3354                 fprintf(stderr, "%s dumping out rules %s\n",
3355                                 g_comment_start, g_comment_end);
3356
3357         /*
3358          * For each table we dump
3359          */
3360         for (t = 0; t < numTables; t++)
3361         {
3362                 if (tablename && strcmp(tblinfo[t].relname, tablename))
3363                         continue;
3364
3365                 /*
3366                  * Get all rules defined for this table
3367                  */
3368                 resetPQExpBuffer(query);
3369                 appendPQExpBuffer(query, "SELECT pg_get_ruledef(pg_rewrite.rulename) "
3370                                 "AS definition FROM pg_rewrite, pg_class "
3371                                 "WHERE pg_class.relname = '%s' "
3372                                 "AND pg_rewrite.ev_class = pg_class.oid "
3373                                 "ORDER BY pg_rewrite.oid",
3374                                 tblinfo[t].relname);
3375                 res = PQexec(g_conn, query->data);
3376                 if (!res ||
3377                         PQresultStatus(res) != PGRES_TUPLES_OK)
3378                 {
3379                         fprintf(stderr, "dumpRules(): SELECT failed for table %s.  Explanation from backend: '%s'.\n",
3380                                         tblinfo[t].relname, PQerrorMessage(g_conn));
3381                         exit_nicely(g_conn);
3382                 }
3383
3384                 nrules = PQntuples(res);
3385                 i_definition = PQfnumber(res, "definition");
3386
3387                 /*
3388                  * Dump them out
3389                  */
3390                 for (i = 0; i < nrules; i++)
3391                         fprintf(fout, "%s\n", PQgetvalue(res, i, i_definition));
3392
3393                 PQclear(res);
3394         }
3395 }
3396
3397
3398 /* Issue a psql \connect command to become the specified user.
3399  * We want to do this only if we are dumping ACLs,
3400  * and only if the new username is different from the last one
3401  * (to avoid the overhead of useless backend launches).
3402  */
3403
3404 static void
3405 becomeUser(FILE *fout, const char *username)
3406 {
3407         static const char *lastusername = "";
3408
3409         if (aclsSkip)
3410                 return;
3411
3412         if (strcmp(lastusername, username) == 0)
3413                 return;
3414
3415         fprintf(fout, "\\connect - %s\n", username);
3416
3417         lastusername = username;
3418 }