~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/bin/pg_dump/pg_dump.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * pg_dump.c
 
4
 *        pg_dump is a utility for dumping out a postgres database
 
5
 *        into a script file.
 
6
 *
 
7
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 *      pg_dump will read the system catalogs in a database and dump out a
 
11
 *      script that reproduces the schema in terms of SQL that is understood
 
12
 *      by PostgreSQL
 
13
 *
 
14
 *      Note that pg_dump runs in a transaction-snapshot mode transaction,
 
15
 *      so it sees a consistent snapshot of the database including system
 
16
 *      catalogs. However, it relies in part on various specialized backend
 
17
 *      functions like pg_get_indexdef(), and those things tend to run on
 
18
 *      SnapshotNow time, ie they look at the currently committed state.  So
 
19
 *      it is possible to get 'cache lookup failed' error if someone
 
20
 *      performs DDL changes while a dump is happening. The window for this
 
21
 *      sort of thing is from the acquisition of the transaction snapshot to
 
22
 *      getSchemaData() (when pg_dump acquires AccessShareLock on every
 
23
 *      table it intends to dump). It isn't very large, but it can happen.
 
24
 *
 
25
 *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
 
26
 *
 
27
 * IDENTIFICATION
 
28
 *        src/bin/pg_dump/pg_dump.c
 
29
 *
 
30
 *-------------------------------------------------------------------------
 
31
 */
 
32
 
 
33
#include "postgres_fe.h"
 
34
 
 
35
#include <unistd.h>
 
36
#include <ctype.h>
 
37
#ifdef ENABLE_NLS
 
38
#include <locale.h>
 
39
#endif
 
40
#ifdef HAVE_TERMIOS_H
 
41
#include <termios.h>
 
42
#endif
 
43
 
 
44
#include "getopt_long.h"
 
45
 
 
46
#include "access/attnum.h"
 
47
#include "access/sysattr.h"
 
48
#include "access/transam.h"
 
49
#include "catalog/pg_cast.h"
 
50
#include "catalog/pg_class.h"
 
51
#include "catalog/pg_default_acl.h"
 
52
#include "catalog/pg_largeobject.h"
 
53
#include "catalog/pg_largeobject_metadata.h"
 
54
#include "catalog/pg_proc.h"
 
55
#include "catalog/pg_trigger.h"
 
56
#include "catalog/pg_type.h"
 
57
#include "libpq/libpq-fs.h"
 
58
 
 
59
#include "pg_backup_archiver.h"
 
60
#include "dumputils.h"
 
61
 
 
62
extern char *optarg;
 
63
extern int      optind,
 
64
                        opterr;
 
65
 
 
66
 
 
67
typedef struct
 
68
{
 
69
        const char *descr;                      /* comment for an object */
 
70
        Oid                     classoid;               /* object class (catalog OID) */
 
71
        Oid                     objoid;                 /* object OID */
 
72
        int                     objsubid;               /* subobject (table column #) */
 
73
} CommentItem;
 
74
 
 
75
typedef struct
 
76
{
 
77
        const char *provider;           /* label provider of this security label */
 
78
        const char *label;                      /* security label for an object */
 
79
        Oid                     classoid;               /* object class (catalog OID) */
 
80
        Oid                     objoid;                 /* object OID */
 
81
        int                     objsubid;               /* subobject (table column #) */
 
82
} SecLabelItem;
 
83
 
 
84
/* global decls */
 
85
bool            g_verbose;                      /* User wants verbose narration of our
 
86
                                                                 * activities. */
 
87
Archive    *g_fout;                             /* the script file */
 
88
PGconn     *g_conn;                             /* the database connection */
 
89
 
 
90
/* various user-settable parameters */
 
91
bool            schemaOnly;
 
92
bool            dataOnly;
 
93
bool            aclsSkip;
 
94
const char *lockWaitTimeout;
 
95
 
 
96
/* subquery used to convert user ID (eg, datdba) to user name */
 
97
static const char *username_subquery;
 
98
 
 
99
/* obsolete as of 7.3: */
 
100
static Oid      g_last_builtin_oid; /* value of the last builtin oid */
 
101
 
 
102
/*
 
103
 * Object inclusion/exclusion lists
 
104
 *
 
105
 * The string lists record the patterns given by command-line switches,
 
106
 * which we then convert to lists of OIDs of matching objects.
 
107
 */
 
108
static SimpleStringList schema_include_patterns = {NULL, NULL};
 
109
static SimpleOidList schema_include_oids = {NULL, NULL};
 
110
static SimpleStringList schema_exclude_patterns = {NULL, NULL};
 
111
static SimpleOidList schema_exclude_oids = {NULL, NULL};
 
112
 
 
113
static SimpleStringList table_include_patterns = {NULL, NULL};
 
114
static SimpleOidList table_include_oids = {NULL, NULL};
 
115
static SimpleStringList table_exclude_patterns = {NULL, NULL};
 
116
static SimpleOidList table_exclude_oids = {NULL, NULL};
 
117
 
 
118
/* default, if no "inclusion" switches appear, is to dump everything */
 
119
static bool include_everything = true;
 
120
 
 
121
char            g_opaque_type[10];      /* name for the opaque type */
 
122
 
 
123
/* placeholders for the delimiters for comments */
 
124
char            g_comment_start[10];
 
125
char            g_comment_end[10];
 
126
 
 
127
static const CatalogId nilCatalogId = {0, 0};
 
128
 
 
129
/* these are to avoid passing around info for findNamespace() */
 
130
static NamespaceInfo *g_namespaces;
 
131
static int      g_numNamespaces;
 
132
 
 
133
/* flags for various command-line long options */
 
134
static int      binary_upgrade = 0;
 
135
static int      disable_dollar_quoting = 0;
 
136
static int      dump_inserts = 0;
 
137
static int      column_inserts = 0;
 
138
static int      no_security_label = 0;
 
139
static int      no_unlogged_table_data = 0;
 
140
static int      serializable_deferrable = 0;
 
141
 
 
142
 
 
143
static void help(const char *progname);
 
144
static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
 
145
static void expand_schema_name_patterns(SimpleStringList *patterns,
 
146
                                                        SimpleOidList *oids);
 
147
static void expand_table_name_patterns(SimpleStringList *patterns,
 
148
                                                   SimpleOidList *oids);
 
149
static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
 
150
static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
 
151
static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
 
152
static void dumpComment(Archive *fout, const char *target,
 
153
                        const char *namespace, const char *owner,
 
154
                        CatalogId catalogId, int subid, DumpId dumpId);
 
155
static int findComments(Archive *fout, Oid classoid, Oid objoid,
 
156
                         CommentItem **items);
 
157
static int      collectComments(Archive *fout, CommentItem **items);
 
158
static void dumpSecLabel(Archive *fout, const char *target,
 
159
                         const char *namespace, const char *owner,
 
160
                         CatalogId catalogId, int subid, DumpId dumpId);
 
161
static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
 
162
                          SecLabelItem **items);
 
163
static int      collectSecLabels(Archive *fout, SecLabelItem **items);
 
164
static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
 
165
static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
 
166
static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
 
167
static void dumpType(Archive *fout, TypeInfo *tyinfo);
 
168
static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
 
169
static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
 
170
static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
 
171
static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
 
172
static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
 
173
static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
 
174
static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
 
175
static void dumpFunc(Archive *fout, FuncInfo *finfo);
 
176
static void dumpCast(Archive *fout, CastInfo *cast);
 
177
static void dumpOpr(Archive *fout, OprInfo *oprinfo);
 
178
static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
 
179
static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
 
180
static void dumpCollation(Archive *fout, CollInfo *convinfo);
 
181
static void dumpConversion(Archive *fout, ConvInfo *convinfo);
 
182
static void dumpRule(Archive *fout, RuleInfo *rinfo);
 
183
static void dumpAgg(Archive *fout, AggInfo *agginfo);
 
184
static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
 
185
static void dumpTable(Archive *fout, TableInfo *tbinfo);
 
186
static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
 
187
static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
 
188
static void dumpSequence(Archive *fout, TableInfo *tbinfo);
 
189
static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
 
190
static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
 
191
static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
 
192
static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
 
193
static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
 
194
static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
 
195
static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
 
196
static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
 
197
static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
 
198
static void dumpUserMappings(Archive *fout,
 
199
                                 const char *servername, const char *namespace,
 
200
                                 const char *owner, CatalogId catalogId, DumpId dumpId);
 
201
static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
 
202
 
 
203
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 
204
                const char *type, const char *name, const char *subname,
 
205
                const char *tag, const char *nspname, const char *owner,
 
206
                const char *acls);
 
207
 
 
208
static void getDependencies(void);
 
209
static void getDomainConstraints(TypeInfo *tyinfo);
 
210
static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
 
211
static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
 
212
static void getTableDataFKConstraints(void);
 
213
static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
 
214
static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
 
215
                                                          char **allargtypes,
 
216
                                                          char **argmodes,
 
217
                                                          char **argnames);
 
218
static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
 
219
static const char *convertRegProcReference(const char *proc);
 
220
static const char *convertOperatorReference(const char *opr);
 
221
static const char *convertTSFunction(Oid funcOid);
 
222
static Oid      findLastBuiltinOid_V71(const char *);
 
223
static Oid      findLastBuiltinOid_V70(void);
 
224
static void selectSourceSchema(const char *schemaName);
 
225
static char *getFormattedTypeName(Oid oid, OidOptions opts);
 
226
static char *myFormatType(const char *typname, int32 typmod);
 
227
static const char *fmtQualifiedId(const char *schema, const char *id);
 
228
static void getBlobs(Archive *AH);
 
229
static void dumpBlob(Archive *AH, BlobInfo *binfo);
 
230
static int      dumpBlobs(Archive *AH, void *arg);
 
231
static void dumpDatabase(Archive *AH);
 
232
static void dumpEncoding(Archive *AH);
 
233
static void dumpStdStrings(Archive *AH);
 
234
static void binary_upgrade_set_type_oids_by_type_oid(
 
235
                                                                PQExpBuffer upgrade_buffer, Oid pg_type_oid);
 
236
static bool binary_upgrade_set_type_oids_by_rel_oid(
 
237
                                                                 PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
 
238
static void binary_upgrade_set_pg_class_oids(PQExpBuffer upgrade_buffer,
 
239
                                                                 Oid pg_class_oid, bool is_index);
 
240
static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
 
241
                                                                DumpableObject *dobj,
 
242
                                                                const char *objlabel);
 
243
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
 
244
static const char *fmtCopyColumnList(const TableInfo *ti);
 
245
static void do_sql_command(PGconn *conn, const char *query);
 
246
static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
 
247
                                 ExecStatusType expected);
 
248
 
 
249
 
 
250
int
 
251
main(int argc, char **argv)
 
252
{
 
253
        int                     c;
 
254
        const char *filename = NULL;
 
255
        const char *format = "p";
 
256
        const char *dbname = NULL;
 
257
        const char *pghost = NULL;
 
258
        const char *pgport = NULL;
 
259
        const char *username = NULL;
 
260
        const char *dumpencoding = NULL;
 
261
        const char *std_strings;
 
262
        bool            oids = false;
 
263
        TableInfo  *tblinfo;
 
264
        int                     numTables;
 
265
        DumpableObject **dobjs;
 
266
        int                     numObjs;
 
267
        int                     i;
 
268
        enum trivalue prompt_password = TRI_DEFAULT;
 
269
        int                     compressLevel = -1;
 
270
        int                     plainText = 0;
 
271
        int                     outputClean = 0;
 
272
        int                     outputCreateDB = 0;
 
273
        bool            outputBlobs = false;
 
274
        int                     outputNoOwner = 0;
 
275
        char       *outputSuperuser = NULL;
 
276
        char       *use_role = NULL;
 
277
        int                     my_version;
 
278
        int                     optindex;
 
279
        RestoreOptions *ropt;
 
280
        ArchiveFormat archiveFormat = archUnknown;
 
281
        ArchiveMode archiveMode;
 
282
 
 
283
        static int      disable_triggers = 0;
 
284
        static int      outputNoTablespaces = 0;
 
285
        static int      use_setsessauth = 0;
 
286
 
 
287
        static struct option long_options[] = {
 
288
                {"data-only", no_argument, NULL, 'a'},
 
289
                {"blobs", no_argument, NULL, 'b'},
 
290
                {"clean", no_argument, NULL, 'c'},
 
291
                {"create", no_argument, NULL, 'C'},
 
292
                {"file", required_argument, NULL, 'f'},
 
293
                {"format", required_argument, NULL, 'F'},
 
294
                {"host", required_argument, NULL, 'h'},
 
295
                {"ignore-version", no_argument, NULL, 'i'},
 
296
                {"no-reconnect", no_argument, NULL, 'R'},
 
297
                {"oids", no_argument, NULL, 'o'},
 
298
                {"no-owner", no_argument, NULL, 'O'},
 
299
                {"port", required_argument, NULL, 'p'},
 
300
                {"schema", required_argument, NULL, 'n'},
 
301
                {"exclude-schema", required_argument, NULL, 'N'},
 
302
                {"schema-only", no_argument, NULL, 's'},
 
303
                {"superuser", required_argument, NULL, 'S'},
 
304
                {"table", required_argument, NULL, 't'},
 
305
                {"exclude-table", required_argument, NULL, 'T'},
 
306
                {"no-password", no_argument, NULL, 'w'},
 
307
                {"password", no_argument, NULL, 'W'},
 
308
                {"username", required_argument, NULL, 'U'},
 
309
                {"verbose", no_argument, NULL, 'v'},
 
310
                {"no-privileges", no_argument, NULL, 'x'},
 
311
                {"no-acl", no_argument, NULL, 'x'},
 
312
                {"compress", required_argument, NULL, 'Z'},
 
313
                {"encoding", required_argument, NULL, 'E'},
 
314
                {"help", no_argument, NULL, '?'},
 
315
                {"version", no_argument, NULL, 'V'},
 
316
 
 
317
                /*
 
318
                 * the following options don't have an equivalent short option letter
 
319
                 */
 
320
                {"attribute-inserts", no_argument, &column_inserts, 1},
 
321
                {"binary-upgrade", no_argument, &binary_upgrade, 1},
 
322
                {"column-inserts", no_argument, &column_inserts, 1},
 
323
                {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
 
324
                {"disable-triggers", no_argument, &disable_triggers, 1},
 
325
                {"inserts", no_argument, &dump_inserts, 1},
 
326
                {"lock-wait-timeout", required_argument, NULL, 2},
 
327
                {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
 
328
                {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
 
329
                {"role", required_argument, NULL, 3},
 
330
                {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
 
331
                {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
 
332
                {"no-security-label", no_argument, &no_security_label, 1},
 
333
                {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
 
334
 
 
335
                {NULL, 0, NULL, 0}
 
336
        };
 
337
 
 
338
        set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
 
339
 
 
340
        g_verbose = false;
 
341
 
 
342
        strcpy(g_comment_start, "-- ");
 
343
        g_comment_end[0] = '\0';
 
344
        strcpy(g_opaque_type, "opaque");
 
345
 
 
346
        dataOnly = schemaOnly = false;
 
347
        lockWaitTimeout = NULL;
 
348
 
 
349
        progname = get_progname(argv[0]);
 
350
 
 
351
        /* Set default options based on progname */
 
352
        if (strcmp(progname, "pg_backup") == 0)
 
353
                format = "c";
 
354
 
 
355
        if (argc > 1)
 
356
        {
 
357
                if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
 
358
                {
 
359
                        help(progname);
 
360
                        exit(0);
 
361
                }
 
362
                if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
 
363
                {
 
364
                        puts("pg_dump (PostgreSQL) " PG_VERSION);
 
365
                        exit(0);
 
366
                }
 
367
        }
 
368
 
 
369
        while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:",
 
370
                                                        long_options, &optindex)) != -1)
 
371
        {
 
372
                switch (c)
 
373
                {
 
374
                        case 'a':                       /* Dump data only */
 
375
                                dataOnly = true;
 
376
                                break;
 
377
 
 
378
                        case 'b':                       /* Dump blobs */
 
379
                                outputBlobs = true;
 
380
                                break;
 
381
 
 
382
                        case 'c':                       /* clean (i.e., drop) schema prior to create */
 
383
                                outputClean = 1;
 
384
                                break;
 
385
 
 
386
                        case 'C':                       /* Create DB */
 
387
                                outputCreateDB = 1;
 
388
                                break;
 
389
 
 
390
                        case 'E':                       /* Dump encoding */
 
391
                                dumpencoding = optarg;
 
392
                                break;
 
393
 
 
394
                        case 'f':
 
395
                                filename = optarg;
 
396
                                break;
 
397
 
 
398
                        case 'F':
 
399
                                format = optarg;
 
400
                                break;
 
401
 
 
402
                        case 'h':                       /* server host */
 
403
                                pghost = optarg;
 
404
                                break;
 
405
 
 
406
                        case 'i':
 
407
                                /* ignored, deprecated option */
 
408
                                break;
 
409
 
 
410
                        case 'n':                       /* include schema(s) */
 
411
                                simple_string_list_append(&schema_include_patterns, optarg);
 
412
                                include_everything = false;
 
413
                                break;
 
414
 
 
415
                        case 'N':                       /* exclude schema(s) */
 
416
                                simple_string_list_append(&schema_exclude_patterns, optarg);
 
417
                                break;
 
418
 
 
419
                        case 'o':                       /* Dump oids */
 
420
                                oids = true;
 
421
                                break;
 
422
 
 
423
                        case 'O':                       /* Don't reconnect to match owner */
 
424
                                outputNoOwner = 1;
 
425
                                break;
 
426
 
 
427
                        case 'p':                       /* server port */
 
428
                                pgport = optarg;
 
429
                                break;
 
430
 
 
431
                        case 'R':
 
432
                                /* no-op, still accepted for backwards compatibility */
 
433
                                break;
 
434
 
 
435
                        case 's':                       /* dump schema only */
 
436
                                schemaOnly = true;
 
437
                                break;
 
438
 
 
439
                        case 'S':                       /* Username for superuser in plain text output */
 
440
                                outputSuperuser = strdup(optarg);
 
441
                                break;
 
442
 
 
443
                        case 't':                       /* include table(s) */
 
444
                                simple_string_list_append(&table_include_patterns, optarg);
 
445
                                include_everything = false;
 
446
                                break;
 
447
 
 
448
                        case 'T':                       /* exclude table(s) */
 
449
                                simple_string_list_append(&table_exclude_patterns, optarg);
 
450
                                break;
 
451
 
 
452
                        case 'U':
 
453
                                username = optarg;
 
454
                                break;
 
455
 
 
456
                        case 'v':                       /* verbose */
 
457
                                g_verbose = true;
 
458
                                break;
 
459
 
 
460
                        case 'w':
 
461
                                prompt_password = TRI_NO;
 
462
                                break;
 
463
 
 
464
                        case 'W':
 
465
                                prompt_password = TRI_YES;
 
466
                                break;
 
467
 
 
468
                        case 'x':                       /* skip ACL dump */
 
469
                                aclsSkip = true;
 
470
                                break;
 
471
 
 
472
                        case 'Z':                       /* Compression Level */
 
473
                                compressLevel = atoi(optarg);
 
474
                                break;
 
475
 
 
476
                        case 0:
 
477
                                /* This covers the long options. */
 
478
                                break;
 
479
 
 
480
                        case 2:                         /* lock-wait-timeout */
 
481
                                lockWaitTimeout = optarg;
 
482
                                break;
 
483
 
 
484
                        case 3:                         /* SET ROLE */
 
485
                                use_role = optarg;
 
486
                                break;
 
487
 
 
488
                        default:
 
489
                                fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 
490
                                exit(1);
 
491
                }
 
492
        }
 
493
 
 
494
        /* Get database name from command line */
 
495
        if (optind < argc)
 
496
                dbname = argv[optind++];
 
497
 
 
498
        /* Complain if any arguments remain */
 
499
        if (optind < argc)
 
500
        {
 
501
                fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
 
502
                                progname, argv[optind]);
 
503
                fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
 
504
                                progname);
 
505
                exit(1);
 
506
        }
 
507
 
 
508
        /* --column-inserts implies --inserts */
 
509
        if (column_inserts)
 
510
                dump_inserts = 1;
 
511
 
 
512
        if (dataOnly && schemaOnly)
 
513
        {
 
514
                write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
 
515
                exit(1);
 
516
        }
 
517
 
 
518
        if (dataOnly && outputClean)
 
519
        {
 
520
                write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
 
521
                exit(1);
 
522
        }
 
523
 
 
524
        if (dump_inserts && oids)
 
525
        {
 
526
                write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
 
527
                write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
 
528
                exit(1);
 
529
        }
 
530
 
 
531
        archiveFormat = parseArchiveFormat(format, &archiveMode);
 
532
 
 
533
        /* archiveFormat specific setup */
 
534
        if (archiveFormat == archNull)
 
535
                plainText = 1;
 
536
 
 
537
        /*
 
538
         * Ignore compression level for plain format. XXX: This is a bit
 
539
         * inconsistent, tar-format throws an error instead.
 
540
         */
 
541
        if (archiveFormat == archNull)
 
542
                compressLevel = 0;
 
543
 
 
544
        /* Custom and directory formats are compressed by default */
 
545
        if (compressLevel == -1)
 
546
        {
 
547
                if (archiveFormat == archCustom || archiveFormat == archDirectory)
 
548
                        compressLevel = Z_DEFAULT_COMPRESSION;
 
549
                else
 
550
                        compressLevel = 0;
 
551
        }
 
552
 
 
553
        /* open the output file */
 
554
        g_fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
 
555
 
 
556
        if (g_fout == NULL)
 
557
        {
 
558
                write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
 
559
                exit(1);
 
560
        }
 
561
 
 
562
        /* Let the archiver know how noisy to be */
 
563
        g_fout->verbose = g_verbose;
 
564
 
 
565
        my_version = parse_version(PG_VERSION);
 
566
        if (my_version < 0)
 
567
        {
 
568
                write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
 
569
                exit(1);
 
570
        }
 
571
 
 
572
        /*
 
573
         * We allow the server to be back to 7.0, and up to any minor release of
 
574
         * our own major version.  (See also version check in pg_dumpall.c.)
 
575
         */
 
576
        g_fout->minRemoteVersion = 70000;
 
577
        g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
 
578
 
 
579
        /*
 
580
         * Open the database using the Archiver, so it knows about it. Errors mean
 
581
         * death.
 
582
         */
 
583
        g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
 
584
                                                         username, prompt_password);
 
585
 
 
586
        /* Set the client encoding if requested */
 
587
        if (dumpencoding)
 
588
        {
 
589
                if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
 
590
                {
 
591
                        write_msg(NULL, "invalid client encoding \"%s\" specified\n",
 
592
                                          dumpencoding);
 
593
                        exit(1);
 
594
                }
 
595
        }
 
596
 
 
597
        /*
 
598
         * Get the active encoding and the standard_conforming_strings setting, so
 
599
         * we know how to escape strings.
 
600
         */
 
601
        g_fout->encoding = PQclientEncoding(g_conn);
 
602
 
 
603
        std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
 
604
        g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
 
605
 
 
606
        /* Set the role if requested */
 
607
        if (use_role && g_fout->remoteVersion >= 80100)
 
608
        {
 
609
                PQExpBuffer query = createPQExpBuffer();
 
610
 
 
611
                appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
 
612
                do_sql_command(g_conn, query->data);
 
613
                destroyPQExpBuffer(query);
 
614
        }
 
615
 
 
616
        /* Set the datestyle to ISO to ensure the dump's portability */
 
617
        do_sql_command(g_conn, "SET DATESTYLE = ISO");
 
618
 
 
619
        /* Likewise, avoid using sql_standard intervalstyle */
 
620
        if (g_fout->remoteVersion >= 80400)
 
621
                do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
 
622
 
 
623
        /*
 
624
         * If supported, set extra_float_digits so that we can dump float data
 
625
         * exactly (given correctly implemented float I/O code, anyway)
 
626
         */
 
627
        if (g_fout->remoteVersion >= 90000)
 
628
                do_sql_command(g_conn, "SET extra_float_digits TO 3");
 
629
        else if (g_fout->remoteVersion >= 70400)
 
630
                do_sql_command(g_conn, "SET extra_float_digits TO 2");
 
631
 
 
632
        /*
 
633
         * If synchronized scanning is supported, disable it, to prevent
 
634
         * unpredictable changes in row ordering across a dump and reload.
 
635
         */
 
636
        if (g_fout->remoteVersion >= 80300)
 
637
                do_sql_command(g_conn, "SET synchronize_seqscans TO off");
 
638
 
 
639
        /*
 
640
         * Disable timeouts if supported.
 
641
         */
 
642
        if (g_fout->remoteVersion >= 70300)
 
643
                do_sql_command(g_conn, "SET statement_timeout = 0");
 
644
 
 
645
        /*
 
646
         * Quote all identifiers, if requested.
 
647
         */
 
648
        if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
 
649
                do_sql_command(g_conn, "SET quote_all_identifiers = true");
 
650
 
 
651
        /*
 
652
         * Disables security label support if server version < v9.1.x
 
653
         */
 
654
        if (!no_security_label && g_fout->remoteVersion < 90100)
 
655
                no_security_label = 1;
 
656
 
 
657
        /*
 
658
         * Start transaction-snapshot mode transaction to dump consistent data.
 
659
         */
 
660
        do_sql_command(g_conn, "BEGIN");
 
661
        if (g_fout->remoteVersion >= 90100)
 
662
        {
 
663
                if (serializable_deferrable)
 
664
                        do_sql_command(g_conn,
 
665
                                                   "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, "
 
666
                                                   "READ ONLY, DEFERRABLE");
 
667
                else
 
668
                        do_sql_command(g_conn,
 
669
                                                   "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
 
670
        }
 
671
        else
 
672
                do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
 
673
 
 
674
        /* Select the appropriate subquery to convert user IDs to names */
 
675
        if (g_fout->remoteVersion >= 80100)
 
676
                username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
 
677
        else if (g_fout->remoteVersion >= 70300)
 
678
                username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
 
679
        else
 
680
                username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
 
681
 
 
682
        /* Find the last built-in OID, if needed */
 
683
        if (g_fout->remoteVersion < 70300)
 
684
        {
 
685
                if (g_fout->remoteVersion >= 70100)
 
686
                        g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
 
687
                else
 
688
                        g_last_builtin_oid = findLastBuiltinOid_V70();
 
689
                if (g_verbose)
 
690
                        write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
 
691
        }
 
692
 
 
693
        /* Expand schema selection patterns into OID lists */
 
694
        if (schema_include_patterns.head != NULL)
 
695
        {
 
696
                expand_schema_name_patterns(&schema_include_patterns,
 
697
                                                                        &schema_include_oids);
 
698
                if (schema_include_oids.head == NULL)
 
699
                {
 
700
                        write_msg(NULL, "No matching schemas were found\n");
 
701
                        exit_nicely();
 
702
                }
 
703
        }
 
704
        expand_schema_name_patterns(&schema_exclude_patterns,
 
705
                                                                &schema_exclude_oids);
 
706
        /* non-matching exclusion patterns aren't an error */
 
707
 
 
708
        /* Expand table selection patterns into OID lists */
 
709
        if (table_include_patterns.head != NULL)
 
710
        {
 
711
                expand_table_name_patterns(&table_include_patterns,
 
712
                                                                   &table_include_oids);
 
713
                if (table_include_oids.head == NULL)
 
714
                {
 
715
                        write_msg(NULL, "No matching tables were found\n");
 
716
                        exit_nicely();
 
717
                }
 
718
        }
 
719
        expand_table_name_patterns(&table_exclude_patterns,
 
720
                                                           &table_exclude_oids);
 
721
        /* non-matching exclusion patterns aren't an error */
 
722
 
 
723
        /*
 
724
         * Dumping blobs is now default unless we saw an inclusion switch or -s
 
725
         * ... but even if we did see one of these, -b turns it back on.
 
726
         */
 
727
        if (include_everything && !schemaOnly)
 
728
                outputBlobs = true;
 
729
 
 
730
        /*
 
731
         * Now scan the database and create DumpableObject structs for all the
 
732
         * objects we intend to dump.
 
733
         */
 
734
        tblinfo = getSchemaData(&numTables);
 
735
 
 
736
        if (g_fout->remoteVersion < 80400)
 
737
                guessConstraintInheritance(tblinfo, numTables);
 
738
 
 
739
        if (!schemaOnly)
 
740
        {
 
741
                getTableData(tblinfo, numTables, oids);
 
742
                if (dataOnly)
 
743
                        getTableDataFKConstraints();
 
744
        }
 
745
 
 
746
        if (outputBlobs)
 
747
                getBlobs(g_fout);
 
748
 
 
749
        /*
 
750
         * Collect dependency data to assist in ordering the objects.
 
751
         */
 
752
        getDependencies();
 
753
 
 
754
        /*
 
755
         * Sort the objects into a safe dump order (no forward references).
 
756
         *
 
757
         * In 7.3 or later, we can rely on dependency information to help us
 
758
         * determine a safe order, so the initial sort is mostly for cosmetic
 
759
         * purposes: we sort by name to ensure that logically identical schemas
 
760
         * will dump identically.  Before 7.3 we don't have dependencies and we
 
761
         * use OID ordering as an (unreliable) guide to creation order.
 
762
         */
 
763
        getDumpableObjects(&dobjs, &numObjs);
 
764
 
 
765
        if (g_fout->remoteVersion >= 70300)
 
766
                sortDumpableObjectsByTypeName(dobjs, numObjs);
 
767
        else
 
768
                sortDumpableObjectsByTypeOid(dobjs, numObjs);
 
769
 
 
770
        sortDumpableObjects(dobjs, numObjs);
 
771
 
 
772
        /*
 
773
         * Create archive TOC entries for all the objects to be dumped, in a safe
 
774
         * order.
 
775
         */
 
776
 
 
777
        /* First the special ENCODING and STDSTRINGS entries. */
 
778
        dumpEncoding(g_fout);
 
779
        dumpStdStrings(g_fout);
 
780
 
 
781
        /* The database item is always next, unless we don't want it at all */
 
782
        if (include_everything && !dataOnly)
 
783
                dumpDatabase(g_fout);
 
784
 
 
785
        /* Now the rearrangeable objects. */
 
786
        for (i = 0; i < numObjs; i++)
 
787
                dumpDumpableObject(g_fout, dobjs[i]);
 
788
 
 
789
        /*
 
790
         * And finally we can do the actual output.
 
791
         */
 
792
        if (plainText)
 
793
        {
 
794
                ropt = NewRestoreOptions();
 
795
                ropt->filename = (char *) filename;
 
796
                ropt->dropSchema = outputClean;
 
797
                ropt->aclsSkip = aclsSkip;
 
798
                ropt->superuser = outputSuperuser;
 
799
                ropt->createDB = outputCreateDB;
 
800
                ropt->noOwner = outputNoOwner;
 
801
                ropt->noTablespace = outputNoTablespaces;
 
802
                ropt->disable_triggers = disable_triggers;
 
803
                ropt->use_setsessauth = use_setsessauth;
 
804
                ropt->dataOnly = dataOnly;
 
805
 
 
806
                if (compressLevel == -1)
 
807
                        ropt->compression = 0;
 
808
                else
 
809
                        ropt->compression = compressLevel;
 
810
 
 
811
                ropt->suppressDumpWarnings = true;              /* We've already shown them */
 
812
 
 
813
                RestoreArchive(g_fout, ropt);
 
814
        }
 
815
 
 
816
        CloseArchive(g_fout);
 
817
 
 
818
        PQfinish(g_conn);
 
819
 
 
820
        exit(0);
 
821
}
 
822
 
 
823
 
 
824
static void
 
825
help(const char *progname)
 
826
{
 
827
        printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
 
828
        printf(_("Usage:\n"));
 
829
        printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
 
830
 
 
831
        printf(_("\nGeneral options:\n"));
 
832
        printf(_("  -f, --file=OUTPUT           output file or directory name\n"));
 
833
        printf(_("  -F, --format=c|d|t|p        output file format (custom, directory, tar, plain text)\n"));
 
834
        printf(_("  -v, --verbose               verbose mode\n"));
 
835
        printf(_("  -Z, --compress=0-9          compression level for compressed formats\n"));
 
836
        printf(_("  --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
 
837
        printf(_("  --help                      show this help, then exit\n"));
 
838
        printf(_("  --version                   output version information, then exit\n"));
 
839
 
 
840
        printf(_("\nOptions controlling the output content:\n"));
 
841
        printf(_("  -a, --data-only             dump only the data, not the schema\n"));
 
842
        printf(_("  -b, --blobs                 include large objects in dump\n"));
 
843
        printf(_("  -c, --clean                 clean (drop) database objects before recreating\n"));
 
844
        printf(_("  -C, --create                include commands to create database in dump\n"));
 
845
        printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
 
846
        printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
 
847
        printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
 
848
        printf(_("  -o, --oids                  include OIDs in dump\n"));
 
849
        printf(_("  -O, --no-owner              skip restoration of object ownership in\n"
 
850
                         "                              plain-text format\n"));
 
851
        printf(_("  -s, --schema-only           dump only the schema, no data\n"));
 
852
        printf(_("  -S, --superuser=NAME        superuser user name to use in plain-text format\n"));
 
853
        printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
 
854
        printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
 
855
        printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
 
856
        printf(_("  --binary-upgrade            for use by upgrade utilities only\n"));
 
857
        printf(_("  --inserts                   dump data as INSERT commands, rather than COPY\n"));
 
858
        printf(_("  --column-inserts            dump data as INSERT commands with column names\n"));
 
859
        printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
 
860
        printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
 
861
        printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
 
862
        printf(_("  --quote-all-identifiers     quote all identifiers, even if not keywords\n"));
 
863
        printf(_("  --serializable-deferrable   wait until the dump can run without anomalies\n"));
 
864
        printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
 
865
        printf(_("  --no-security-label         do not dump security label assignments\n"));
 
866
        printf(_("  --no-unlogged-table-data    do not dump unlogged table data\n"));
 
867
        printf(_("  --use-set-session-authorization\n"
 
868
                         "                              use SET SESSION AUTHORIZATION commands instead of\n"
 
869
        "                              ALTER OWNER commands to set ownership\n"));
 
870
 
 
871
        printf(_("\nConnection options:\n"));
 
872
        printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
 
873
        printf(_("  -p, --port=PORT          database server port number\n"));
 
874
        printf(_("  -U, --username=NAME      connect as specified database user\n"));
 
875
        printf(_("  -w, --no-password        never prompt for password\n"));
 
876
        printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
 
877
 
 
878
        printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
 
879
                         "variable value is used.\n\n"));
 
880
        printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
 
881
}
 
882
 
 
883
void
 
884
exit_nicely(void)
 
885
{
 
886
        PQfinish(g_conn);
 
887
        if (g_verbose)
 
888
                write_msg(NULL, "*** aborted because of error\n");
 
889
        exit(1);
 
890
}
 
891
 
 
892
static ArchiveFormat
 
893
parseArchiveFormat(const char *format, ArchiveMode *mode)
 
894
{
 
895
        ArchiveFormat archiveFormat;
 
896
 
 
897
        *mode = archModeWrite;
 
898
 
 
899
        if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
 
900
        {
 
901
                /* This is used by pg_dumpall, and is not documented */
 
902
                archiveFormat = archNull;
 
903
                *mode = archModeAppend;
 
904
        }
 
905
        else if (pg_strcasecmp(format, "c") == 0)
 
906
                archiveFormat = archCustom;
 
907
        else if (pg_strcasecmp(format, "custom") == 0)
 
908
                archiveFormat = archCustom;
 
909
        else if (pg_strcasecmp(format, "d") == 0)
 
910
                archiveFormat = archDirectory;
 
911
        else if (pg_strcasecmp(format, "directory") == 0)
 
912
                archiveFormat = archDirectory;
 
913
        else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
 
914
 
 
915
                /*
 
916
                 * Dump files into the current directory; for demonstration only, not
 
917
                 * documented.
 
918
                 */
 
919
                archiveFormat = archFiles;
 
920
        else if (pg_strcasecmp(format, "p") == 0)
 
921
                archiveFormat = archNull;
 
922
        else if (pg_strcasecmp(format, "plain") == 0)
 
923
                archiveFormat = archNull;
 
924
        else if (pg_strcasecmp(format, "t") == 0)
 
925
                archiveFormat = archTar;
 
926
        else if (pg_strcasecmp(format, "tar") == 0)
 
927
                archiveFormat = archTar;
 
928
        else
 
929
        {
 
930
                write_msg(NULL, "invalid output format \"%s\" specified\n", format);
 
931
                exit(1);
 
932
        }
 
933
        return archiveFormat;
 
934
}
 
935
 
 
936
/*
 
937
 * Find the OIDs of all schemas matching the given list of patterns,
 
938
 * and append them to the given OID list.
 
939
 */
 
940
static void
 
941
expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
 
942
{
 
943
        PQExpBuffer query;
 
944
        PGresult   *res;
 
945
        SimpleStringListCell *cell;
 
946
        int                     i;
 
947
 
 
948
        if (patterns->head == NULL)
 
949
                return;                                 /* nothing to do */
 
950
 
 
951
        if (g_fout->remoteVersion < 70300)
 
952
        {
 
953
                write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
 
954
                exit_nicely();
 
955
        }
 
956
 
 
957
        query = createPQExpBuffer();
 
958
 
 
959
        /*
 
960
         * We use UNION ALL rather than UNION; this might sometimes result in
 
961
         * duplicate entries in the OID list, but we don't care.
 
962
         */
 
963
 
 
964
        for (cell = patterns->head; cell; cell = cell->next)
 
965
        {
 
966
                if (cell != patterns->head)
 
967
                        appendPQExpBuffer(query, "UNION ALL\n");
 
968
                appendPQExpBuffer(query,
 
969
                                                  "SELECT oid FROM pg_catalog.pg_namespace n\n");
 
970
                processSQLNamePattern(g_conn, query, cell->val, false, false,
 
971
                                                          NULL, "n.nspname", NULL,
 
972
                                                          NULL);
 
973
        }
 
974
 
 
975
        res = PQexec(g_conn, query->data);
 
976
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
977
 
 
978
        for (i = 0; i < PQntuples(res); i++)
 
979
        {
 
980
                simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
 
981
        }
 
982
 
 
983
        PQclear(res);
 
984
        destroyPQExpBuffer(query);
 
985
}
 
986
 
 
987
/*
 
988
 * Find the OIDs of all tables matching the given list of patterns,
 
989
 * and append them to the given OID list.
 
990
 */
 
991
static void
 
992
expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
 
993
{
 
994
        PQExpBuffer query;
 
995
        PGresult   *res;
 
996
        SimpleStringListCell *cell;
 
997
        int                     i;
 
998
 
 
999
        if (patterns->head == NULL)
 
1000
                return;                                 /* nothing to do */
 
1001
 
 
1002
        query = createPQExpBuffer();
 
1003
 
 
1004
        /*
 
1005
         * We use UNION ALL rather than UNION; this might sometimes result in
 
1006
         * duplicate entries in the OID list, but we don't care.
 
1007
         */
 
1008
 
 
1009
        for (cell = patterns->head; cell; cell = cell->next)
 
1010
        {
 
1011
                if (cell != patterns->head)
 
1012
                        appendPQExpBuffer(query, "UNION ALL\n");
 
1013
                appendPQExpBuffer(query,
 
1014
                                                  "SELECT c.oid"
 
1015
                                                  "\nFROM pg_catalog.pg_class c"
 
1016
                "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
 
1017
                                                  "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n",
 
1018
                                                  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
 
1019
                                                  RELKIND_FOREIGN_TABLE);
 
1020
                processSQLNamePattern(g_conn, query, cell->val, true, false,
 
1021
                                                          "n.nspname", "c.relname", NULL,
 
1022
                                                          "pg_catalog.pg_table_is_visible(c.oid)");
 
1023
        }
 
1024
 
 
1025
        res = PQexec(g_conn, query->data);
 
1026
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
1027
 
 
1028
        for (i = 0; i < PQntuples(res); i++)
 
1029
        {
 
1030
                simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
 
1031
        }
 
1032
 
 
1033
        PQclear(res);
 
1034
        destroyPQExpBuffer(query);
 
1035
}
 
1036
 
 
1037
/*
 
1038
 * selectDumpableNamespace: policy-setting subroutine
 
1039
 *              Mark a namespace as to be dumped or not
 
1040
 */
 
1041
static void
 
1042
selectDumpableNamespace(NamespaceInfo *nsinfo)
 
1043
{
 
1044
        /*
 
1045
         * If specific tables are being dumped, do not dump any complete
 
1046
         * namespaces. If specific namespaces are being dumped, dump just those
 
1047
         * namespaces. Otherwise, dump all non-system namespaces.
 
1048
         */
 
1049
        if (table_include_oids.head != NULL)
 
1050
                nsinfo->dobj.dump = false;
 
1051
        else if (schema_include_oids.head != NULL)
 
1052
                nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
 
1053
                                                                                                   nsinfo->dobj.catId.oid);
 
1054
        else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
 
1055
                         strcmp(nsinfo->dobj.name, "information_schema") == 0)
 
1056
                nsinfo->dobj.dump = false;
 
1057
        else
 
1058
                nsinfo->dobj.dump = true;
 
1059
 
 
1060
        /*
 
1061
         * In any case, a namespace can be excluded by an exclusion switch
 
1062
         */
 
1063
        if (nsinfo->dobj.dump &&
 
1064
                simple_oid_list_member(&schema_exclude_oids,
 
1065
                                                           nsinfo->dobj.catId.oid))
 
1066
                nsinfo->dobj.dump = false;
 
1067
}
 
1068
 
 
1069
/*
 
1070
 * selectDumpableTable: policy-setting subroutine
 
1071
 *              Mark a table as to be dumped or not
 
1072
 */
 
1073
static void
 
1074
selectDumpableTable(TableInfo *tbinfo)
 
1075
{
 
1076
        /*
 
1077
         * If specific tables are being dumped, dump just those tables; else, dump
 
1078
         * according to the parent namespace's dump flag.
 
1079
         */
 
1080
        if (table_include_oids.head != NULL)
 
1081
                tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
 
1082
                                                                                                   tbinfo->dobj.catId.oid);
 
1083
        else
 
1084
                tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
 
1085
 
 
1086
        /*
 
1087
         * In any case, a table can be excluded by an exclusion switch
 
1088
         */
 
1089
        if (tbinfo->dobj.dump &&
 
1090
                simple_oid_list_member(&table_exclude_oids,
 
1091
                                                           tbinfo->dobj.catId.oid))
 
1092
                tbinfo->dobj.dump = false;
 
1093
}
 
1094
 
 
1095
/*
 
1096
 * selectDumpableType: policy-setting subroutine
 
1097
 *              Mark a type as to be dumped or not
 
1098
 *
 
1099
 * If it's a table's rowtype or an autogenerated array type, we also apply a
 
1100
 * special type code to facilitate sorting into the desired order.      (We don't
 
1101
 * want to consider those to be ordinary types because that would bring tables
 
1102
 * up into the datatype part of the dump order.)  Those tests should be made
 
1103
 * first to ensure the objType change is applied regardless of namespace etc.
 
1104
 */
 
1105
static void
 
1106
selectDumpableType(TypeInfo *tyinfo)
 
1107
{
 
1108
        /* skip complex types, except for standalone composite types */
 
1109
        if (OidIsValid(tyinfo->typrelid) &&
 
1110
                tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
 
1111
        {
 
1112
                tyinfo->dobj.dump = false;
 
1113
                tyinfo->dobj.objType = DO_DUMMY_TYPE;
 
1114
        }
 
1115
 
 
1116
        /* skip auto-generated array types */
 
1117
        else if (tyinfo->isArray)
 
1118
        {
 
1119
                tyinfo->dobj.dump = false;
 
1120
                tyinfo->dobj.objType = DO_DUMMY_TYPE;
 
1121
        }
 
1122
 
 
1123
        /* dump only types in dumpable namespaces */
 
1124
        else if (!tyinfo->dobj.namespace->dobj.dump)
 
1125
                tyinfo->dobj.dump = false;
 
1126
 
 
1127
        /* skip undefined placeholder types */
 
1128
        else if (!tyinfo->isDefined)
 
1129
                tyinfo->dobj.dump = false;
 
1130
 
 
1131
        else
 
1132
                tyinfo->dobj.dump = true;
 
1133
}
 
1134
 
 
1135
/*
 
1136
 * selectDumpableDefaultACL: policy-setting subroutine
 
1137
 *              Mark a default ACL as to be dumped or not
 
1138
 *
 
1139
 * For per-schema default ACLs, dump if the schema is to be dumped.
 
1140
 * Otherwise dump if we are dumping "everything".  Note that dataOnly
 
1141
 * and aclsSkip are checked separately.
 
1142
 */
 
1143
static void
 
1144
selectDumpableDefaultACL(DefaultACLInfo *dinfo)
 
1145
{
 
1146
        if (dinfo->dobj.namespace)
 
1147
                dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
 
1148
        else
 
1149
                dinfo->dobj.dump = include_everything;
 
1150
}
 
1151
 
 
1152
/*
 
1153
 * selectDumpableExtension: policy-setting subroutine
 
1154
 *              Mark an extension as to be dumped or not
 
1155
 *
 
1156
 * Normally, we just dump all extensions.  However, in binary-upgrade mode
 
1157
 * it's necessary to skip built-in extensions, since we assume those will
 
1158
 * already be installed in the target database.  We identify such extensions
 
1159
 * by their having OIDs in the range reserved for initdb.
 
1160
 */
 
1161
static void
 
1162
selectDumpableExtension(ExtensionInfo *extinfo)
 
1163
{
 
1164
        if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
 
1165
                extinfo->dobj.dump = false;
 
1166
        else
 
1167
                extinfo->dobj.dump = true;
 
1168
}
 
1169
 
 
1170
/*
 
1171
 * selectDumpableObject: policy-setting subroutine
 
1172
 *              Mark a generic dumpable object as to be dumped or not
 
1173
 *
 
1174
 * Use this only for object types without a special-case routine above.
 
1175
 */
 
1176
static void
 
1177
selectDumpableObject(DumpableObject *dobj)
 
1178
{
 
1179
        /*
 
1180
         * Default policy is to dump if parent namespace is dumpable, or always
 
1181
         * for non-namespace-associated items.
 
1182
         */
 
1183
        if (dobj->namespace)
 
1184
                dobj->dump = dobj->namespace->dobj.dump;
 
1185
        else
 
1186
                dobj->dump = true;
 
1187
}
 
1188
 
 
1189
/*
 
1190
 *      Dump a table's contents for loading using the COPY command
 
1191
 *      - this routine is called by the Archiver when it wants the table
 
1192
 *        to be dumped.
 
1193
 */
 
1194
 
 
1195
static int
 
1196
dumpTableData_copy(Archive *fout, void *dcontext)
 
1197
{
 
1198
        TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
 
1199
        TableInfo  *tbinfo = tdinfo->tdtable;
 
1200
        const char *classname = tbinfo->dobj.name;
 
1201
        const bool      hasoids = tbinfo->hasoids;
 
1202
        const bool      oids = tdinfo->oids;
 
1203
        PQExpBuffer q = createPQExpBuffer();
 
1204
        PGresult   *res;
 
1205
        int                     ret;
 
1206
        char       *copybuf;
 
1207
        const char *column_list;
 
1208
 
 
1209
        if (g_verbose)
 
1210
                write_msg(NULL, "dumping contents of table %s\n", classname);
 
1211
 
 
1212
        /*
 
1213
         * Make sure we are in proper schema.  We will qualify the table name
 
1214
         * below anyway (in case its name conflicts with a pg_catalog table); but
 
1215
         * this ensures reproducible results in case the table contains regproc,
 
1216
         * regclass, etc columns.
 
1217
         */
 
1218
        selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
1219
 
 
1220
        /*
 
1221
         * If possible, specify the column list explicitly so that we have no
 
1222
         * possibility of retrieving data in the wrong column order.  (The default
 
1223
         * column ordering of COPY will not be what we want in certain corner
 
1224
         * cases involving ADD COLUMN and inheritance.)
 
1225
         */
 
1226
        if (g_fout->remoteVersion >= 70300)
 
1227
                column_list = fmtCopyColumnList(tbinfo);
 
1228
        else
 
1229
                column_list = "";               /* can't select columns in COPY */
 
1230
 
 
1231
        if (oids && hasoids)
 
1232
        {
 
1233
                appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
 
1234
                                                  fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
 
1235
                                                                                 classname),
 
1236
                                                  column_list);
 
1237
        }
 
1238
        else if (tdinfo->filtercond)
 
1239
        {
 
1240
                /* Note: this syntax is only supported in 8.2 and up */
 
1241
                appendPQExpBufferStr(q, "COPY (SELECT ");
 
1242
                /* klugery to get rid of parens in column list */
 
1243
                if (strlen(column_list) > 2)
 
1244
                {
 
1245
                        appendPQExpBufferStr(q, column_list + 1);
 
1246
                        q->data[q->len - 1] = ' ';
 
1247
                }
 
1248
                else
 
1249
                        appendPQExpBufferStr(q, "* ");
 
1250
                appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
 
1251
                                                  fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
 
1252
                                                                                 classname),
 
1253
                                                  tdinfo->filtercond);
 
1254
        }
 
1255
        else
 
1256
        {
 
1257
                appendPQExpBuffer(q, "COPY %s %s TO stdout;",
 
1258
                                                  fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
 
1259
                                                                                 classname),
 
1260
                                                  column_list);
 
1261
        }
 
1262
        res = PQexec(g_conn, q->data);
 
1263
        check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
 
1264
        PQclear(res);
 
1265
 
 
1266
        for (;;)
 
1267
        {
 
1268
                ret = PQgetCopyData(g_conn, &copybuf, 0);
 
1269
 
 
1270
                if (ret < 0)
 
1271
                        break;                          /* done or error */
 
1272
 
 
1273
                if (copybuf)
 
1274
                {
 
1275
                        WriteData(fout, copybuf, ret);
 
1276
                        PQfreemem(copybuf);
 
1277
                }
 
1278
 
 
1279
                /* ----------
 
1280
                 * THROTTLE:
 
1281
                 *
 
1282
                 * There was considerable discussion in late July, 2000 regarding
 
1283
                 * slowing down pg_dump when backing up large tables. Users with both
 
1284
                 * slow & fast (multi-processor) machines experienced performance
 
1285
                 * degradation when doing a backup.
 
1286
                 *
 
1287
                 * Initial attempts based on sleeping for a number of ms for each ms
 
1288
                 * of work were deemed too complex, then a simple 'sleep in each loop'
 
1289
                 * implementation was suggested. The latter failed because the loop
 
1290
                 * was too tight. Finally, the following was implemented:
 
1291
                 *
 
1292
                 * If throttle is non-zero, then
 
1293
                 *              See how long since the last sleep.
 
1294
                 *              Work out how long to sleep (based on ratio).
 
1295
                 *              If sleep is more than 100ms, then
 
1296
                 *                      sleep
 
1297
                 *                      reset timer
 
1298
                 *              EndIf
 
1299
                 * EndIf
 
1300
                 *
 
1301
                 * where the throttle value was the number of ms to sleep per ms of
 
1302
                 * work. The calculation was done in each loop.
 
1303
                 *
 
1304
                 * Most of the hard work is done in the backend, and this solution
 
1305
                 * still did not work particularly well: on slow machines, the ratio
 
1306
                 * was 50:1, and on medium paced machines, 1:1, and on fast
 
1307
                 * multi-processor machines, it had little or no effect, for reasons
 
1308
                 * that were unclear.
 
1309
                 *
 
1310
                 * Further discussion ensued, and the proposal was dropped.
 
1311
                 *
 
1312
                 * For those people who want this feature, it can be implemented using
 
1313
                 * gettimeofday in each loop, calculating the time since last sleep,
 
1314
                 * multiplying that by the sleep ratio, then if the result is more
 
1315
                 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
 
1316
                 * function to sleep for a subsecond period ie.
 
1317
                 *
 
1318
                 * select(0, NULL, NULL, NULL, &tvi);
 
1319
                 *
 
1320
                 * This will return after the interval specified in the structure tvi.
 
1321
                 * Finally, call gettimeofday again to save the 'last sleep time'.
 
1322
                 * ----------
 
1323
                 */
 
1324
        }
 
1325
        archprintf(fout, "\\.\n\n\n");
 
1326
 
 
1327
        if (ret == -2)
 
1328
        {
 
1329
                /* copy data transfer failed */
 
1330
                write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
 
1331
                write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
 
1332
                write_msg(NULL, "The command was: %s\n", q->data);
 
1333
                exit_nicely();
 
1334
        }
 
1335
 
 
1336
        /* Check command status and return to normal libpq state */
 
1337
        res = PQgetResult(g_conn);
 
1338
        check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
 
1339
        PQclear(res);
 
1340
 
 
1341
        destroyPQExpBuffer(q);
 
1342
        return 1;
 
1343
}
 
1344
 
 
1345
static int
 
1346
dumpTableData_insert(Archive *fout, void *dcontext)
 
1347
{
 
1348
        TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
 
1349
        TableInfo  *tbinfo = tdinfo->tdtable;
 
1350
        const char *classname = tbinfo->dobj.name;
 
1351
        PQExpBuffer q = createPQExpBuffer();
 
1352
        PGresult   *res;
 
1353
        int                     tuple;
 
1354
        int                     nfields;
 
1355
        int                     field;
 
1356
 
 
1357
        /*
 
1358
         * Make sure we are in proper schema.  We will qualify the table name
 
1359
         * below anyway (in case its name conflicts with a pg_catalog table); but
 
1360
         * this ensures reproducible results in case the table contains regproc,
 
1361
         * regclass, etc columns.
 
1362
         */
 
1363
        selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
1364
 
 
1365
        if (fout->remoteVersion >= 70100)
 
1366
        {
 
1367
                appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
 
1368
                                                  "SELECT * FROM ONLY %s",
 
1369
                                                  fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
 
1370
                                                                                 classname));
 
1371
        }
 
1372
        else
 
1373
        {
 
1374
                appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
 
1375
                                                  "SELECT * FROM %s",
 
1376
                                                  fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
 
1377
                                                                                 classname));
 
1378
        }
 
1379
        if (tdinfo->filtercond)
 
1380
                appendPQExpBuffer(q, " %s", tdinfo->filtercond);
 
1381
 
 
1382
        res = PQexec(g_conn, q->data);
 
1383
        check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
 
1384
 
 
1385
        do
 
1386
        {
 
1387
                PQclear(res);
 
1388
 
 
1389
                res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
 
1390
                check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
 
1391
                                                 PGRES_TUPLES_OK);
 
1392
                nfields = PQnfields(res);
 
1393
                for (tuple = 0; tuple < PQntuples(res); tuple++)
 
1394
                {
 
1395
                        archprintf(fout, "INSERT INTO %s ", fmtId(classname));
 
1396
                        if (nfields == 0)
 
1397
                        {
 
1398
                                /* corner case for zero-column table */
 
1399
                                archprintf(fout, "DEFAULT VALUES;\n");
 
1400
                                continue;
 
1401
                        }
 
1402
                        if (column_inserts)
 
1403
                        {
 
1404
                                resetPQExpBuffer(q);
 
1405
                                appendPQExpBuffer(q, "(");
 
1406
                                for (field = 0; field < nfields; field++)
 
1407
                                {
 
1408
                                        if (field > 0)
 
1409
                                                appendPQExpBuffer(q, ", ");
 
1410
                                        appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
 
1411
                                }
 
1412
                                appendPQExpBuffer(q, ") ");
 
1413
                                archputs(q->data, fout);
 
1414
                        }
 
1415
                        archprintf(fout, "VALUES (");
 
1416
                        for (field = 0; field < nfields; field++)
 
1417
                        {
 
1418
                                if (field > 0)
 
1419
                                        archprintf(fout, ", ");
 
1420
                                if (PQgetisnull(res, tuple, field))
 
1421
                                {
 
1422
                                        archprintf(fout, "NULL");
 
1423
                                        continue;
 
1424
                                }
 
1425
 
 
1426
                                /* XXX This code is partially duplicated in ruleutils.c */
 
1427
                                switch (PQftype(res, field))
 
1428
                                {
 
1429
                                        case INT2OID:
 
1430
                                        case INT4OID:
 
1431
                                        case INT8OID:
 
1432
                                        case OIDOID:
 
1433
                                        case FLOAT4OID:
 
1434
                                        case FLOAT8OID:
 
1435
                                        case NUMERICOID:
 
1436
                                                {
 
1437
                                                        /*
 
1438
                                                         * These types are printed without quotes unless
 
1439
                                                         * they contain values that aren't accepted by the
 
1440
                                                         * scanner unquoted (e.g., 'NaN').      Note that
 
1441
                                                         * strtod() and friends might accept NaN, so we
 
1442
                                                         * can't use that to test.
 
1443
                                                         *
 
1444
                                                         * In reality we only need to defend against
 
1445
                                                         * infinity and NaN, so we need not get too crazy
 
1446
                                                         * about pattern matching here.
 
1447
                                                         */
 
1448
                                                        const char *s = PQgetvalue(res, tuple, field);
 
1449
 
 
1450
                                                        if (strspn(s, "0123456789 +-eE.") == strlen(s))
 
1451
                                                                archprintf(fout, "%s", s);
 
1452
                                                        else
 
1453
                                                                archprintf(fout, "'%s'", s);
 
1454
                                                }
 
1455
                                                break;
 
1456
 
 
1457
                                        case BITOID:
 
1458
                                        case VARBITOID:
 
1459
                                                archprintf(fout, "B'%s'",
 
1460
                                                                   PQgetvalue(res, tuple, field));
 
1461
                                                break;
 
1462
 
 
1463
                                        case BOOLOID:
 
1464
                                                if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
 
1465
                                                        archprintf(fout, "true");
 
1466
                                                else
 
1467
                                                        archprintf(fout, "false");
 
1468
                                                break;
 
1469
 
 
1470
                                        default:
 
1471
                                                /* All other types are printed as string literals. */
 
1472
                                                resetPQExpBuffer(q);
 
1473
                                                appendStringLiteralAH(q,
 
1474
                                                                                          PQgetvalue(res, tuple, field),
 
1475
                                                                                          fout);
 
1476
                                                archputs(q->data, fout);
 
1477
                                                break;
 
1478
                                }
 
1479
                        }
 
1480
                        archprintf(fout, ");\n");
 
1481
                }
 
1482
        } while (PQntuples(res) > 0);
 
1483
 
 
1484
        PQclear(res);
 
1485
 
 
1486
        archprintf(fout, "\n\n");
 
1487
 
 
1488
        do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
 
1489
 
 
1490
        destroyPQExpBuffer(q);
 
1491
        return 1;
 
1492
}
 
1493
 
 
1494
 
 
1495
/*
 
1496
 * dumpTableData -
 
1497
 *        dump the contents of a single table
 
1498
 *
 
1499
 * Actually, this just makes an ArchiveEntry for the table contents.
 
1500
 */
 
1501
static void
 
1502
dumpTableData(Archive *fout, TableDataInfo *tdinfo)
 
1503
{
 
1504
        TableInfo  *tbinfo = tdinfo->tdtable;
 
1505
        PQExpBuffer copyBuf = createPQExpBuffer();
 
1506
        DataDumperPtr dumpFn;
 
1507
        char       *copyStmt;
 
1508
 
 
1509
        if (!dump_inserts)
 
1510
        {
 
1511
                /* Dump/restore using COPY */
 
1512
                dumpFn = dumpTableData_copy;
 
1513
                /* must use 2 steps here 'cause fmtId is nonreentrant */
 
1514
                appendPQExpBuffer(copyBuf, "COPY %s ",
 
1515
                                                  fmtId(tbinfo->dobj.name));
 
1516
                appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
 
1517
                                                  fmtCopyColumnList(tbinfo),
 
1518
                                          (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
 
1519
                copyStmt = copyBuf->data;
 
1520
        }
 
1521
        else
 
1522
        {
 
1523
                /* Restore using INSERT */
 
1524
                dumpFn = dumpTableData_insert;
 
1525
                copyStmt = NULL;
 
1526
        }
 
1527
 
 
1528
        ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
 
1529
                                 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
 
1530
                                 NULL, tbinfo->rolname,
 
1531
                                 false, "TABLE DATA", SECTION_DATA,
 
1532
                                 "", "", copyStmt,
 
1533
                                 tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
 
1534
                                 dumpFn, tdinfo);
 
1535
 
 
1536
        destroyPQExpBuffer(copyBuf);
 
1537
}
 
1538
 
 
1539
/*
 
1540
 * getTableData -
 
1541
 *        set up dumpable objects representing the contents of tables
 
1542
 */
 
1543
static void
 
1544
getTableData(TableInfo *tblinfo, int numTables, bool oids)
 
1545
{
 
1546
        int                     i;
 
1547
 
 
1548
        for (i = 0; i < numTables; i++)
 
1549
        {
 
1550
                /* Skip VIEWs (no data to dump) */
 
1551
                if (tblinfo[i].relkind == RELKIND_VIEW)
 
1552
                        continue;
 
1553
                /* Skip SEQUENCEs (handled elsewhere) */
 
1554
                if (tblinfo[i].relkind == RELKIND_SEQUENCE)
 
1555
                        continue;
 
1556
                /* Skip FOREIGN TABLEs (no data to dump) */
 
1557
                if (tblinfo[i].relkind == RELKIND_FOREIGN_TABLE)
 
1558
                        continue;
 
1559
                /* Skip unlogged tables if so requested */
 
1560
                if (tblinfo[i].relpersistence == RELPERSISTENCE_UNLOGGED
 
1561
                        && no_unlogged_table_data)
 
1562
                        continue;
 
1563
 
 
1564
                if (tblinfo[i].dobj.dump && tblinfo[i].dataObj == NULL)
 
1565
                        makeTableDataInfo(&(tblinfo[i]), oids);
 
1566
        }
 
1567
}
 
1568
 
 
1569
/*
 
1570
 * Make a dumpable object for the data of this specific table
 
1571
 */
 
1572
static void
 
1573
makeTableDataInfo(TableInfo *tbinfo, bool oids)
 
1574
{
 
1575
        TableDataInfo *tdinfo;
 
1576
 
 
1577
        tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
 
1578
 
 
1579
        tdinfo->dobj.objType = DO_TABLE_DATA;
 
1580
 
 
1581
        /*
 
1582
         * Note: use tableoid 0 so that this object won't be mistaken for
 
1583
         * something that pg_depend entries apply to.
 
1584
         */
 
1585
        tdinfo->dobj.catId.tableoid = 0;
 
1586
        tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
 
1587
        AssignDumpId(&tdinfo->dobj);
 
1588
        tdinfo->dobj.name = tbinfo->dobj.name;
 
1589
        tdinfo->dobj.namespace = tbinfo->dobj.namespace;
 
1590
        tdinfo->tdtable = tbinfo;
 
1591
        tdinfo->oids = oids;
 
1592
        tdinfo->filtercond = NULL;      /* might get set later */
 
1593
        addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
 
1594
 
 
1595
        tbinfo->dataObj = tdinfo;
 
1596
}
 
1597
 
 
1598
/*
 
1599
 * getTableDataFKConstraints -
 
1600
 *        add dump-order dependencies reflecting foreign key constraints
 
1601
 *
 
1602
 * This code is executed only in a data-only dump --- in schema+data dumps
 
1603
 * we handle foreign key issues by not creating the FK constraints until
 
1604
 * after the data is loaded.  In a data-only dump, however, we want to
 
1605
 * order the table data objects in such a way that a table's referenced
 
1606
 * tables are restored first.  (In the presence of circular references or
 
1607
 * self-references this may be impossible; we'll detect and complain about
 
1608
 * that during the dependency sorting step.)
 
1609
 */
 
1610
static void
 
1611
getTableDataFKConstraints(void)
 
1612
{
 
1613
        DumpableObject **dobjs;
 
1614
        int                     numObjs;
 
1615
        int                     i;
 
1616
 
 
1617
        /* Search through all the dumpable objects for FK constraints */
 
1618
        getDumpableObjects(&dobjs, &numObjs);
 
1619
        for (i = 0; i < numObjs; i++)
 
1620
        {
 
1621
                if (dobjs[i]->objType == DO_FK_CONSTRAINT)
 
1622
                {
 
1623
                        ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
 
1624
                        TableInfo  *ftable;
 
1625
 
 
1626
                        /* Not interesting unless both tables are to be dumped */
 
1627
                        if (cinfo->contable == NULL ||
 
1628
                                cinfo->contable->dataObj == NULL)
 
1629
                                continue;
 
1630
                        ftable = findTableByOid(cinfo->confrelid);
 
1631
                        if (ftable == NULL ||
 
1632
                                ftable->dataObj == NULL)
 
1633
                                continue;
 
1634
 
 
1635
                        /*
 
1636
                         * Okay, make referencing table's TABLE_DATA object depend on the
 
1637
                         * referenced table's TABLE_DATA object.
 
1638
                         */
 
1639
                        addObjectDependency(&cinfo->contable->dataObj->dobj,
 
1640
                                                                ftable->dataObj->dobj.dumpId);
 
1641
                }
 
1642
        }
 
1643
        free(dobjs);
 
1644
}
 
1645
 
 
1646
 
 
1647
/*
 
1648
 * guessConstraintInheritance:
 
1649
 *      In pre-8.4 databases, we can't tell for certain which constraints
 
1650
 *      are inherited.  We assume a CHECK constraint is inherited if its name
 
1651
 *      matches the name of any constraint in the parent.  Originally this code
 
1652
 *      tried to compare the expression texts, but that can fail for various
 
1653
 *      reasons --- for example, if the parent and child tables are in different
 
1654
 *      schemas, reverse-listing of function calls may produce different text
 
1655
 *      (schema-qualified or not) depending on search path.
 
1656
 *
 
1657
 *      In 8.4 and up we can rely on the conislocal field to decide which
 
1658
 *      constraints must be dumped; much safer.
 
1659
 *
 
1660
 *      This function assumes all conislocal flags were initialized to TRUE.
 
1661
 *      It clears the flag on anything that seems to be inherited.
 
1662
 */
 
1663
static void
 
1664
guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 
1665
{
 
1666
        int                     i,
 
1667
                                j,
 
1668
                                k;
 
1669
 
 
1670
        for (i = 0; i < numTables; i++)
 
1671
        {
 
1672
                TableInfo  *tbinfo = &(tblinfo[i]);
 
1673
                int                     numParents;
 
1674
                TableInfo **parents;
 
1675
                TableInfo  *parent;
 
1676
 
 
1677
                /* Sequences and views never have parents */
 
1678
                if (tbinfo->relkind == RELKIND_SEQUENCE ||
 
1679
                        tbinfo->relkind == RELKIND_VIEW)
 
1680
                        continue;
 
1681
 
 
1682
                /* Don't bother computing anything for non-target tables, either */
 
1683
                if (!tbinfo->dobj.dump)
 
1684
                        continue;
 
1685
 
 
1686
                numParents = tbinfo->numParents;
 
1687
                parents = tbinfo->parents;
 
1688
 
 
1689
                if (numParents == 0)
 
1690
                        continue;                       /* nothing to see here, move along */
 
1691
 
 
1692
                /* scan for inherited CHECK constraints */
 
1693
                for (j = 0; j < tbinfo->ncheck; j++)
 
1694
                {
 
1695
                        ConstraintInfo *constr;
 
1696
 
 
1697
                        constr = &(tbinfo->checkexprs[j]);
 
1698
 
 
1699
                        for (k = 0; k < numParents; k++)
 
1700
                        {
 
1701
                                int                     l;
 
1702
 
 
1703
                                parent = parents[k];
 
1704
                                for (l = 0; l < parent->ncheck; l++)
 
1705
                                {
 
1706
                                        ConstraintInfo *pconstr = &(parent->checkexprs[l]);
 
1707
 
 
1708
                                        if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
 
1709
                                        {
 
1710
                                                constr->conislocal = false;
 
1711
                                                break;
 
1712
                                        }
 
1713
                                }
 
1714
                                if (!constr->conislocal)
 
1715
                                        break;
 
1716
                        }
 
1717
                }
 
1718
        }
 
1719
}
 
1720
 
 
1721
 
 
1722
/*
 
1723
 * dumpDatabase:
 
1724
 *      dump the database definition
 
1725
 */
 
1726
static void
 
1727
dumpDatabase(Archive *AH)
 
1728
{
 
1729
        PQExpBuffer dbQry = createPQExpBuffer();
 
1730
        PQExpBuffer delQry = createPQExpBuffer();
 
1731
        PQExpBuffer creaQry = createPQExpBuffer();
 
1732
        PGresult   *res;
 
1733
        int                     ntups;
 
1734
        int                     i_tableoid,
 
1735
                                i_oid,
 
1736
                                i_dba,
 
1737
                                i_encoding,
 
1738
                                i_collate,
 
1739
                                i_ctype,
 
1740
                                i_frozenxid,
 
1741
                                i_tablespace;
 
1742
        CatalogId       dbCatId;
 
1743
        DumpId          dbDumpId;
 
1744
        const char *datname,
 
1745
                           *dba,
 
1746
                           *encoding,
 
1747
                           *collate,
 
1748
                           *ctype,
 
1749
                           *tablespace;
 
1750
        uint32          frozenxid;
 
1751
 
 
1752
        datname = PQdb(g_conn);
 
1753
 
 
1754
        if (g_verbose)
 
1755
                write_msg(NULL, "saving database definition\n");
 
1756
 
 
1757
        /* Make sure we are in proper schema */
 
1758
        selectSourceSchema("pg_catalog");
 
1759
 
 
1760
        /* Get the database owner and parameters from pg_database */
 
1761
        if (g_fout->remoteVersion >= 80400)
 
1762
        {
 
1763
                appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
 
1764
                                                  "(%s datdba) AS dba, "
 
1765
                                                  "pg_encoding_to_char(encoding) AS encoding, "
 
1766
                                                  "datcollate, datctype, datfrozenxid, "
 
1767
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
 
1768
                                          "shobj_description(oid, 'pg_database') AS description "
 
1769
 
 
1770
                                                  "FROM pg_database "
 
1771
                                                  "WHERE datname = ",
 
1772
                                                  username_subquery);
 
1773
                appendStringLiteralAH(dbQry, datname, AH);
 
1774
        }
 
1775
        else if (g_fout->remoteVersion >= 80200)
 
1776
        {
 
1777
                appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
 
1778
                                                  "(%s datdba) AS dba, "
 
1779
                                                  "pg_encoding_to_char(encoding) AS encoding, "
 
1780
                                           "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
 
1781
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
 
1782
                                          "shobj_description(oid, 'pg_database') AS description "
 
1783
 
 
1784
                                                  "FROM pg_database "
 
1785
                                                  "WHERE datname = ",
 
1786
                                                  username_subquery);
 
1787
                appendStringLiteralAH(dbQry, datname, AH);
 
1788
        }
 
1789
        else if (g_fout->remoteVersion >= 80000)
 
1790
        {
 
1791
                appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
 
1792
                                                  "(%s datdba) AS dba, "
 
1793
                                                  "pg_encoding_to_char(encoding) AS encoding, "
 
1794
                                           "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
 
1795
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
 
1796
                                                  "FROM pg_database "
 
1797
                                                  "WHERE datname = ",
 
1798
                                                  username_subquery);
 
1799
                appendStringLiteralAH(dbQry, datname, AH);
 
1800
        }
 
1801
        else if (g_fout->remoteVersion >= 70100)
 
1802
        {
 
1803
                appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
 
1804
                                                  "(%s datdba) AS dba, "
 
1805
                                                  "pg_encoding_to_char(encoding) AS encoding, "
 
1806
                                                  "NULL AS datcollate, NULL AS datctype, "
 
1807
                                                  "0 AS datfrozenxid, "
 
1808
                                                  "NULL AS tablespace "
 
1809
                                                  "FROM pg_database "
 
1810
                                                  "WHERE datname = ",
 
1811
                                                  username_subquery);
 
1812
                appendStringLiteralAH(dbQry, datname, AH);
 
1813
        }
 
1814
        else
 
1815
        {
 
1816
                appendPQExpBuffer(dbQry, "SELECT "
 
1817
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
 
1818
                                                  "oid, "
 
1819
                                                  "(%s datdba) AS dba, "
 
1820
                                                  "pg_encoding_to_char(encoding) AS encoding, "
 
1821
                                                  "NULL AS datcollate, NULL AS datctype, "
 
1822
                                                  "0 AS datfrozenxid, "
 
1823
                                                  "NULL AS tablespace "
 
1824
                                                  "FROM pg_database "
 
1825
                                                  "WHERE datname = ",
 
1826
                                                  username_subquery);
 
1827
                appendStringLiteralAH(dbQry, datname, AH);
 
1828
        }
 
1829
 
 
1830
        res = PQexec(g_conn, dbQry->data);
 
1831
        check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
 
1832
 
 
1833
        ntups = PQntuples(res);
 
1834
 
 
1835
        if (ntups <= 0)
 
1836
        {
 
1837
                write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
 
1838
                                  datname);
 
1839
                exit_nicely();
 
1840
        }
 
1841
 
 
1842
        if (ntups != 1)
 
1843
        {
 
1844
                write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
 
1845
                                  ntups, datname);
 
1846
                exit_nicely();
 
1847
        }
 
1848
 
 
1849
        i_tableoid = PQfnumber(res, "tableoid");
 
1850
        i_oid = PQfnumber(res, "oid");
 
1851
        i_dba = PQfnumber(res, "dba");
 
1852
        i_encoding = PQfnumber(res, "encoding");
 
1853
        i_collate = PQfnumber(res, "datcollate");
 
1854
        i_ctype = PQfnumber(res, "datctype");
 
1855
        i_frozenxid = PQfnumber(res, "datfrozenxid");
 
1856
        i_tablespace = PQfnumber(res, "tablespace");
 
1857
 
 
1858
        dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
 
1859
        dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
 
1860
        dba = PQgetvalue(res, 0, i_dba);
 
1861
        encoding = PQgetvalue(res, 0, i_encoding);
 
1862
        collate = PQgetvalue(res, 0, i_collate);
 
1863
        ctype = PQgetvalue(res, 0, i_ctype);
 
1864
        frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
 
1865
        tablespace = PQgetvalue(res, 0, i_tablespace);
 
1866
 
 
1867
        appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
 
1868
                                          fmtId(datname));
 
1869
        if (strlen(encoding) > 0)
 
1870
        {
 
1871
                appendPQExpBuffer(creaQry, " ENCODING = ");
 
1872
                appendStringLiteralAH(creaQry, encoding, AH);
 
1873
        }
 
1874
        if (strlen(collate) > 0)
 
1875
        {
 
1876
                appendPQExpBuffer(creaQry, " LC_COLLATE = ");
 
1877
                appendStringLiteralAH(creaQry, collate, AH);
 
1878
        }
 
1879
        if (strlen(ctype) > 0)
 
1880
        {
 
1881
                appendPQExpBuffer(creaQry, " LC_CTYPE = ");
 
1882
                appendStringLiteralAH(creaQry, ctype, AH);
 
1883
        }
 
1884
        if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
 
1885
                appendPQExpBuffer(creaQry, " TABLESPACE = %s",
 
1886
                                                  fmtId(tablespace));
 
1887
        appendPQExpBuffer(creaQry, ";\n");
 
1888
 
 
1889
        if (binary_upgrade)
 
1890
        {
 
1891
                appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
 
1892
                appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
 
1893
                                                  "SET datfrozenxid = '%u'\n"
 
1894
                                                  "WHERE        datname = ",
 
1895
                                                  frozenxid);
 
1896
                appendStringLiteralAH(creaQry, datname, AH);
 
1897
                appendPQExpBuffer(creaQry, ";\n");
 
1898
 
 
1899
        }
 
1900
 
 
1901
        appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
 
1902
                                          fmtId(datname));
 
1903
 
 
1904
        dbDumpId = createDumpId();
 
1905
 
 
1906
        ArchiveEntry(AH,
 
1907
                                 dbCatId,               /* catalog ID */
 
1908
                                 dbDumpId,              /* dump ID */
 
1909
                                 datname,               /* Name */
 
1910
                                 NULL,                  /* Namespace */
 
1911
                                 NULL,                  /* Tablespace */
 
1912
                                 dba,                   /* Owner */
 
1913
                                 false,                 /* with oids */
 
1914
                                 "DATABASE",    /* Desc */
 
1915
                                 SECTION_PRE_DATA,              /* Section */
 
1916
                                 creaQry->data, /* Create */
 
1917
                                 delQry->data,  /* Del */
 
1918
                                 NULL,                  /* Copy */
 
1919
                                 NULL,                  /* Deps */
 
1920
                                 0,                             /* # Deps */
 
1921
                                 NULL,                  /* Dumper */
 
1922
                                 NULL);                 /* Dumper Arg */
 
1923
 
 
1924
        /*
 
1925
         * pg_largeobject and pg_largeobject_metadata come from the old system
 
1926
         * intact, so set their relfrozenxids.
 
1927
         */
 
1928
        if (binary_upgrade)
 
1929
        {
 
1930
                PGresult   *lo_res;
 
1931
                PQExpBuffer loFrozenQry = createPQExpBuffer();
 
1932
                PQExpBuffer loOutQry = createPQExpBuffer();
 
1933
                int                     i_relfrozenxid;
 
1934
 
 
1935
                /*
 
1936
                 * pg_largeobject
 
1937
                 */
 
1938
                appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
 
1939
                                                  "FROM pg_catalog.pg_class\n"
 
1940
                                                  "WHERE oid = %u;\n",
 
1941
                                                  LargeObjectRelationId);
 
1942
 
 
1943
                lo_res = PQexec(g_conn, loFrozenQry->data);
 
1944
                check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
 
1945
 
 
1946
                if (PQntuples(lo_res) != 1)
 
1947
                {
 
1948
                        write_msg(NULL, "dumpDatabase(): could not find pg_largeobject.relfrozenxid\n");
 
1949
                        exit_nicely();
 
1950
                }
 
1951
 
 
1952
                i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
 
1953
 
 
1954
                appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
 
1955
                appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
 
1956
                                                  "SET relfrozenxid = '%u'\n"
 
1957
                                                  "WHERE oid = %u;\n",
 
1958
                                                  atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
 
1959
                                                  LargeObjectRelationId);
 
1960
                ArchiveEntry(AH, nilCatalogId, createDumpId(),
 
1961
                                         "pg_largeobject", NULL, NULL, "",
 
1962
                                         false, "pg_largeobject", SECTION_PRE_DATA,
 
1963
                                         loOutQry->data, "", NULL,
 
1964
                                         NULL, 0,
 
1965
                                         NULL, NULL);
 
1966
 
 
1967
                PQclear(lo_res);
 
1968
 
 
1969
                /*
 
1970
                 * pg_largeobject_metadata
 
1971
                 */
 
1972
                if (g_fout->remoteVersion >= 90000)
 
1973
                {
 
1974
                        resetPQExpBuffer(loFrozenQry);
 
1975
                        resetPQExpBuffer(loOutQry);
 
1976
 
 
1977
                        appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
 
1978
                                                          "FROM pg_catalog.pg_class\n"
 
1979
                                                          "WHERE oid = %u;\n",
 
1980
                                                          LargeObjectMetadataRelationId);
 
1981
 
 
1982
                        lo_res = PQexec(g_conn, loFrozenQry->data);
 
1983
                        check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
 
1984
 
 
1985
                        if (PQntuples(lo_res) != 1)
 
1986
                        {
 
1987
                                write_msg(NULL, "dumpDatabase(): could not find pg_largeobject_metadata.relfrozenxid\n");
 
1988
                                exit_nicely();
 
1989
                        }
 
1990
 
 
1991
                        i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
 
1992
 
 
1993
                        appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
 
1994
                        appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
 
1995
                                                          "SET relfrozenxid = '%u'\n"
 
1996
                                                          "WHERE oid = %u;\n",
 
1997
                                                          atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
 
1998
                                                          LargeObjectMetadataRelationId);
 
1999
                        ArchiveEntry(AH, nilCatalogId, createDumpId(),
 
2000
                                                 "pg_largeobject_metadata", NULL, NULL, "",
 
2001
                                                 false, "pg_largeobject_metadata", SECTION_PRE_DATA,
 
2002
                                                 loOutQry->data, "", NULL,
 
2003
                                                 NULL, 0,
 
2004
                                                 NULL, NULL);
 
2005
 
 
2006
                        PQclear(lo_res);
 
2007
                }
 
2008
 
 
2009
                destroyPQExpBuffer(loFrozenQry);
 
2010
                destroyPQExpBuffer(loOutQry);
 
2011
        }
 
2012
 
 
2013
        /* Dump DB comment if any */
 
2014
        if (g_fout->remoteVersion >= 80200)
 
2015
        {
 
2016
                /*
 
2017
                 * 8.2 keeps comments on shared objects in a shared table, so we
 
2018
                 * cannot use the dumpComment used for other database objects.
 
2019
                 */
 
2020
                char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
 
2021
 
 
2022
                if (comment && strlen(comment))
 
2023
                {
 
2024
                        resetPQExpBuffer(dbQry);
 
2025
 
 
2026
                        /*
 
2027
                         * Generates warning when loaded into a differently-named
 
2028
                         * database.
 
2029
                         */
 
2030
                        appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
 
2031
                        appendStringLiteralAH(dbQry, comment, AH);
 
2032
                        appendPQExpBuffer(dbQry, ";\n");
 
2033
 
 
2034
                        ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
 
2035
                                                 dba, false, "COMMENT", SECTION_NONE,
 
2036
                                                 dbQry->data, "", NULL,
 
2037
                                                 &dbDumpId, 1, NULL, NULL);
 
2038
                }
 
2039
        }
 
2040
        else
 
2041
        {
 
2042
                resetPQExpBuffer(dbQry);
 
2043
                appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
 
2044
                dumpComment(AH, dbQry->data, NULL, "",
 
2045
                                        dbCatId, 0, dbDumpId);
 
2046
        }
 
2047
 
 
2048
        PQclear(res);
 
2049
 
 
2050
        destroyPQExpBuffer(dbQry);
 
2051
        destroyPQExpBuffer(delQry);
 
2052
        destroyPQExpBuffer(creaQry);
 
2053
}
 
2054
 
 
2055
 
 
2056
/*
 
2057
 * dumpEncoding: put the correct encoding into the archive
 
2058
 */
 
2059
static void
 
2060
dumpEncoding(Archive *AH)
 
2061
{
 
2062
        const char *encname = pg_encoding_to_char(AH->encoding);
 
2063
        PQExpBuffer qry = createPQExpBuffer();
 
2064
 
 
2065
        if (g_verbose)
 
2066
                write_msg(NULL, "saving encoding = %s\n", encname);
 
2067
 
 
2068
        appendPQExpBuffer(qry, "SET client_encoding = ");
 
2069
        appendStringLiteralAH(qry, encname, AH);
 
2070
        appendPQExpBuffer(qry, ";\n");
 
2071
 
 
2072
        ArchiveEntry(AH, nilCatalogId, createDumpId(),
 
2073
                                 "ENCODING", NULL, NULL, "",
 
2074
                                 false, "ENCODING", SECTION_PRE_DATA,
 
2075
                                 qry->data, "", NULL,
 
2076
                                 NULL, 0,
 
2077
                                 NULL, NULL);
 
2078
 
 
2079
        destroyPQExpBuffer(qry);
 
2080
}
 
2081
 
 
2082
 
 
2083
/*
 
2084
 * dumpStdStrings: put the correct escape string behavior into the archive
 
2085
 */
 
2086
static void
 
2087
dumpStdStrings(Archive *AH)
 
2088
{
 
2089
        const char *stdstrings = AH->std_strings ? "on" : "off";
 
2090
        PQExpBuffer qry = createPQExpBuffer();
 
2091
 
 
2092
        if (g_verbose)
 
2093
                write_msg(NULL, "saving standard_conforming_strings = %s\n",
 
2094
                                  stdstrings);
 
2095
 
 
2096
        appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
 
2097
                                          stdstrings);
 
2098
 
 
2099
        ArchiveEntry(AH, nilCatalogId, createDumpId(),
 
2100
                                 "STDSTRINGS", NULL, NULL, "",
 
2101
                                 false, "STDSTRINGS", SECTION_PRE_DATA,
 
2102
                                 qry->data, "", NULL,
 
2103
                                 NULL, 0,
 
2104
                                 NULL, NULL);
 
2105
 
 
2106
        destroyPQExpBuffer(qry);
 
2107
}
 
2108
 
 
2109
 
 
2110
/*
 
2111
 * getBlobs:
 
2112
 *      Collect schema-level data about large objects
 
2113
 */
 
2114
static void
 
2115
getBlobs(Archive *AH)
 
2116
{
 
2117
        PQExpBuffer blobQry = createPQExpBuffer();
 
2118
        BlobInfo   *binfo;
 
2119
        DumpableObject *bdata;
 
2120
        PGresult   *res;
 
2121
        int                     ntups;
 
2122
        int                     i;
 
2123
 
 
2124
        /* Verbose message */
 
2125
        if (g_verbose)
 
2126
                write_msg(NULL, "reading large objects\n");
 
2127
 
 
2128
        /* Make sure we are in proper schema */
 
2129
        selectSourceSchema("pg_catalog");
 
2130
 
 
2131
        /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
 
2132
        if (AH->remoteVersion >= 90000)
 
2133
                appendPQExpBuffer(blobQry,
 
2134
                                                  "SELECT oid, (%s lomowner) AS rolname, lomacl"
 
2135
                                                  " FROM pg_largeobject_metadata",
 
2136
                                                  username_subquery);
 
2137
        else if (AH->remoteVersion >= 70100)
 
2138
                appendPQExpBuffer(blobQry,
 
2139
                                                  "SELECT DISTINCT loid, NULL::oid, NULL::oid"
 
2140
                                                  " FROM pg_largeobject");
 
2141
        else
 
2142
                appendPQExpBuffer(blobQry,
 
2143
                                                  "SELECT oid, NULL::oid, NULL::oid"
 
2144
                                                  " FROM pg_class WHERE relkind = 'l'");
 
2145
 
 
2146
        res = PQexec(g_conn, blobQry->data);
 
2147
        check_sql_result(res, g_conn, blobQry->data, PGRES_TUPLES_OK);
 
2148
 
 
2149
        ntups = PQntuples(res);
 
2150
        if (ntups > 0)
 
2151
        {
 
2152
                /*
 
2153
                 * Each large object has its own BLOB archive entry.
 
2154
                 */
 
2155
                binfo = (BlobInfo *) malloc(ntups * sizeof(BlobInfo));
 
2156
 
 
2157
                for (i = 0; i < ntups; i++)
 
2158
                {
 
2159
                        binfo[i].dobj.objType = DO_BLOB;
 
2160
                        binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
 
2161
                        binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
 
2162
                        AssignDumpId(&binfo[i].dobj);
 
2163
 
 
2164
                        binfo[i].dobj.name = strdup(PQgetvalue(res, i, 0));
 
2165
                        if (!PQgetisnull(res, i, 1))
 
2166
                                binfo[i].rolname = strdup(PQgetvalue(res, i, 1));
 
2167
                        else
 
2168
                                binfo[i].rolname = "";
 
2169
                        if (!PQgetisnull(res, i, 2))
 
2170
                                binfo[i].blobacl = strdup(PQgetvalue(res, i, 2));
 
2171
                        else
 
2172
                                binfo[i].blobacl = NULL;
 
2173
                }
 
2174
 
 
2175
                /*
 
2176
                 * If we have any large objects, a "BLOBS" archive entry is needed.
 
2177
                 * This is just a placeholder for sorting; it carries no data now.
 
2178
                 */
 
2179
                bdata = (DumpableObject *) malloc(sizeof(DumpableObject));
 
2180
                bdata->objType = DO_BLOB_DATA;
 
2181
                bdata->catId = nilCatalogId;
 
2182
                AssignDumpId(bdata);
 
2183
                bdata->name = strdup("BLOBS");
 
2184
        }
 
2185
 
 
2186
        PQclear(res);
 
2187
        destroyPQExpBuffer(blobQry);
 
2188
}
 
2189
 
 
2190
/*
 
2191
 * dumpBlob
 
2192
 *
 
2193
 * dump the definition (metadata) of the given large object
 
2194
 */
 
2195
static void
 
2196
dumpBlob(Archive *AH, BlobInfo *binfo)
 
2197
{
 
2198
        PQExpBuffer cquery = createPQExpBuffer();
 
2199
        PQExpBuffer dquery = createPQExpBuffer();
 
2200
 
 
2201
        appendPQExpBuffer(cquery,
 
2202
                                          "SELECT pg_catalog.lo_create('%s');\n",
 
2203
                                          binfo->dobj.name);
 
2204
 
 
2205
        appendPQExpBuffer(dquery,
 
2206
                                          "SELECT pg_catalog.lo_unlink('%s');\n",
 
2207
                                          binfo->dobj.name);
 
2208
 
 
2209
        ArchiveEntry(AH, binfo->dobj.catId, binfo->dobj.dumpId,
 
2210
                                 binfo->dobj.name,
 
2211
                                 NULL, NULL,
 
2212
                                 binfo->rolname, false,
 
2213
                                 "BLOB", SECTION_PRE_DATA,
 
2214
                                 cquery->data, dquery->data, NULL,
 
2215
                                 binfo->dobj.dependencies, binfo->dobj.nDeps,
 
2216
                                 NULL, NULL);
 
2217
 
 
2218
        /* set up tag for comment and/or ACL */
 
2219
        resetPQExpBuffer(cquery);
 
2220
        appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
 
2221
 
 
2222
        /* Dump comment if any */
 
2223
        dumpComment(AH, cquery->data,
 
2224
                                NULL, binfo->rolname,
 
2225
                                binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
2226
 
 
2227
        /* Dump security label if any */
 
2228
        dumpSecLabel(AH, cquery->data,
 
2229
                                 NULL, binfo->rolname,
 
2230
                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
 
2231
 
 
2232
        /* Dump ACL if any */
 
2233
        if (binfo->blobacl)
 
2234
                dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
 
2235
                                binfo->dobj.name, NULL, cquery->data,
 
2236
                                NULL, binfo->rolname, binfo->blobacl);
 
2237
 
 
2238
        destroyPQExpBuffer(cquery);
 
2239
        destroyPQExpBuffer(dquery);
 
2240
}
 
2241
 
 
2242
/*
 
2243
 * dumpBlobs:
 
2244
 *      dump the data contents of all large objects
 
2245
 */
 
2246
static int
 
2247
dumpBlobs(Archive *AH, void *arg)
 
2248
{
 
2249
        const char *blobQry;
 
2250
        const char *blobFetchQry;
 
2251
        PGresult   *res;
 
2252
        char            buf[LOBBUFSIZE];
 
2253
        int                     ntups;
 
2254
        int                     i;
 
2255
        int                     cnt;
 
2256
 
 
2257
        if (g_verbose)
 
2258
                write_msg(NULL, "saving large objects\n");
 
2259
 
 
2260
        /* Make sure we are in proper schema */
 
2261
        selectSourceSchema("pg_catalog");
 
2262
 
 
2263
        /*
 
2264
         * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
 
2265
         * the already-in-memory dumpable objects instead...
 
2266
         */
 
2267
        if (AH->remoteVersion >= 90000)
 
2268
                blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
 
2269
        else if (AH->remoteVersion >= 70100)
 
2270
                blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
 
2271
        else
 
2272
                blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
 
2273
 
 
2274
        res = PQexec(g_conn, blobQry);
 
2275
        check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
 
2276
 
 
2277
        /* Command to fetch from cursor */
 
2278
        blobFetchQry = "FETCH 1000 IN bloboid";
 
2279
 
 
2280
        do
 
2281
        {
 
2282
                PQclear(res);
 
2283
 
 
2284
                /* Do a fetch */
 
2285
                res = PQexec(g_conn, blobFetchQry);
 
2286
                check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
 
2287
 
 
2288
                /* Process the tuples, if any */
 
2289
                ntups = PQntuples(res);
 
2290
                for (i = 0; i < ntups; i++)
 
2291
                {
 
2292
                        Oid                     blobOid;
 
2293
                        int                     loFd;
 
2294
 
 
2295
                        blobOid = atooid(PQgetvalue(res, i, 0));
 
2296
                        /* Open the BLOB */
 
2297
                        loFd = lo_open(g_conn, blobOid, INV_READ);
 
2298
                        if (loFd == -1)
 
2299
                        {
 
2300
                                write_msg(NULL, "could not open large object %u: %s",
 
2301
                                                  blobOid, PQerrorMessage(g_conn));
 
2302
                                exit_nicely();
 
2303
                        }
 
2304
 
 
2305
                        StartBlob(AH, blobOid);
 
2306
 
 
2307
                        /* Now read it in chunks, sending data to archive */
 
2308
                        do
 
2309
                        {
 
2310
                                cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
 
2311
                                if (cnt < 0)
 
2312
                                {
 
2313
                                        write_msg(NULL, "error reading large object %u: %s",
 
2314
                                                          blobOid, PQerrorMessage(g_conn));
 
2315
                                        exit_nicely();
 
2316
                                }
 
2317
 
 
2318
                                WriteData(AH, buf, cnt);
 
2319
                        } while (cnt > 0);
 
2320
 
 
2321
                        lo_close(g_conn, loFd);
 
2322
 
 
2323
                        EndBlob(AH, blobOid);
 
2324
                }
 
2325
        } while (ntups > 0);
 
2326
 
 
2327
        PQclear(res);
 
2328
 
 
2329
        return 1;
 
2330
}
 
2331
 
 
2332
static void
 
2333
binary_upgrade_set_type_oids_by_type_oid(PQExpBuffer upgrade_buffer,
 
2334
                                                                                 Oid pg_type_oid)
 
2335
{
 
2336
        PQExpBuffer upgrade_query = createPQExpBuffer();
 
2337
        int                     ntups;
 
2338
        PGresult   *upgrade_res;
 
2339
        Oid                     pg_type_array_oid;
 
2340
 
 
2341
        appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
 
2342
        appendPQExpBuffer(upgrade_buffer,
 
2343
         "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
 
2344
                                          pg_type_oid);
 
2345
 
 
2346
        /* we only support old >= 8.3 for binary upgrades */
 
2347
        appendPQExpBuffer(upgrade_query,
 
2348
                                          "SELECT typarray "
 
2349
                                          "FROM pg_catalog.pg_type "
 
2350
                                          "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
 
2351
                                          pg_type_oid);
 
2352
 
 
2353
        upgrade_res = PQexec(g_conn, upgrade_query->data);
 
2354
        check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
 
2355
 
 
2356
        /* Expecting a single result only */
 
2357
        ntups = PQntuples(upgrade_res);
 
2358
        if (ntups != 1)
 
2359
        {
 
2360
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
2361
                                                           "query returned %d rows instead of one: %s\n",
 
2362
                                                                 ntups),
 
2363
                                  ntups, upgrade_query->data);
 
2364
                exit_nicely();
 
2365
        }
 
2366
 
 
2367
        pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
 
2368
 
 
2369
        if (OidIsValid(pg_type_array_oid))
 
2370
        {
 
2371
                appendPQExpBuffer(upgrade_buffer,
 
2372
                           "\n-- For binary upgrade, must preserve pg_type array oid\n");
 
2373
                appendPQExpBuffer(upgrade_buffer,
 
2374
                                                  "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
 
2375
                                                  pg_type_array_oid);
 
2376
        }
 
2377
 
 
2378
        PQclear(upgrade_res);
 
2379
        destroyPQExpBuffer(upgrade_query);
 
2380
}
 
2381
 
 
2382
static bool
 
2383
binary_upgrade_set_type_oids_by_rel_oid(PQExpBuffer upgrade_buffer,
 
2384
                                                                                Oid pg_rel_oid)
 
2385
{
 
2386
        PQExpBuffer upgrade_query = createPQExpBuffer();
 
2387
        int                     ntups;
 
2388
        PGresult   *upgrade_res;
 
2389
        Oid                     pg_type_oid;
 
2390
        bool            toast_set = false;
 
2391
 
 
2392
        /* we only support old >= 8.3 for binary upgrades */
 
2393
        appendPQExpBuffer(upgrade_query,
 
2394
                                          "SELECT c.reltype AS crel, t.reltype AS trel "
 
2395
                                          "FROM pg_catalog.pg_class c "
 
2396
                                          "LEFT JOIN pg_catalog.pg_class t ON "
 
2397
                                          "  (c.reltoastrelid = t.oid) "
 
2398
                                          "WHERE c.oid = '%u'::pg_catalog.oid;",
 
2399
                                          pg_rel_oid);
 
2400
 
 
2401
        upgrade_res = PQexec(g_conn, upgrade_query->data);
 
2402
        check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
 
2403
 
 
2404
        /* Expecting a single result only */
 
2405
        ntups = PQntuples(upgrade_res);
 
2406
        if (ntups != 1)
 
2407
        {
 
2408
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
2409
                                                           "query returned %d rows instead of one: %s\n",
 
2410
                                                                 ntups),
 
2411
                                  ntups, upgrade_query->data);
 
2412
                exit_nicely();
 
2413
        }
 
2414
 
 
2415
        pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
 
2416
 
 
2417
        binary_upgrade_set_type_oids_by_type_oid(upgrade_buffer, pg_type_oid);
 
2418
 
 
2419
        if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
 
2420
        {
 
2421
                /* Toast tables do not have pg_type array rows */
 
2422
                Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
 
2423
                                                                                        PQfnumber(upgrade_res, "trel")));
 
2424
 
 
2425
                appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
 
2426
                appendPQExpBuffer(upgrade_buffer,
 
2427
                                                  "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
 
2428
                                                  pg_type_toast_oid);
 
2429
 
 
2430
                toast_set = true;
 
2431
        }
 
2432
 
 
2433
        PQclear(upgrade_res);
 
2434
        destroyPQExpBuffer(upgrade_query);
 
2435
 
 
2436
        return toast_set;
 
2437
}
 
2438
 
 
2439
static void
 
2440
binary_upgrade_set_pg_class_oids(PQExpBuffer upgrade_buffer, Oid pg_class_oid,
 
2441
                                                                 bool is_index)
 
2442
{
 
2443
        PQExpBuffer upgrade_query = createPQExpBuffer();
 
2444
        int                     ntups;
 
2445
        PGresult   *upgrade_res;
 
2446
        Oid                     pg_class_reltoastrelid;
 
2447
        Oid                     pg_class_reltoastidxid;
 
2448
 
 
2449
        appendPQExpBuffer(upgrade_query,
 
2450
                                          "SELECT c.reltoastrelid, t.reltoastidxid "
 
2451
                                          "FROM pg_catalog.pg_class c LEFT JOIN "
 
2452
                                          "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
 
2453
                                          "WHERE c.oid = '%u'::pg_catalog.oid;",
 
2454
                                          pg_class_oid);
 
2455
 
 
2456
        upgrade_res = PQexec(g_conn, upgrade_query->data);
 
2457
        check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
 
2458
 
 
2459
        /* Expecting a single result only */
 
2460
        ntups = PQntuples(upgrade_res);
 
2461
        if (ntups != 1)
 
2462
        {
 
2463
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
2464
                                                           "query returned %d rows instead of one: %s\n",
 
2465
                                                                 ntups),
 
2466
                                  ntups, upgrade_query->data);
 
2467
                exit_nicely();
 
2468
        }
 
2469
 
 
2470
        pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
 
2471
        pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
 
2472
 
 
2473
        appendPQExpBuffer(upgrade_buffer,
 
2474
                                   "\n-- For binary upgrade, must preserve pg_class oids\n");
 
2475
 
 
2476
        if (!is_index)
 
2477
        {
 
2478
                appendPQExpBuffer(upgrade_buffer,
 
2479
                                                  "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
 
2480
                                                  pg_class_oid);
 
2481
                /* only tables have toast tables, not indexes */
 
2482
                if (OidIsValid(pg_class_reltoastrelid))
 
2483
                {
 
2484
                        /*
 
2485
                         * One complexity is that the table definition might not require
 
2486
                         * the creation of a TOAST table, and the TOAST table might have
 
2487
                         * been created long after table creation, when the table was
 
2488
                         * loaded with wide data.  By setting the TOAST oid we force
 
2489
                         * creation of the TOAST heap and TOAST index by the backend so we
 
2490
                         * can cleanly copy the files during binary upgrade.
 
2491
                         */
 
2492
 
 
2493
                        appendPQExpBuffer(upgrade_buffer,
 
2494
                                                          "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
 
2495
                                                          pg_class_reltoastrelid);
 
2496
 
 
2497
                        /* every toast table has an index */
 
2498
                        appendPQExpBuffer(upgrade_buffer,
 
2499
                                                          "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
 
2500
                                                          pg_class_reltoastidxid);
 
2501
                }
 
2502
        }
 
2503
        else
 
2504
                appendPQExpBuffer(upgrade_buffer,
 
2505
                                                  "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
 
2506
                                                  pg_class_oid);
 
2507
 
 
2508
        appendPQExpBuffer(upgrade_buffer, "\n");
 
2509
 
 
2510
        PQclear(upgrade_res);
 
2511
        destroyPQExpBuffer(upgrade_query);
 
2512
}
 
2513
 
 
2514
/*
 
2515
 * If the DumpableObject is a member of an extension, add a suitable
 
2516
 * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
 
2517
 */
 
2518
static void
 
2519
binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
 
2520
                                                                DumpableObject *dobj,
 
2521
                                                                const char *objlabel)
 
2522
{
 
2523
        DumpableObject *extobj = NULL;
 
2524
        int                     i;
 
2525
 
 
2526
        if (!dobj->ext_member)
 
2527
                return;
 
2528
 
 
2529
        /*
 
2530
         * Find the parent extension.  We could avoid this search if we wanted to
 
2531
         * add a link field to DumpableObject, but the space costs of that would
 
2532
         * be considerable.  We assume that member objects could only have a
 
2533
         * direct dependency on their own extension, not any others.
 
2534
         */
 
2535
        for (i = 0; i < dobj->nDeps; i++)
 
2536
        {
 
2537
                extobj = findObjectByDumpId(dobj->dependencies[i]);
 
2538
                if (extobj && extobj->objType == DO_EXTENSION)
 
2539
                        break;
 
2540
                extobj = NULL;
 
2541
        }
 
2542
        if (extobj == NULL)
 
2543
        {
 
2544
                write_msg(NULL, "failed to find parent extension for %s", objlabel);
 
2545
                exit_nicely();
 
2546
        }
 
2547
 
 
2548
        appendPQExpBuffer(upgrade_buffer,
 
2549
          "\n-- For binary upgrade, handle extension membership the hard way\n");
 
2550
        appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
 
2551
                                          fmtId(extobj->name),
 
2552
                                          objlabel);
 
2553
}
 
2554
 
 
2555
/*
 
2556
 * getNamespaces:
 
2557
 *        read all namespaces in the system catalogs and return them in the
 
2558
 * NamespaceInfo* structure
 
2559
 *
 
2560
 *      numNamespaces is set to the number of namespaces read in
 
2561
 */
 
2562
NamespaceInfo *
 
2563
getNamespaces(int *numNamespaces)
 
2564
{
 
2565
        PGresult   *res;
 
2566
        int                     ntups;
 
2567
        int                     i;
 
2568
        PQExpBuffer query;
 
2569
        NamespaceInfo *nsinfo;
 
2570
        int                     i_tableoid;
 
2571
        int                     i_oid;
 
2572
        int                     i_nspname;
 
2573
        int                     i_rolname;
 
2574
        int                     i_nspacl;
 
2575
 
 
2576
        /*
 
2577
         * Before 7.3, there are no real namespaces; create two dummy entries, one
 
2578
         * for user stuff and one for system stuff.
 
2579
         */
 
2580
        if (g_fout->remoteVersion < 70300)
 
2581
        {
 
2582
                nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
 
2583
 
 
2584
                nsinfo[0].dobj.objType = DO_NAMESPACE;
 
2585
                nsinfo[0].dobj.catId.tableoid = 0;
 
2586
                nsinfo[0].dobj.catId.oid = 0;
 
2587
                AssignDumpId(&nsinfo[0].dobj);
 
2588
                nsinfo[0].dobj.name = strdup("public");
 
2589
                nsinfo[0].rolname = strdup("");
 
2590
                nsinfo[0].nspacl = strdup("");
 
2591
 
 
2592
                selectDumpableNamespace(&nsinfo[0]);
 
2593
 
 
2594
                nsinfo[1].dobj.objType = DO_NAMESPACE;
 
2595
                nsinfo[1].dobj.catId.tableoid = 0;
 
2596
                nsinfo[1].dobj.catId.oid = 1;
 
2597
                AssignDumpId(&nsinfo[1].dobj);
 
2598
                nsinfo[1].dobj.name = strdup("pg_catalog");
 
2599
                nsinfo[1].rolname = strdup("");
 
2600
                nsinfo[1].nspacl = strdup("");
 
2601
 
 
2602
                selectDumpableNamespace(&nsinfo[1]);
 
2603
 
 
2604
                g_namespaces = nsinfo;
 
2605
                g_numNamespaces = *numNamespaces = 2;
 
2606
 
 
2607
                return nsinfo;
 
2608
        }
 
2609
 
 
2610
        query = createPQExpBuffer();
 
2611
 
 
2612
        /* Make sure we are in proper schema */
 
2613
        selectSourceSchema("pg_catalog");
 
2614
 
 
2615
        /*
 
2616
         * we fetch all namespaces including system ones, so that every object we
 
2617
         * read in can be linked to a containing namespace.
 
2618
         */
 
2619
        appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
 
2620
                                          "(%s nspowner) AS rolname, "
 
2621
                                          "nspacl FROM pg_namespace",
 
2622
                                          username_subquery);
 
2623
 
 
2624
        res = PQexec(g_conn, query->data);
 
2625
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
2626
 
 
2627
        ntups = PQntuples(res);
 
2628
 
 
2629
        nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
 
2630
 
 
2631
        i_tableoid = PQfnumber(res, "tableoid");
 
2632
        i_oid = PQfnumber(res, "oid");
 
2633
        i_nspname = PQfnumber(res, "nspname");
 
2634
        i_rolname = PQfnumber(res, "rolname");
 
2635
        i_nspacl = PQfnumber(res, "nspacl");
 
2636
 
 
2637
        for (i = 0; i < ntups; i++)
 
2638
        {
 
2639
                nsinfo[i].dobj.objType = DO_NAMESPACE;
 
2640
                nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
2641
                nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
2642
                AssignDumpId(&nsinfo[i].dobj);
 
2643
                nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
 
2644
                nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
2645
                nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
 
2646
 
 
2647
                /* Decide whether to dump this namespace */
 
2648
                selectDumpableNamespace(&nsinfo[i]);
 
2649
 
 
2650
                if (strlen(nsinfo[i].rolname) == 0)
 
2651
                        write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
 
2652
                                          nsinfo[i].dobj.name);
 
2653
        }
 
2654
 
 
2655
        PQclear(res);
 
2656
        destroyPQExpBuffer(query);
 
2657
 
 
2658
        g_namespaces = nsinfo;
 
2659
        g_numNamespaces = *numNamespaces = ntups;
 
2660
 
 
2661
        return nsinfo;
 
2662
}
 
2663
 
 
2664
/*
 
2665
 * findNamespace:
 
2666
 *              given a namespace OID and an object OID, look up the info read by
 
2667
 *              getNamespaces
 
2668
 *
 
2669
 * NB: for pre-7.3 source database, we use object OID to guess whether it's
 
2670
 * a system object or not.      In 7.3 and later there is no guessing.
 
2671
 */
 
2672
static NamespaceInfo *
 
2673
findNamespace(Oid nsoid, Oid objoid)
 
2674
{
 
2675
        int                     i;
 
2676
 
 
2677
        if (g_fout->remoteVersion >= 70300)
 
2678
        {
 
2679
                for (i = 0; i < g_numNamespaces; i++)
 
2680
                {
 
2681
                        NamespaceInfo *nsinfo = &g_namespaces[i];
 
2682
 
 
2683
                        if (nsoid == nsinfo->dobj.catId.oid)
 
2684
                                return nsinfo;
 
2685
                }
 
2686
                write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
 
2687
                exit_nicely();
 
2688
        }
 
2689
        else
 
2690
        {
 
2691
                /* This code depends on the layout set up by getNamespaces. */
 
2692
                if (objoid > g_last_builtin_oid)
 
2693
                        i = 0;                          /* user object */
 
2694
                else
 
2695
                        i = 1;                          /* system object */
 
2696
                return &g_namespaces[i];
 
2697
        }
 
2698
 
 
2699
        return NULL;                            /* keep compiler quiet */
 
2700
}
 
2701
 
 
2702
/*
 
2703
 * getExtensions:
 
2704
 *        read all extensions in the system catalogs and return them in the
 
2705
 * ExtensionInfo* structure
 
2706
 *
 
2707
 *      numExtensions is set to the number of extensions read in
 
2708
 */
 
2709
ExtensionInfo *
 
2710
getExtensions(int *numExtensions)
 
2711
{
 
2712
        PGresult   *res;
 
2713
        int                     ntups;
 
2714
        int                     i;
 
2715
        PQExpBuffer query;
 
2716
        ExtensionInfo *extinfo;
 
2717
        int                     i_tableoid;
 
2718
        int                     i_oid;
 
2719
        int                     i_extname;
 
2720
        int                     i_nspname;
 
2721
        int                     i_extrelocatable;
 
2722
        int                     i_extversion;
 
2723
        int                     i_extconfig;
 
2724
        int                     i_extcondition;
 
2725
 
 
2726
        /*
 
2727
         * Before 9.1, there are no extensions.
 
2728
         */
 
2729
        if (g_fout->remoteVersion < 90100)
 
2730
        {
 
2731
                *numExtensions = 0;
 
2732
                return NULL;
 
2733
        }
 
2734
 
 
2735
        query = createPQExpBuffer();
 
2736
 
 
2737
        /* Make sure we are in proper schema */
 
2738
        selectSourceSchema("pg_catalog");
 
2739
 
 
2740
        appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
 
2741
                                          "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
 
2742
                                          "FROM pg_extension x "
 
2743
                                          "JOIN pg_namespace n ON n.oid = x.extnamespace");
 
2744
 
 
2745
        res = PQexec(g_conn, query->data);
 
2746
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
2747
 
 
2748
        ntups = PQntuples(res);
 
2749
 
 
2750
        extinfo = (ExtensionInfo *) malloc(ntups * sizeof(ExtensionInfo));
 
2751
 
 
2752
        i_tableoid = PQfnumber(res, "tableoid");
 
2753
        i_oid = PQfnumber(res, "oid");
 
2754
        i_extname = PQfnumber(res, "extname");
 
2755
        i_nspname = PQfnumber(res, "nspname");
 
2756
        i_extrelocatable = PQfnumber(res, "extrelocatable");
 
2757
        i_extversion = PQfnumber(res, "extversion");
 
2758
        i_extconfig = PQfnumber(res, "extconfig");
 
2759
        i_extcondition = PQfnumber(res, "extcondition");
 
2760
 
 
2761
        for (i = 0; i < ntups; i++)
 
2762
        {
 
2763
                extinfo[i].dobj.objType = DO_EXTENSION;
 
2764
                extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
2765
                extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
2766
                AssignDumpId(&extinfo[i].dobj);
 
2767
                extinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_extname));
 
2768
                extinfo[i].namespace = strdup(PQgetvalue(res, i, i_nspname));
 
2769
                extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
 
2770
                extinfo[i].extversion = strdup(PQgetvalue(res, i, i_extversion));
 
2771
                extinfo[i].extconfig = strdup(PQgetvalue(res, i, i_extconfig));
 
2772
                extinfo[i].extcondition = strdup(PQgetvalue(res, i, i_extcondition));
 
2773
 
 
2774
                /* Decide whether we want to dump it */
 
2775
                selectDumpableExtension(&(extinfo[i]));
 
2776
        }
 
2777
 
 
2778
        PQclear(res);
 
2779
        destroyPQExpBuffer(query);
 
2780
 
 
2781
        *numExtensions = ntups;
 
2782
 
 
2783
        return extinfo;
 
2784
}
 
2785
 
 
2786
/*
 
2787
 * getTypes:
 
2788
 *        read all types in the system catalogs and return them in the
 
2789
 * TypeInfo* structure
 
2790
 *
 
2791
 *      numTypes is set to the number of types read in
 
2792
 *
 
2793
 * NB: this must run after getFuncs() because we assume we can do
 
2794
 * findFuncByOid().
 
2795
 */
 
2796
TypeInfo *
 
2797
getTypes(int *numTypes)
 
2798
{
 
2799
        PGresult   *res;
 
2800
        int                     ntups;
 
2801
        int                     i;
 
2802
        PQExpBuffer query = createPQExpBuffer();
 
2803
        TypeInfo   *tyinfo;
 
2804
        ShellTypeInfo *stinfo;
 
2805
        int                     i_tableoid;
 
2806
        int                     i_oid;
 
2807
        int                     i_typname;
 
2808
        int                     i_typnamespace;
 
2809
        int                     i_rolname;
 
2810
        int                     i_typinput;
 
2811
        int                     i_typoutput;
 
2812
        int                     i_typelem;
 
2813
        int                     i_typrelid;
 
2814
        int                     i_typrelkind;
 
2815
        int                     i_typtype;
 
2816
        int                     i_typisdefined;
 
2817
        int                     i_isarray;
 
2818
 
 
2819
        /*
 
2820
         * we include even the built-in types because those may be used as array
 
2821
         * elements by user-defined types
 
2822
         *
 
2823
         * we filter out the built-in types when we dump out the types
 
2824
         *
 
2825
         * same approach for undefined (shell) types and array types
 
2826
         *
 
2827
         * Note: as of 8.3 we can reliably detect whether a type is an
 
2828
         * auto-generated array type by checking the element type's typarray.
 
2829
         * (Before that the test is capable of generating false positives.) We
 
2830
         * still check for name beginning with '_', though, so as to avoid the
 
2831
         * cost of the subselect probe for all standard types.  This would have to
 
2832
         * be revisited if the backend ever allows renaming of array types.
 
2833
         */
 
2834
 
 
2835
        /* Make sure we are in proper schema */
 
2836
        selectSourceSchema("pg_catalog");
 
2837
 
 
2838
        if (g_fout->remoteVersion >= 80300)
 
2839
        {
 
2840
                appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
 
2841
                                                  "typnamespace, "
 
2842
                                                  "(%s typowner) AS rolname, "
 
2843
                                                  "typinput::oid AS typinput, "
 
2844
                                                  "typoutput::oid AS typoutput, typelem, typrelid, "
 
2845
                                                  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 
2846
                                                  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 
2847
                                                  "typtype, typisdefined, "
 
2848
                                                  "typname[0] = '_' AND typelem != 0 AND "
 
2849
                                                  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
 
2850
                                                  "FROM pg_type",
 
2851
                                                  username_subquery);
 
2852
        }
 
2853
        else if (g_fout->remoteVersion >= 70300)
 
2854
        {
 
2855
                appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
 
2856
                                                  "typnamespace, "
 
2857
                                                  "(%s typowner) AS rolname, "
 
2858
                                                  "typinput::oid AS typinput, "
 
2859
                                                  "typoutput::oid AS typoutput, typelem, typrelid, "
 
2860
                                                  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 
2861
                                                  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 
2862
                                                  "typtype, typisdefined, "
 
2863
                                                  "typname[0] = '_' AND typelem != 0 AS isarray "
 
2864
                                                  "FROM pg_type",
 
2865
                                                  username_subquery);
 
2866
        }
 
2867
        else if (g_fout->remoteVersion >= 70100)
 
2868
        {
 
2869
                appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
 
2870
                                                  "0::oid AS typnamespace, "
 
2871
                                                  "(%s typowner) AS rolname, "
 
2872
                                                  "typinput::oid AS typinput, "
 
2873
                                                  "typoutput::oid AS typoutput, typelem, typrelid, "
 
2874
                                                  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 
2875
                                                  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 
2876
                                                  "typtype, typisdefined, "
 
2877
                                                  "typname[0] = '_' AND typelem != 0 AS isarray "
 
2878
                                                  "FROM pg_type",
 
2879
                                                  username_subquery);
 
2880
        }
 
2881
        else
 
2882
        {
 
2883
                appendPQExpBuffer(query, "SELECT "
 
2884
                 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
 
2885
                                                  "oid, typname, "
 
2886
                                                  "0::oid AS typnamespace, "
 
2887
                                                  "(%s typowner) AS rolname, "
 
2888
                                                  "typinput::oid AS typinput, "
 
2889
                                                  "typoutput::oid AS typoutput, typelem, typrelid, "
 
2890
                                                  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
 
2891
                                                  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
 
2892
                                                  "typtype, typisdefined, "
 
2893
                                                  "typname[0] = '_' AND typelem != 0 AS isarray "
 
2894
                                                  "FROM pg_type",
 
2895
                                                  username_subquery);
 
2896
        }
 
2897
 
 
2898
        res = PQexec(g_conn, query->data);
 
2899
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
2900
 
 
2901
        ntups = PQntuples(res);
 
2902
 
 
2903
        tyinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
 
2904
 
 
2905
        i_tableoid = PQfnumber(res, "tableoid");
 
2906
        i_oid = PQfnumber(res, "oid");
 
2907
        i_typname = PQfnumber(res, "typname");
 
2908
        i_typnamespace = PQfnumber(res, "typnamespace");
 
2909
        i_rolname = PQfnumber(res, "rolname");
 
2910
        i_typinput = PQfnumber(res, "typinput");
 
2911
        i_typoutput = PQfnumber(res, "typoutput");
 
2912
        i_typelem = PQfnumber(res, "typelem");
 
2913
        i_typrelid = PQfnumber(res, "typrelid");
 
2914
        i_typrelkind = PQfnumber(res, "typrelkind");
 
2915
        i_typtype = PQfnumber(res, "typtype");
 
2916
        i_typisdefined = PQfnumber(res, "typisdefined");
 
2917
        i_isarray = PQfnumber(res, "isarray");
 
2918
 
 
2919
        for (i = 0; i < ntups; i++)
 
2920
        {
 
2921
                tyinfo[i].dobj.objType = DO_TYPE;
 
2922
                tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
2923
                tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
2924
                AssignDumpId(&tyinfo[i].dobj);
 
2925
                tyinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
 
2926
                tyinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
 
2927
                                                                                                 tyinfo[i].dobj.catId.oid);
 
2928
                tyinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
2929
                tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
 
2930
                tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
 
2931
                tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
 
2932
                tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
 
2933
                tyinfo[i].shellType = NULL;
 
2934
 
 
2935
                if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
 
2936
                        tyinfo[i].isDefined = true;
 
2937
                else
 
2938
                        tyinfo[i].isDefined = false;
 
2939
 
 
2940
                if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
 
2941
                        tyinfo[i].isArray = true;
 
2942
                else
 
2943
                        tyinfo[i].isArray = false;
 
2944
 
 
2945
                /* Decide whether we want to dump it */
 
2946
                selectDumpableType(&tyinfo[i]);
 
2947
 
 
2948
                /*
 
2949
                 * If it's a domain, fetch info about its constraints, if any
 
2950
                 */
 
2951
                tyinfo[i].nDomChecks = 0;
 
2952
                tyinfo[i].domChecks = NULL;
 
2953
                if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
 
2954
                        getDomainConstraints(&(tyinfo[i]));
 
2955
 
 
2956
                /*
 
2957
                 * If it's a base type, make a DumpableObject representing a shell
 
2958
                 * definition of the type.      We will need to dump that ahead of the I/O
 
2959
                 * functions for the type.
 
2960
                 *
 
2961
                 * Note: the shell type doesn't have a catId.  You might think it
 
2962
                 * should copy the base type's catId, but then it might capture the
 
2963
                 * pg_depend entries for the type, which we don't want.
 
2964
                 */
 
2965
                if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_BASE)
 
2966
                {
 
2967
                        stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
 
2968
                        stinfo->dobj.objType = DO_SHELL_TYPE;
 
2969
                        stinfo->dobj.catId = nilCatalogId;
 
2970
                        AssignDumpId(&stinfo->dobj);
 
2971
                        stinfo->dobj.name = strdup(tyinfo[i].dobj.name);
 
2972
                        stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
 
2973
                        stinfo->baseType = &(tyinfo[i]);
 
2974
                        tyinfo[i].shellType = stinfo;
 
2975
 
 
2976
                        /*
 
2977
                         * Initially mark the shell type as not to be dumped.  We'll only
 
2978
                         * dump it if the I/O functions need to be dumped; this is taken
 
2979
                         * care of while sorting dependencies.
 
2980
                         */
 
2981
                        stinfo->dobj.dump = false;
 
2982
 
 
2983
                        /*
 
2984
                         * However, if dumping from pre-7.3, there will be no dependency
 
2985
                         * info so we have to fake it here.  We only need to worry about
 
2986
                         * typinput and typoutput since the other functions only exist
 
2987
                         * post-7.3.
 
2988
                         */
 
2989
                        if (g_fout->remoteVersion < 70300)
 
2990
                        {
 
2991
                                Oid                     typinput;
 
2992
                                Oid                     typoutput;
 
2993
                                FuncInfo   *funcInfo;
 
2994
 
 
2995
                                typinput = atooid(PQgetvalue(res, i, i_typinput));
 
2996
                                typoutput = atooid(PQgetvalue(res, i, i_typoutput));
 
2997
 
 
2998
                                funcInfo = findFuncByOid(typinput);
 
2999
                                if (funcInfo && funcInfo->dobj.dump)
 
3000
                                {
 
3001
                                        /* base type depends on function */
 
3002
                                        addObjectDependency(&tyinfo[i].dobj,
 
3003
                                                                                funcInfo->dobj.dumpId);
 
3004
                                        /* function depends on shell type */
 
3005
                                        addObjectDependency(&funcInfo->dobj,
 
3006
                                                                                stinfo->dobj.dumpId);
 
3007
                                        /* mark shell type as to be dumped */
 
3008
                                        stinfo->dobj.dump = true;
 
3009
                                }
 
3010
 
 
3011
                                funcInfo = findFuncByOid(typoutput);
 
3012
                                if (funcInfo && funcInfo->dobj.dump)
 
3013
                                {
 
3014
                                        /* base type depends on function */
 
3015
                                        addObjectDependency(&tyinfo[i].dobj,
 
3016
                                                                                funcInfo->dobj.dumpId);
 
3017
                                        /* function depends on shell type */
 
3018
                                        addObjectDependency(&funcInfo->dobj,
 
3019
                                                                                stinfo->dobj.dumpId);
 
3020
                                        /* mark shell type as to be dumped */
 
3021
                                        stinfo->dobj.dump = true;
 
3022
                                }
 
3023
                        }
 
3024
                }
 
3025
 
 
3026
                if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
 
3027
                        write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
 
3028
                                          tyinfo[i].dobj.name);
 
3029
        }
 
3030
 
 
3031
        *numTypes = ntups;
 
3032
 
 
3033
        PQclear(res);
 
3034
 
 
3035
        destroyPQExpBuffer(query);
 
3036
 
 
3037
        return tyinfo;
 
3038
}
 
3039
 
 
3040
/*
 
3041
 * getOperators:
 
3042
 *        read all operators in the system catalogs and return them in the
 
3043
 * OprInfo* structure
 
3044
 *
 
3045
 *      numOprs is set to the number of operators read in
 
3046
 */
 
3047
OprInfo *
 
3048
getOperators(int *numOprs)
 
3049
{
 
3050
        PGresult   *res;
 
3051
        int                     ntups;
 
3052
        int                     i;
 
3053
        PQExpBuffer query = createPQExpBuffer();
 
3054
        OprInfo    *oprinfo;
 
3055
        int                     i_tableoid;
 
3056
        int                     i_oid;
 
3057
        int                     i_oprname;
 
3058
        int                     i_oprnamespace;
 
3059
        int                     i_rolname;
 
3060
        int                     i_oprcode;
 
3061
 
 
3062
        /*
 
3063
         * find all operators, including builtin operators; we filter out
 
3064
         * system-defined operators at dump-out time.
 
3065
         */
 
3066
 
 
3067
        /* Make sure we are in proper schema */
 
3068
        selectSourceSchema("pg_catalog");
 
3069
 
 
3070
        if (g_fout->remoteVersion >= 70300)
 
3071
        {
 
3072
                appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
 
3073
                                                  "oprnamespace, "
 
3074
                                                  "(%s oprowner) AS rolname, "
 
3075
                                                  "oprcode::oid AS oprcode "
 
3076
                                                  "FROM pg_operator",
 
3077
                                                  username_subquery);
 
3078
        }
 
3079
        else if (g_fout->remoteVersion >= 70100)
 
3080
        {
 
3081
                appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
 
3082
                                                  "0::oid AS oprnamespace, "
 
3083
                                                  "(%s oprowner) AS rolname, "
 
3084
                                                  "oprcode::oid AS oprcode "
 
3085
                                                  "FROM pg_operator",
 
3086
                                                  username_subquery);
 
3087
        }
 
3088
        else
 
3089
        {
 
3090
                appendPQExpBuffer(query, "SELECT "
 
3091
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
 
3092
                                                  "oid, oprname, "
 
3093
                                                  "0::oid AS oprnamespace, "
 
3094
                                                  "(%s oprowner) AS rolname, "
 
3095
                                                  "oprcode::oid AS oprcode "
 
3096
                                                  "FROM pg_operator",
 
3097
                                                  username_subquery);
 
3098
        }
 
3099
 
 
3100
        res = PQexec(g_conn, query->data);
 
3101
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3102
 
 
3103
        ntups = PQntuples(res);
 
3104
        *numOprs = ntups;
 
3105
 
 
3106
        oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
 
3107
 
 
3108
        i_tableoid = PQfnumber(res, "tableoid");
 
3109
        i_oid = PQfnumber(res, "oid");
 
3110
        i_oprname = PQfnumber(res, "oprname");
 
3111
        i_oprnamespace = PQfnumber(res, "oprnamespace");
 
3112
        i_rolname = PQfnumber(res, "rolname");
 
3113
        i_oprcode = PQfnumber(res, "oprcode");
 
3114
 
 
3115
        for (i = 0; i < ntups; i++)
 
3116
        {
 
3117
                oprinfo[i].dobj.objType = DO_OPERATOR;
 
3118
                oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3119
                oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3120
                AssignDumpId(&oprinfo[i].dobj);
 
3121
                oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
 
3122
                oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
 
3123
                                                                                                  oprinfo[i].dobj.catId.oid);
 
3124
                oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3125
                oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
 
3126
 
 
3127
                /* Decide whether we want to dump it */
 
3128
                selectDumpableObject(&(oprinfo[i].dobj));
 
3129
 
 
3130
                if (strlen(oprinfo[i].rolname) == 0)
 
3131
                        write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
 
3132
                                          oprinfo[i].dobj.name);
 
3133
        }
 
3134
 
 
3135
        PQclear(res);
 
3136
 
 
3137
        destroyPQExpBuffer(query);
 
3138
 
 
3139
        return oprinfo;
 
3140
}
 
3141
 
 
3142
/*
 
3143
 * getCollations:
 
3144
 *        read all collations in the system catalogs and return them in the
 
3145
 * CollInfo* structure
 
3146
 *
 
3147
 *      numCollations is set to the number of collations read in
 
3148
 */
 
3149
CollInfo *
 
3150
getCollations(int *numCollations)
 
3151
{
 
3152
        PGresult   *res;
 
3153
        int                     ntups;
 
3154
        int                     i;
 
3155
        PQExpBuffer query = createPQExpBuffer();
 
3156
        CollInfo   *collinfo;
 
3157
        int                     i_tableoid;
 
3158
        int                     i_oid;
 
3159
        int                     i_collname;
 
3160
        int                     i_collnamespace;
 
3161
        int                     i_rolname;
 
3162
 
 
3163
        /* Collations didn't exist pre-9.1 */
 
3164
        if (g_fout->remoteVersion < 90100)
 
3165
        {
 
3166
                *numCollations = 0;
 
3167
                return NULL;
 
3168
        }
 
3169
 
 
3170
        /*
 
3171
         * find all collations, including builtin collations; we filter out
 
3172
         * system-defined collations at dump-out time.
 
3173
         */
 
3174
 
 
3175
        /* Make sure we are in proper schema */
 
3176
        selectSourceSchema("pg_catalog");
 
3177
 
 
3178
        appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
 
3179
                                          "collnamespace, "
 
3180
                                          "(%s collowner) AS rolname "
 
3181
                                          "FROM pg_collation",
 
3182
                                          username_subquery);
 
3183
 
 
3184
        res = PQexec(g_conn, query->data);
 
3185
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3186
 
 
3187
        ntups = PQntuples(res);
 
3188
        *numCollations = ntups;
 
3189
 
 
3190
        collinfo = (CollInfo *) malloc(ntups * sizeof(CollInfo));
 
3191
 
 
3192
        i_tableoid = PQfnumber(res, "tableoid");
 
3193
        i_oid = PQfnumber(res, "oid");
 
3194
        i_collname = PQfnumber(res, "collname");
 
3195
        i_collnamespace = PQfnumber(res, "collnamespace");
 
3196
        i_rolname = PQfnumber(res, "rolname");
 
3197
 
 
3198
        for (i = 0; i < ntups; i++)
 
3199
        {
 
3200
                collinfo[i].dobj.objType = DO_COLLATION;
 
3201
                collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3202
                collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3203
                AssignDumpId(&collinfo[i].dobj);
 
3204
                collinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_collname));
 
3205
                collinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)),
 
3206
                                                                                                 collinfo[i].dobj.catId.oid);
 
3207
                collinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3208
 
 
3209
                /* Decide whether we want to dump it */
 
3210
                selectDumpableObject(&(collinfo[i].dobj));
 
3211
        }
 
3212
 
 
3213
        PQclear(res);
 
3214
 
 
3215
        destroyPQExpBuffer(query);
 
3216
 
 
3217
        return collinfo;
 
3218
}
 
3219
 
 
3220
/*
 
3221
 * getConversions:
 
3222
 *        read all conversions in the system catalogs and return them in the
 
3223
 * ConvInfo* structure
 
3224
 *
 
3225
 *      numConversions is set to the number of conversions read in
 
3226
 */
 
3227
ConvInfo *
 
3228
getConversions(int *numConversions)
 
3229
{
 
3230
        PGresult   *res;
 
3231
        int                     ntups;
 
3232
        int                     i;
 
3233
        PQExpBuffer query = createPQExpBuffer();
 
3234
        ConvInfo   *convinfo;
 
3235
        int                     i_tableoid;
 
3236
        int                     i_oid;
 
3237
        int                     i_conname;
 
3238
        int                     i_connamespace;
 
3239
        int                     i_rolname;
 
3240
 
 
3241
        /* Conversions didn't exist pre-7.3 */
 
3242
        if (g_fout->remoteVersion < 70300)
 
3243
        {
 
3244
                *numConversions = 0;
 
3245
                return NULL;
 
3246
        }
 
3247
 
 
3248
        /*
 
3249
         * find all conversions, including builtin conversions; we filter out
 
3250
         * system-defined conversions at dump-out time.
 
3251
         */
 
3252
 
 
3253
        /* Make sure we are in proper schema */
 
3254
        selectSourceSchema("pg_catalog");
 
3255
 
 
3256
        appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
 
3257
                                          "connamespace, "
 
3258
                                          "(%s conowner) AS rolname "
 
3259
                                          "FROM pg_conversion",
 
3260
                                          username_subquery);
 
3261
 
 
3262
        res = PQexec(g_conn, query->data);
 
3263
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3264
 
 
3265
        ntups = PQntuples(res);
 
3266
        *numConversions = ntups;
 
3267
 
 
3268
        convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
 
3269
 
 
3270
        i_tableoid = PQfnumber(res, "tableoid");
 
3271
        i_oid = PQfnumber(res, "oid");
 
3272
        i_conname = PQfnumber(res, "conname");
 
3273
        i_connamespace = PQfnumber(res, "connamespace");
 
3274
        i_rolname = PQfnumber(res, "rolname");
 
3275
 
 
3276
        for (i = 0; i < ntups; i++)
 
3277
        {
 
3278
                convinfo[i].dobj.objType = DO_CONVERSION;
 
3279
                convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3280
                convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3281
                AssignDumpId(&convinfo[i].dobj);
 
3282
                convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
 
3283
                convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
 
3284
                                                                                                 convinfo[i].dobj.catId.oid);
 
3285
                convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3286
 
 
3287
                /* Decide whether we want to dump it */
 
3288
                selectDumpableObject(&(convinfo[i].dobj));
 
3289
        }
 
3290
 
 
3291
        PQclear(res);
 
3292
 
 
3293
        destroyPQExpBuffer(query);
 
3294
 
 
3295
        return convinfo;
 
3296
}
 
3297
 
 
3298
/*
 
3299
 * getOpclasses:
 
3300
 *        read all opclasses in the system catalogs and return them in the
 
3301
 * OpclassInfo* structure
 
3302
 *
 
3303
 *      numOpclasses is set to the number of opclasses read in
 
3304
 */
 
3305
OpclassInfo *
 
3306
getOpclasses(int *numOpclasses)
 
3307
{
 
3308
        PGresult   *res;
 
3309
        int                     ntups;
 
3310
        int                     i;
 
3311
        PQExpBuffer query = createPQExpBuffer();
 
3312
        OpclassInfo *opcinfo;
 
3313
        int                     i_tableoid;
 
3314
        int                     i_oid;
 
3315
        int                     i_opcname;
 
3316
        int                     i_opcnamespace;
 
3317
        int                     i_rolname;
 
3318
 
 
3319
        /*
 
3320
         * find all opclasses, including builtin opclasses; we filter out
 
3321
         * system-defined opclasses at dump-out time.
 
3322
         */
 
3323
 
 
3324
        /* Make sure we are in proper schema */
 
3325
        selectSourceSchema("pg_catalog");
 
3326
 
 
3327
        if (g_fout->remoteVersion >= 70300)
 
3328
        {
 
3329
                appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
 
3330
                                                  "opcnamespace, "
 
3331
                                                  "(%s opcowner) AS rolname "
 
3332
                                                  "FROM pg_opclass",
 
3333
                                                  username_subquery);
 
3334
        }
 
3335
        else if (g_fout->remoteVersion >= 70100)
 
3336
        {
 
3337
                appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
 
3338
                                                  "0::oid AS opcnamespace, "
 
3339
                                                  "''::name AS rolname "
 
3340
                                                  "FROM pg_opclass");
 
3341
        }
 
3342
        else
 
3343
        {
 
3344
                appendPQExpBuffer(query, "SELECT "
 
3345
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
 
3346
                                                  "oid, opcname, "
 
3347
                                                  "0::oid AS opcnamespace, "
 
3348
                                                  "''::name AS rolname "
 
3349
                                                  "FROM pg_opclass");
 
3350
        }
 
3351
 
 
3352
        res = PQexec(g_conn, query->data);
 
3353
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3354
 
 
3355
        ntups = PQntuples(res);
 
3356
        *numOpclasses = ntups;
 
3357
 
 
3358
        opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
 
3359
 
 
3360
        i_tableoid = PQfnumber(res, "tableoid");
 
3361
        i_oid = PQfnumber(res, "oid");
 
3362
        i_opcname = PQfnumber(res, "opcname");
 
3363
        i_opcnamespace = PQfnumber(res, "opcnamespace");
 
3364
        i_rolname = PQfnumber(res, "rolname");
 
3365
 
 
3366
        for (i = 0; i < ntups; i++)
 
3367
        {
 
3368
                opcinfo[i].dobj.objType = DO_OPCLASS;
 
3369
                opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3370
                opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3371
                AssignDumpId(&opcinfo[i].dobj);
 
3372
                opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
 
3373
                opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
 
3374
                                                                                                  opcinfo[i].dobj.catId.oid);
 
3375
                opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3376
 
 
3377
                /* Decide whether we want to dump it */
 
3378
                selectDumpableObject(&(opcinfo[i].dobj));
 
3379
 
 
3380
                if (g_fout->remoteVersion >= 70300)
 
3381
                {
 
3382
                        if (strlen(opcinfo[i].rolname) == 0)
 
3383
                                write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
 
3384
                                                  opcinfo[i].dobj.name);
 
3385
                }
 
3386
        }
 
3387
 
 
3388
        PQclear(res);
 
3389
 
 
3390
        destroyPQExpBuffer(query);
 
3391
 
 
3392
        return opcinfo;
 
3393
}
 
3394
 
 
3395
/*
 
3396
 * getOpfamilies:
 
3397
 *        read all opfamilies in the system catalogs and return them in the
 
3398
 * OpfamilyInfo* structure
 
3399
 *
 
3400
 *      numOpfamilies is set to the number of opfamilies read in
 
3401
 */
 
3402
OpfamilyInfo *
 
3403
getOpfamilies(int *numOpfamilies)
 
3404
{
 
3405
        PGresult   *res;
 
3406
        int                     ntups;
 
3407
        int                     i;
 
3408
        PQExpBuffer query;
 
3409
        OpfamilyInfo *opfinfo;
 
3410
        int                     i_tableoid;
 
3411
        int                     i_oid;
 
3412
        int                     i_opfname;
 
3413
        int                     i_opfnamespace;
 
3414
        int                     i_rolname;
 
3415
 
 
3416
        /* Before 8.3, there is no separate concept of opfamilies */
 
3417
        if (g_fout->remoteVersion < 80300)
 
3418
        {
 
3419
                *numOpfamilies = 0;
 
3420
                return NULL;
 
3421
        }
 
3422
 
 
3423
        query = createPQExpBuffer();
 
3424
 
 
3425
        /*
 
3426
         * find all opfamilies, including builtin opfamilies; we filter out
 
3427
         * system-defined opfamilies at dump-out time.
 
3428
         */
 
3429
 
 
3430
        /* Make sure we are in proper schema */
 
3431
        selectSourceSchema("pg_catalog");
 
3432
 
 
3433
        appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
 
3434
                                          "opfnamespace, "
 
3435
                                          "(%s opfowner) AS rolname "
 
3436
                                          "FROM pg_opfamily",
 
3437
                                          username_subquery);
 
3438
 
 
3439
        res = PQexec(g_conn, query->data);
 
3440
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3441
 
 
3442
        ntups = PQntuples(res);
 
3443
        *numOpfamilies = ntups;
 
3444
 
 
3445
        opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
 
3446
 
 
3447
        i_tableoid = PQfnumber(res, "tableoid");
 
3448
        i_oid = PQfnumber(res, "oid");
 
3449
        i_opfname = PQfnumber(res, "opfname");
 
3450
        i_opfnamespace = PQfnumber(res, "opfnamespace");
 
3451
        i_rolname = PQfnumber(res, "rolname");
 
3452
 
 
3453
        for (i = 0; i < ntups; i++)
 
3454
        {
 
3455
                opfinfo[i].dobj.objType = DO_OPFAMILY;
 
3456
                opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3457
                opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3458
                AssignDumpId(&opfinfo[i].dobj);
 
3459
                opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
 
3460
                opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
 
3461
                                                                                                  opfinfo[i].dobj.catId.oid);
 
3462
                opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3463
 
 
3464
                /* Decide whether we want to dump it */
 
3465
                selectDumpableObject(&(opfinfo[i].dobj));
 
3466
 
 
3467
                if (g_fout->remoteVersion >= 70300)
 
3468
                {
 
3469
                        if (strlen(opfinfo[i].rolname) == 0)
 
3470
                                write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
 
3471
                                                  opfinfo[i].dobj.name);
 
3472
                }
 
3473
        }
 
3474
 
 
3475
        PQclear(res);
 
3476
 
 
3477
        destroyPQExpBuffer(query);
 
3478
 
 
3479
        return opfinfo;
 
3480
}
 
3481
 
 
3482
/*
 
3483
 * getAggregates:
 
3484
 *        read all the user-defined aggregates in the system catalogs and
 
3485
 * return them in the AggInfo* structure
 
3486
 *
 
3487
 * numAggs is set to the number of aggregates read in
 
3488
 */
 
3489
AggInfo *
 
3490
getAggregates(int *numAggs)
 
3491
{
 
3492
        PGresult   *res;
 
3493
        int                     ntups;
 
3494
        int                     i;
 
3495
        PQExpBuffer query = createPQExpBuffer();
 
3496
        AggInfo    *agginfo;
 
3497
        int                     i_tableoid;
 
3498
        int                     i_oid;
 
3499
        int                     i_aggname;
 
3500
        int                     i_aggnamespace;
 
3501
        int                     i_pronargs;
 
3502
        int                     i_proargtypes;
 
3503
        int                     i_rolname;
 
3504
        int                     i_aggacl;
 
3505
 
 
3506
        /* Make sure we are in proper schema */
 
3507
        selectSourceSchema("pg_catalog");
 
3508
 
 
3509
        /*
 
3510
         * Find all user-defined aggregates.  See comment in getFuncs() for the
 
3511
         * rationale behind the filtering logic.
 
3512
         */
 
3513
 
 
3514
        if (g_fout->remoteVersion >= 80200)
 
3515
        {
 
3516
                appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
 
3517
                                                  "pronamespace AS aggnamespace, "
 
3518
                                                  "pronargs, proargtypes, "
 
3519
                                                  "(%s proowner) AS rolname, "
 
3520
                                                  "proacl AS aggacl "
 
3521
                                                  "FROM pg_proc p "
 
3522
                                                  "WHERE proisagg AND ("
 
3523
                                                  "pronamespace != "
 
3524
                                                  "(SELECT oid FROM pg_namespace "
 
3525
                                                  "WHERE nspname = 'pg_catalog')",
 
3526
                                                  username_subquery);
 
3527
                if (binary_upgrade && g_fout->remoteVersion >= 90100)
 
3528
                        appendPQExpBuffer(query,
 
3529
                                                          " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
 
3530
                                                          "classid = 'pg_proc'::regclass AND "
 
3531
                                                          "objid = p.oid AND "
 
3532
                                                          "refclassid = 'pg_extension'::regclass AND "
 
3533
                                                          "deptype = 'e')");
 
3534
                appendPQExpBuffer(query, ")");
 
3535
        }
 
3536
        else if (g_fout->remoteVersion >= 70300)
 
3537
        {
 
3538
                appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
 
3539
                                                  "pronamespace AS aggnamespace, "
 
3540
                                                  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
 
3541
                                                  "proargtypes, "
 
3542
                                                  "(%s proowner) AS rolname, "
 
3543
                                                  "proacl AS aggacl "
 
3544
                                                  "FROM pg_proc "
 
3545
                                                  "WHERE proisagg "
 
3546
                                                  "AND pronamespace != "
 
3547
                           "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
 
3548
                                                  username_subquery);
 
3549
        }
 
3550
        else if (g_fout->remoteVersion >= 70100)
 
3551
        {
 
3552
                appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
 
3553
                                                  "0::oid AS aggnamespace, "
 
3554
                                  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 
3555
                                                  "aggbasetype AS proargtypes, "
 
3556
                                                  "(%s aggowner) AS rolname, "
 
3557
                                                  "'{=X}' AS aggacl "
 
3558
                                                  "FROM pg_aggregate "
 
3559
                                                  "where oid > '%u'::oid",
 
3560
                                                  username_subquery,
 
3561
                                                  g_last_builtin_oid);
 
3562
        }
 
3563
        else
 
3564
        {
 
3565
                appendPQExpBuffer(query, "SELECT "
 
3566
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
 
3567
                                                  "oid, aggname, "
 
3568
                                                  "0::oid AS aggnamespace, "
 
3569
                                  "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
 
3570
                                                  "aggbasetype AS proargtypes, "
 
3571
                                                  "(%s aggowner) AS rolname, "
 
3572
                                                  "'{=X}' AS aggacl "
 
3573
                                                  "FROM pg_aggregate "
 
3574
                                                  "where oid > '%u'::oid",
 
3575
                                                  username_subquery,
 
3576
                                                  g_last_builtin_oid);
 
3577
        }
 
3578
 
 
3579
        res = PQexec(g_conn, query->data);
 
3580
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3581
 
 
3582
        ntups = PQntuples(res);
 
3583
        *numAggs = ntups;
 
3584
 
 
3585
        agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
 
3586
 
 
3587
        i_tableoid = PQfnumber(res, "tableoid");
 
3588
        i_oid = PQfnumber(res, "oid");
 
3589
        i_aggname = PQfnumber(res, "aggname");
 
3590
        i_aggnamespace = PQfnumber(res, "aggnamespace");
 
3591
        i_pronargs = PQfnumber(res, "pronargs");
 
3592
        i_proargtypes = PQfnumber(res, "proargtypes");
 
3593
        i_rolname = PQfnumber(res, "rolname");
 
3594
        i_aggacl = PQfnumber(res, "aggacl");
 
3595
 
 
3596
        for (i = 0; i < ntups; i++)
 
3597
        {
 
3598
                agginfo[i].aggfn.dobj.objType = DO_AGG;
 
3599
                agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3600
                agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3601
                AssignDumpId(&agginfo[i].aggfn.dobj);
 
3602
                agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
 
3603
                agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
 
3604
                                                                                        agginfo[i].aggfn.dobj.catId.oid);
 
3605
                agginfo[i].aggfn.rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3606
                if (strlen(agginfo[i].aggfn.rolname) == 0)
 
3607
                        write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
 
3608
                                          agginfo[i].aggfn.dobj.name);
 
3609
                agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
 
3610
                agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
 
3611
                agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
 
3612
                agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
 
3613
                if (agginfo[i].aggfn.nargs == 0)
 
3614
                        agginfo[i].aggfn.argtypes = NULL;
 
3615
                else
 
3616
                {
 
3617
                        agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
 
3618
                        if (g_fout->remoteVersion >= 70300)
 
3619
                                parseOidArray(PQgetvalue(res, i, i_proargtypes),
 
3620
                                                          agginfo[i].aggfn.argtypes,
 
3621
                                                          agginfo[i].aggfn.nargs);
 
3622
                        else
 
3623
                                /* it's just aggbasetype */
 
3624
                                agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
 
3625
                }
 
3626
 
 
3627
                /* Decide whether we want to dump it */
 
3628
                selectDumpableObject(&(agginfo[i].aggfn.dobj));
 
3629
        }
 
3630
 
 
3631
        PQclear(res);
 
3632
 
 
3633
        destroyPQExpBuffer(query);
 
3634
 
 
3635
        return agginfo;
 
3636
}
 
3637
 
 
3638
/*
 
3639
 * getFuncs:
 
3640
 *        read all the user-defined functions in the system catalogs and
 
3641
 * return them in the FuncInfo* structure
 
3642
 *
 
3643
 * numFuncs is set to the number of functions read in
 
3644
 */
 
3645
FuncInfo *
 
3646
getFuncs(int *numFuncs)
 
3647
{
 
3648
        PGresult   *res;
 
3649
        int                     ntups;
 
3650
        int                     i;
 
3651
        PQExpBuffer query = createPQExpBuffer();
 
3652
        FuncInfo   *finfo;
 
3653
        int                     i_tableoid;
 
3654
        int                     i_oid;
 
3655
        int                     i_proname;
 
3656
        int                     i_pronamespace;
 
3657
        int                     i_rolname;
 
3658
        int                     i_prolang;
 
3659
        int                     i_pronargs;
 
3660
        int                     i_proargtypes;
 
3661
        int                     i_prorettype;
 
3662
        int                     i_proacl;
 
3663
 
 
3664
        /* Make sure we are in proper schema */
 
3665
        selectSourceSchema("pg_catalog");
 
3666
 
 
3667
        /*
 
3668
         * Find all user-defined functions.  Normally we can exclude functions in
 
3669
         * pg_catalog, which is worth doing since there are several thousand of
 
3670
         * 'em.  However, there are some extensions that create functions in
 
3671
         * pg_catalog.  In normal dumps we can still ignore those --- but in
 
3672
         * binary-upgrade mode, we must dump the member objects of the extension,
 
3673
         * so be sure to fetch any such functions.
 
3674
         */
 
3675
 
 
3676
        if (g_fout->remoteVersion >= 70300)
 
3677
        {
 
3678
                appendPQExpBuffer(query,
 
3679
                                                  "SELECT tableoid, oid, proname, prolang, "
 
3680
                                                  "pronargs, proargtypes, prorettype, proacl, "
 
3681
                                                  "pronamespace, "
 
3682
                                                  "(%s proowner) AS rolname "
 
3683
                                                  "FROM pg_proc p "
 
3684
                                                  "WHERE NOT proisagg AND ("
 
3685
                                                  "pronamespace != "
 
3686
                                                  "(SELECT oid FROM pg_namespace "
 
3687
                                                  "WHERE nspname = 'pg_catalog')",
 
3688
                                                  username_subquery);
 
3689
                if (binary_upgrade && g_fout->remoteVersion >= 90100)
 
3690
                        appendPQExpBuffer(query,
 
3691
                                                          " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
 
3692
                                                          "classid = 'pg_proc'::regclass AND "
 
3693
                                                          "objid = p.oid AND "
 
3694
                                                          "refclassid = 'pg_extension'::regclass AND "
 
3695
                                                          "deptype = 'e')");
 
3696
                appendPQExpBuffer(query, ")");
 
3697
        }
 
3698
        else if (g_fout->remoteVersion >= 70100)
 
3699
        {
 
3700
                appendPQExpBuffer(query,
 
3701
                                                  "SELECT tableoid, oid, proname, prolang, "
 
3702
                                                  "pronargs, proargtypes, prorettype, "
 
3703
                                                  "'{=X}' AS proacl, "
 
3704
                                                  "0::oid AS pronamespace, "
 
3705
                                                  "(%s proowner) AS rolname "
 
3706
                                                  "FROM pg_proc "
 
3707
                                                  "WHERE pg_proc.oid > '%u'::oid",
 
3708
                                                  username_subquery,
 
3709
                                                  g_last_builtin_oid);
 
3710
        }
 
3711
        else
 
3712
        {
 
3713
                appendPQExpBuffer(query,
 
3714
                                                  "SELECT "
 
3715
                                                  "(SELECT oid FROM pg_class "
 
3716
                                                  " WHERE relname = 'pg_proc') AS tableoid, "
 
3717
                                                  "oid, proname, prolang, "
 
3718
                                                  "pronargs, proargtypes, prorettype, "
 
3719
                                                  "'{=X}' AS proacl, "
 
3720
                                                  "0::oid AS pronamespace, "
 
3721
                                                  "(%s proowner) AS rolname "
 
3722
                                                  "FROM pg_proc "
 
3723
                                                  "where pg_proc.oid > '%u'::oid",
 
3724
                                                  username_subquery,
 
3725
                                                  g_last_builtin_oid);
 
3726
        }
 
3727
 
 
3728
        res = PQexec(g_conn, query->data);
 
3729
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
3730
 
 
3731
        ntups = PQntuples(res);
 
3732
 
 
3733
        *numFuncs = ntups;
 
3734
 
 
3735
        finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
 
3736
 
 
3737
        i_tableoid = PQfnumber(res, "tableoid");
 
3738
        i_oid = PQfnumber(res, "oid");
 
3739
        i_proname = PQfnumber(res, "proname");
 
3740
        i_pronamespace = PQfnumber(res, "pronamespace");
 
3741
        i_rolname = PQfnumber(res, "rolname");
 
3742
        i_prolang = PQfnumber(res, "prolang");
 
3743
        i_pronargs = PQfnumber(res, "pronargs");
 
3744
        i_proargtypes = PQfnumber(res, "proargtypes");
 
3745
        i_prorettype = PQfnumber(res, "prorettype");
 
3746
        i_proacl = PQfnumber(res, "proacl");
 
3747
 
 
3748
        for (i = 0; i < ntups; i++)
 
3749
        {
 
3750
                finfo[i].dobj.objType = DO_FUNC;
 
3751
                finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
3752
                finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
3753
                AssignDumpId(&finfo[i].dobj);
 
3754
                finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
 
3755
                finfo[i].dobj.namespace =
 
3756
                        findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
 
3757
                                                  finfo[i].dobj.catId.oid);
 
3758
                finfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
3759
                finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
 
3760
                finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
 
3761
                finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
 
3762
                finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
 
3763
                if (finfo[i].nargs == 0)
 
3764
                        finfo[i].argtypes = NULL;
 
3765
                else
 
3766
                {
 
3767
                        finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
 
3768
                        parseOidArray(PQgetvalue(res, i, i_proargtypes),
 
3769
                                                  finfo[i].argtypes, finfo[i].nargs);
 
3770
                }
 
3771
 
 
3772
                /* Decide whether we want to dump it */
 
3773
                selectDumpableObject(&(finfo[i].dobj));
 
3774
 
 
3775
                if (strlen(finfo[i].rolname) == 0)
 
3776
                        write_msg(NULL,
 
3777
                                 "WARNING: owner of function \"%s\" appears to be invalid\n",
 
3778
                                          finfo[i].dobj.name);
 
3779
        }
 
3780
 
 
3781
        PQclear(res);
 
3782
 
 
3783
        destroyPQExpBuffer(query);
 
3784
 
 
3785
        return finfo;
 
3786
}
 
3787
 
 
3788
/*
 
3789
 * getTables
 
3790
 *        read all the user-defined tables (no indexes, no catalogs)
 
3791
 * in the system catalogs return them in the TableInfo* structure
 
3792
 *
 
3793
 * numTables is set to the number of tables read in
 
3794
 */
 
3795
TableInfo *
 
3796
getTables(int *numTables)
 
3797
{
 
3798
        PGresult   *res;
 
3799
        int                     ntups;
 
3800
        int                     i;
 
3801
        PQExpBuffer query = createPQExpBuffer();
 
3802
        TableInfo  *tblinfo;
 
3803
        int                     i_reltableoid;
 
3804
        int                     i_reloid;
 
3805
        int                     i_relname;
 
3806
        int                     i_relnamespace;
 
3807
        int                     i_relkind;
 
3808
        int                     i_relacl;
 
3809
        int                     i_rolname;
 
3810
        int                     i_relchecks;
 
3811
        int                     i_relhastriggers;
 
3812
        int                     i_relhasindex;
 
3813
        int                     i_relhasrules;
 
3814
        int                     i_relhasoids;
 
3815
        int                     i_relfrozenxid;
 
3816
        int                     i_toastoid;
 
3817
        int                     i_toastfrozenxid;
 
3818
        int                     i_relpersistence;
 
3819
        int                     i_owning_tab;
 
3820
        int                     i_owning_col;
 
3821
        int                     i_reltablespace;
 
3822
        int                     i_reloptions;
 
3823
        int                     i_toastreloptions;
 
3824
        int                     i_reloftype;
 
3825
 
 
3826
        /* Make sure we are in proper schema */
 
3827
        selectSourceSchema("pg_catalog");
 
3828
 
 
3829
        /*
 
3830
         * Find all the tables (including views and sequences).
 
3831
         *
 
3832
         * We include system catalogs, so that we can work if a user table is
 
3833
         * defined to inherit from a system catalog (pretty weird, but...)
 
3834
         *
 
3835
         * We ignore tables that are not type 'r' (ordinary relation), 'S'
 
3836
         * (sequence), 'v' (view), or 'c' (composite type).
 
3837
         *
 
3838
         * Composite-type table entries won't be dumped as such, but we have to
 
3839
         * make a DumpableObject for them so that we can track dependencies of the
 
3840
         * composite type (pg_depend entries for columns of the composite type
 
3841
         * link to the pg_class entry not the pg_type entry).
 
3842
         *
 
3843
         * Note: in this phase we should collect only a minimal amount of
 
3844
         * information about each table, basically just enough to decide if it is
 
3845
         * interesting. We must fetch all tables in this phase because otherwise
 
3846
         * we cannot correctly identify inherited columns, owned sequences, etc.
 
3847
         */
 
3848
 
 
3849
        if (g_fout->remoteVersion >= 90100)
 
3850
        {
 
3851
                /*
 
3852
                 * Left join to pick up dependency info linking sequences to their
 
3853
                 * owning column, if any (note this dependency is AUTO as of 8.2)
 
3854
                 */
 
3855
                appendPQExpBuffer(query,
 
3856
                                                  "SELECT c.tableoid, c.oid, c.relname, "
 
3857
                                                  "c.relacl, c.relkind, c.relnamespace, "
 
3858
                                                  "(%s c.relowner) AS rolname, "
 
3859
                                                  "c.relchecks, c.relhastriggers, "
 
3860
                                                  "c.relhasindex, c.relhasrules, c.relhasoids, "
 
3861
                                                  "c.relfrozenxid, tc.oid AS toid, "
 
3862
                                                  "tc.relfrozenxid AS tfrozenxid, "
 
3863
                                                  "c.relpersistence, "
 
3864
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 
3865
                                                  "d.refobjid AS owning_tab, "
 
3866
                                                  "d.refobjsubid AS owning_col, "
 
3867
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 
3868
                                                "array_to_string(c.reloptions, ', ') AS reloptions, "
 
3869
                                                  "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
 
3870
                                                  "FROM pg_class c "
 
3871
                                                  "LEFT JOIN pg_depend d ON "
 
3872
                                                  "(c.relkind = '%c' AND "
 
3873
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
 
3874
                                                  "d.objsubid = 0 AND "
 
3875
                                                  "d.refclassid = c.tableoid AND d.deptype = 'a') "
 
3876
                                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
 
3877
                                                  "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
 
3878
                                                  "ORDER BY c.oid",
 
3879
                                                  username_subquery,
 
3880
                                                  RELKIND_SEQUENCE,
 
3881
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
 
3882
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
 
3883
                                                  RELKIND_FOREIGN_TABLE);
 
3884
        }
 
3885
        else if (g_fout->remoteVersion >= 90000)
 
3886
        {
 
3887
                /*
 
3888
                 * Left join to pick up dependency info linking sequences to their
 
3889
                 * owning column, if any (note this dependency is AUTO as of 8.2)
 
3890
                 */
 
3891
                appendPQExpBuffer(query,
 
3892
                                                  "SELECT c.tableoid, c.oid, c.relname, "
 
3893
                                                  "c.relacl, c.relkind, c.relnamespace, "
 
3894
                                                  "(%s c.relowner) AS rolname, "
 
3895
                                                  "c.relchecks, c.relhastriggers, "
 
3896
                                                  "c.relhasindex, c.relhasrules, c.relhasoids, "
 
3897
                                                  "c.relfrozenxid, tc.oid AS toid, "
 
3898
                                                  "tc.relfrozenxid AS tfrozenxid, "
 
3899
                                                  "'p' AS relpersistence, "
 
3900
                                                  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 
3901
                                                  "d.refobjid AS owning_tab, "
 
3902
                                                  "d.refobjsubid AS owning_col, "
 
3903
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 
3904
                                                "array_to_string(c.reloptions, ', ') AS reloptions, "
 
3905
                                                  "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
 
3906
                                                  "FROM pg_class c "
 
3907
                                                  "LEFT JOIN pg_depend d ON "
 
3908
                                                  "(c.relkind = '%c' AND "
 
3909
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
 
3910
                                                  "d.objsubid = 0 AND "
 
3911
                                                  "d.refclassid = c.tableoid AND d.deptype = 'a') "
 
3912
                                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
 
3913
                                                  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
 
3914
                                                  "ORDER BY c.oid",
 
3915
                                                  username_subquery,
 
3916
                                                  RELKIND_SEQUENCE,
 
3917
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
 
3918
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
 
3919
        }
 
3920
        else if (g_fout->remoteVersion >= 80400)
 
3921
        {
 
3922
                /*
 
3923
                 * Left join to pick up dependency info linking sequences to their
 
3924
                 * owning column, if any (note this dependency is AUTO as of 8.2)
 
3925
                 */
 
3926
                appendPQExpBuffer(query,
 
3927
                                                  "SELECT c.tableoid, c.oid, c.relname, "
 
3928
                                                  "c.relacl, c.relkind, c.relnamespace, "
 
3929
                                                  "(%s c.relowner) AS rolname, "
 
3930
                                                  "c.relchecks, c.relhastriggers, "
 
3931
                                                  "c.relhasindex, c.relhasrules, c.relhasoids, "
 
3932
                                                  "c.relfrozenxid, tc.oid AS toid, "
 
3933
                                                  "tc.relfrozenxid AS tfrozenxid, "
 
3934
                                                  "'p' AS relpersistence, "
 
3935
                                                  "NULL AS reloftype, "
 
3936
                                                  "d.refobjid AS owning_tab, "
 
3937
                                                  "d.refobjsubid AS owning_col, "
 
3938
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 
3939
                                                "array_to_string(c.reloptions, ', ') AS reloptions, "
 
3940
                                                  "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
 
3941
                                                  "FROM pg_class c "
 
3942
                                                  "LEFT JOIN pg_depend d ON "
 
3943
                                                  "(c.relkind = '%c' AND "
 
3944
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
 
3945
                                                  "d.objsubid = 0 AND "
 
3946
                                                  "d.refclassid = c.tableoid AND d.deptype = 'a') "
 
3947
                                           "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
 
3948
                                                  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
 
3949
                                                  "ORDER BY c.oid",
 
3950
                                                  username_subquery,
 
3951
                                                  RELKIND_SEQUENCE,
 
3952
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
 
3953
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
 
3954
        }
 
3955
        else if (g_fout->remoteVersion >= 80200)
 
3956
        {
 
3957
                /*
 
3958
                 * Left join to pick up dependency info linking sequences to their
 
3959
                 * owning column, if any (note this dependency is AUTO as of 8.2)
 
3960
                 */
 
3961
                appendPQExpBuffer(query,
 
3962
                                                  "SELECT c.tableoid, c.oid, relname, "
 
3963
                                                  "relacl, relkind, relnamespace, "
 
3964
                                                  "(%s relowner) AS rolname, "
 
3965
                                                  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 
3966
                                                  "relhasindex, relhasrules, relhasoids, "
 
3967
                                                  "relfrozenxid, "
 
3968
                                                  "0 AS toid, "
 
3969
                                                  "0 AS tfrozenxid, "
 
3970
                                                  "'p' AS relpersistence, "
 
3971
                                                  "NULL AS reloftype, "
 
3972
                                                  "d.refobjid AS owning_tab, "
 
3973
                                                  "d.refobjsubid AS owning_col, "
 
3974
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 
3975
                                                "array_to_string(c.reloptions, ', ') AS reloptions, "
 
3976
                                                  "NULL AS toast_reloptions "
 
3977
                                                  "FROM pg_class c "
 
3978
                                                  "LEFT JOIN pg_depend d ON "
 
3979
                                                  "(c.relkind = '%c' AND "
 
3980
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
 
3981
                                                  "d.objsubid = 0 AND "
 
3982
                                                  "d.refclassid = c.tableoid AND d.deptype = 'a') "
 
3983
                                                  "WHERE relkind in ('%c', '%c', '%c', '%c') "
 
3984
                                                  "ORDER BY c.oid",
 
3985
                                                  username_subquery,
 
3986
                                                  RELKIND_SEQUENCE,
 
3987
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
 
3988
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
 
3989
        }
 
3990
        else if (g_fout->remoteVersion >= 80000)
 
3991
        {
 
3992
                /*
 
3993
                 * Left join to pick up dependency info linking sequences to their
 
3994
                 * owning column, if any
 
3995
                 */
 
3996
                appendPQExpBuffer(query,
 
3997
                                                  "SELECT c.tableoid, c.oid, relname, "
 
3998
                                                  "relacl, relkind, relnamespace, "
 
3999
                                                  "(%s relowner) AS rolname, "
 
4000
                                                  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 
4001
                                                  "relhasindex, relhasrules, relhasoids, "
 
4002
                                                  "0 AS relfrozenxid, "
 
4003
                                                  "0 AS toid, "
 
4004
                                                  "0 AS tfrozenxid, "
 
4005
                                                  "'p' AS relpersistence, "
 
4006
                                                  "NULL AS reloftype, "
 
4007
                                                  "d.refobjid AS owning_tab, "
 
4008
                                                  "d.refobjsubid AS owning_col, "
 
4009
                                                  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 
4010
                                                  "NULL AS reloptions, "
 
4011
                                                  "NULL AS toast_reloptions "
 
4012
                                                  "FROM pg_class c "
 
4013
                                                  "LEFT JOIN pg_depend d ON "
 
4014
                                                  "(c.relkind = '%c' AND "
 
4015
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
 
4016
                                                  "d.objsubid = 0 AND "
 
4017
                                                  "d.refclassid = c.tableoid AND d.deptype = 'i') "
 
4018
                                                  "WHERE relkind in ('%c', '%c', '%c', '%c') "
 
4019
                                                  "ORDER BY c.oid",
 
4020
                                                  username_subquery,
 
4021
                                                  RELKIND_SEQUENCE,
 
4022
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
 
4023
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
 
4024
        }
 
4025
        else if (g_fout->remoteVersion >= 70300)
 
4026
        {
 
4027
                /*
 
4028
                 * Left join to pick up dependency info linking sequences to their
 
4029
                 * owning column, if any
 
4030
                 */
 
4031
                appendPQExpBuffer(query,
 
4032
                                                  "SELECT c.tableoid, c.oid, relname, "
 
4033
                                                  "relacl, relkind, relnamespace, "
 
4034
                                                  "(%s relowner) AS rolname, "
 
4035
                                                  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 
4036
                                                  "relhasindex, relhasrules, relhasoids, "
 
4037
                                                  "0 AS relfrozenxid, "
 
4038
                                                  "0 AS toid, "
 
4039
                                                  "0 AS tfrozenxid, "
 
4040
                                                  "'p' AS relpersistence, "
 
4041
                                                  "NULL AS reloftype, "
 
4042
                                                  "d.refobjid AS owning_tab, "
 
4043
                                                  "d.refobjsubid AS owning_col, "
 
4044
                                                  "NULL AS reltablespace, "
 
4045
                                                  "NULL AS reloptions, "
 
4046
                                                  "NULL AS toast_reloptions "
 
4047
                                                  "FROM pg_class c "
 
4048
                                                  "LEFT JOIN pg_depend d ON "
 
4049
                                                  "(c.relkind = '%c' AND "
 
4050
                                                  "d.classid = c.tableoid AND d.objid = c.oid AND "
 
4051
                                                  "d.objsubid = 0 AND "
 
4052
                                                  "d.refclassid = c.tableoid AND d.deptype = 'i') "
 
4053
                                                  "WHERE relkind IN ('%c', '%c', '%c', '%c') "
 
4054
                                                  "ORDER BY c.oid",
 
4055
                                                  username_subquery,
 
4056
                                                  RELKIND_SEQUENCE,
 
4057
                                                  RELKIND_RELATION, RELKIND_SEQUENCE,
 
4058
                                                  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
 
4059
        }
 
4060
        else if (g_fout->remoteVersion >= 70200)
 
4061
        {
 
4062
                appendPQExpBuffer(query,
 
4063
                                                  "SELECT tableoid, oid, relname, relacl, relkind, "
 
4064
                                                  "0::oid AS relnamespace, "
 
4065
                                                  "(%s relowner) AS rolname, "
 
4066
                                                  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 
4067
                                                  "relhasindex, relhasrules, relhasoids, "
 
4068
                                                  "0 AS relfrozenxid, "
 
4069
                                                  "0 AS toid, "
 
4070
                                                  "0 AS tfrozenxid, "
 
4071
                                                  "'p' AS relpersistence, "
 
4072
                                                  "NULL AS reloftype, "
 
4073
                                                  "NULL::oid AS owning_tab, "
 
4074
                                                  "NULL::int4 AS owning_col, "
 
4075
                                                  "NULL AS reltablespace, "
 
4076
                                                  "NULL AS reloptions, "
 
4077
                                                  "NULL AS toast_reloptions "
 
4078
                                                  "FROM pg_class "
 
4079
                                                  "WHERE relkind IN ('%c', '%c', '%c') "
 
4080
                                                  "ORDER BY oid",
 
4081
                                                  username_subquery,
 
4082
                                                  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
 
4083
        }
 
4084
        else if (g_fout->remoteVersion >= 70100)
 
4085
        {
 
4086
                /* all tables have oids in 7.1 */
 
4087
                appendPQExpBuffer(query,
 
4088
                                                  "SELECT tableoid, oid, relname, relacl, relkind, "
 
4089
                                                  "0::oid AS relnamespace, "
 
4090
                                                  "(%s relowner) AS rolname, "
 
4091
                                                  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 
4092
                                                  "relhasindex, relhasrules, "
 
4093
                                                  "'t'::bool AS relhasoids, "
 
4094
                                                  "0 AS relfrozenxid, "
 
4095
                                                  "0 AS toid, "
 
4096
                                                  "0 AS tfrozenxid, "
 
4097
                                                  "'p' AS relpersistence, "
 
4098
                                                  "NULL AS reloftype, "
 
4099
                                                  "NULL::oid AS owning_tab, "
 
4100
                                                  "NULL::int4 AS owning_col, "
 
4101
                                                  "NULL AS reltablespace, "
 
4102
                                                  "NULL AS reloptions, "
 
4103
                                                  "NULL AS toast_reloptions "
 
4104
                                                  "FROM pg_class "
 
4105
                                                  "WHERE relkind IN ('%c', '%c', '%c') "
 
4106
                                                  "ORDER BY oid",
 
4107
                                                  username_subquery,
 
4108
                                                  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
 
4109
        }
 
4110
        else
 
4111
        {
 
4112
                /*
 
4113
                 * Before 7.1, view relkind was not set to 'v', so we must check if we
 
4114
                 * have a view by looking for a rule in pg_rewrite.
 
4115
                 */
 
4116
                appendPQExpBuffer(query,
 
4117
                                                  "SELECT "
 
4118
                "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
 
4119
                                                  "oid, relname, relacl, "
 
4120
                                                  "CASE WHEN relhasrules and relkind = 'r' "
 
4121
                                          "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
 
4122
                                          "             r.ev_class = c.oid AND r.ev_type = '1') "
 
4123
                                                  "THEN '%c'::\"char\" "
 
4124
                                                  "ELSE relkind END AS relkind,"
 
4125
                                                  "0::oid AS relnamespace, "
 
4126
                                                  "(%s relowner) AS rolname, "
 
4127
                                                  "relchecks, (reltriggers <> 0) AS relhastriggers, "
 
4128
                                                  "relhasindex, relhasrules, "
 
4129
                                                  "'t'::bool AS relhasoids, "
 
4130
                                                  "0 as relfrozenxid, "
 
4131
                                                  "0 AS toid, "
 
4132
                                                  "0 AS tfrozenxid, "
 
4133
                                                  "'p' AS relpersistence, "
 
4134
                                                  "NULL AS reloftype, "
 
4135
                                                  "NULL::oid AS owning_tab, "
 
4136
                                                  "NULL::int4 AS owning_col, "
 
4137
                                                  "NULL AS reltablespace, "
 
4138
                                                  "NULL AS reloptions, "
 
4139
                                                  "NULL AS toast_reloptions "
 
4140
                                                  "FROM pg_class c "
 
4141
                                                  "WHERE relkind IN ('%c', '%c') "
 
4142
                                                  "ORDER BY oid",
 
4143
                                                  RELKIND_VIEW,
 
4144
                                                  username_subquery,
 
4145
                                                  RELKIND_RELATION, RELKIND_SEQUENCE);
 
4146
        }
 
4147
 
 
4148
        res = PQexec(g_conn, query->data);
 
4149
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
4150
 
 
4151
        ntups = PQntuples(res);
 
4152
 
 
4153
        *numTables = ntups;
 
4154
 
 
4155
        /*
 
4156
         * Extract data from result and lock dumpable tables.  We do the locking
 
4157
         * before anything else, to minimize the window wherein a table could
 
4158
         * disappear under us.
 
4159
         *
 
4160
         * Note that we have to save info about all tables here, even when dumping
 
4161
         * only one, because we don't yet know which tables might be inheritance
 
4162
         * ancestors of the target table.
 
4163
         */
 
4164
        tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
 
4165
 
 
4166
        i_reltableoid = PQfnumber(res, "tableoid");
 
4167
        i_reloid = PQfnumber(res, "oid");
 
4168
        i_relname = PQfnumber(res, "relname");
 
4169
        i_relnamespace = PQfnumber(res, "relnamespace");
 
4170
        i_relacl = PQfnumber(res, "relacl");
 
4171
        i_relkind = PQfnumber(res, "relkind");
 
4172
        i_rolname = PQfnumber(res, "rolname");
 
4173
        i_relchecks = PQfnumber(res, "relchecks");
 
4174
        i_relhastriggers = PQfnumber(res, "relhastriggers");
 
4175
        i_relhasindex = PQfnumber(res, "relhasindex");
 
4176
        i_relhasrules = PQfnumber(res, "relhasrules");
 
4177
        i_relhasoids = PQfnumber(res, "relhasoids");
 
4178
        i_relfrozenxid = PQfnumber(res, "relfrozenxid");
 
4179
        i_toastoid = PQfnumber(res, "toid");
 
4180
        i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
 
4181
        i_relpersistence = PQfnumber(res, "relpersistence");
 
4182
        i_owning_tab = PQfnumber(res, "owning_tab");
 
4183
        i_owning_col = PQfnumber(res, "owning_col");
 
4184
        i_reltablespace = PQfnumber(res, "reltablespace");
 
4185
        i_reloptions = PQfnumber(res, "reloptions");
 
4186
        i_toastreloptions = PQfnumber(res, "toast_reloptions");
 
4187
        i_reloftype = PQfnumber(res, "reloftype");
 
4188
 
 
4189
        if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
 
4190
        {
 
4191
                /*
 
4192
                 * Arrange to fail instead of waiting forever for a table lock.
 
4193
                 *
 
4194
                 * NB: this coding assumes that the only queries issued within the
 
4195
                 * following loop are LOCK TABLEs; else the timeout may be undesirably
 
4196
                 * applied to other things too.
 
4197
                 */
 
4198
                resetPQExpBuffer(query);
 
4199
                appendPQExpBuffer(query, "SET statement_timeout = ");
 
4200
                appendStringLiteralConn(query, lockWaitTimeout, g_conn);
 
4201
                do_sql_command(g_conn, query->data);
 
4202
        }
 
4203
 
 
4204
        for (i = 0; i < ntups; i++)
 
4205
        {
 
4206
                tblinfo[i].dobj.objType = DO_TABLE;
 
4207
                tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
 
4208
                tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
 
4209
                AssignDumpId(&tblinfo[i].dobj);
 
4210
                tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
 
4211
                tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
 
4212
                                                                                                  tblinfo[i].dobj.catId.oid);
 
4213
                tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
4214
                tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
 
4215
                tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
 
4216
                tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
 
4217
                tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
 
4218
                tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
 
4219
                tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
 
4220
                tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
 
4221
                tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
 
4222
                tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
 
4223
                tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
 
4224
                if (PQgetisnull(res, i, i_reloftype))
 
4225
                        tblinfo[i].reloftype = NULL;
 
4226
                else
 
4227
                        tblinfo[i].reloftype = strdup(PQgetvalue(res, i, i_reloftype));
 
4228
                tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
 
4229
                if (PQgetisnull(res, i, i_owning_tab))
 
4230
                {
 
4231
                        tblinfo[i].owning_tab = InvalidOid;
 
4232
                        tblinfo[i].owning_col = 0;
 
4233
                }
 
4234
                else
 
4235
                {
 
4236
                        tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
 
4237
                        tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
 
4238
                }
 
4239
                tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
 
4240
                tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
 
4241
                tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
 
4242
 
 
4243
                /* other fields were zeroed above */
 
4244
 
 
4245
                /*
 
4246
                 * Decide whether we want to dump this table.
 
4247
                 */
 
4248
                if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
 
4249
                        tblinfo[i].dobj.dump = false;
 
4250
                else
 
4251
                        selectDumpableTable(&tblinfo[i]);
 
4252
                tblinfo[i].interesting = tblinfo[i].dobj.dump;
 
4253
 
 
4254
                /*
 
4255
                 * Read-lock target tables to make sure they aren't DROPPED or altered
 
4256
                 * in schema before we get around to dumping them.
 
4257
                 *
 
4258
                 * Note that we don't explicitly lock parents of the target tables; we
 
4259
                 * assume our lock on the child is enough to prevent schema
 
4260
                 * alterations to parent tables.
 
4261
                 *
 
4262
                 * NOTE: it'd be kinda nice to lock other relations too, not only
 
4263
                 * plain tables, but the backend doesn't presently allow that.
 
4264
                 */
 
4265
                if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
 
4266
                {
 
4267
                        resetPQExpBuffer(query);
 
4268
                        appendPQExpBuffer(query,
 
4269
                                                          "LOCK TABLE %s IN ACCESS SHARE MODE",
 
4270
                                                 fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
 
4271
                                                                                tblinfo[i].dobj.name));
 
4272
                        do_sql_command(g_conn, query->data);
 
4273
                }
 
4274
 
 
4275
                /* Emit notice if join for owner failed */
 
4276
                if (strlen(tblinfo[i].rolname) == 0)
 
4277
                        write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
 
4278
                                          tblinfo[i].dobj.name);
 
4279
        }
 
4280
 
 
4281
        if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
 
4282
        {
 
4283
                do_sql_command(g_conn, "SET statement_timeout = 0");
 
4284
        }
 
4285
 
 
4286
        PQclear(res);
 
4287
 
 
4288
        /*
 
4289
         * Force sequences that are "owned" by table columns to be dumped whenever
 
4290
         * their owning table is being dumped.
 
4291
         */
 
4292
        for (i = 0; i < ntups; i++)
 
4293
        {
 
4294
                TableInfo  *seqinfo = &tblinfo[i];
 
4295
                int                     j;
 
4296
 
 
4297
                if (!OidIsValid(seqinfo->owning_tab))
 
4298
                        continue;                       /* not an owned sequence */
 
4299
                if (seqinfo->dobj.dump)
 
4300
                        continue;                       /* no need to search */
 
4301
 
 
4302
                /* can't use findTableByOid yet, unfortunately */
 
4303
                for (j = 0; j < ntups; j++)
 
4304
                {
 
4305
                        if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
 
4306
                        {
 
4307
                                if (tblinfo[j].dobj.dump)
 
4308
                                {
 
4309
                                        seqinfo->interesting = true;
 
4310
                                        seqinfo->dobj.dump = true;
 
4311
                                }
 
4312
                                break;
 
4313
                        }
 
4314
                }
 
4315
        }
 
4316
 
 
4317
        destroyPQExpBuffer(query);
 
4318
 
 
4319
        return tblinfo;
 
4320
}
 
4321
 
 
4322
/*
 
4323
 * getInherits
 
4324
 *        read all the inheritance information
 
4325
 * from the system catalogs return them in the InhInfo* structure
 
4326
 *
 
4327
 * numInherits is set to the number of pairs read in
 
4328
 */
 
4329
InhInfo *
 
4330
getInherits(int *numInherits)
 
4331
{
 
4332
        PGresult   *res;
 
4333
        int                     ntups;
 
4334
        int                     i;
 
4335
        PQExpBuffer query = createPQExpBuffer();
 
4336
        InhInfo    *inhinfo;
 
4337
 
 
4338
        int                     i_inhrelid;
 
4339
        int                     i_inhparent;
 
4340
 
 
4341
        /* Make sure we are in proper schema */
 
4342
        selectSourceSchema("pg_catalog");
 
4343
 
 
4344
        /* find all the inheritance information */
 
4345
 
 
4346
        appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
 
4347
 
 
4348
        res = PQexec(g_conn, query->data);
 
4349
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
4350
 
 
4351
        ntups = PQntuples(res);
 
4352
 
 
4353
        *numInherits = ntups;
 
4354
 
 
4355
        inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
 
4356
 
 
4357
        i_inhrelid = PQfnumber(res, "inhrelid");
 
4358
        i_inhparent = PQfnumber(res, "inhparent");
 
4359
 
 
4360
        for (i = 0; i < ntups; i++)
 
4361
        {
 
4362
                inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
 
4363
                inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
 
4364
        }
 
4365
 
 
4366
        PQclear(res);
 
4367
 
 
4368
        destroyPQExpBuffer(query);
 
4369
 
 
4370
        return inhinfo;
 
4371
}
 
4372
 
 
4373
/*
 
4374
 * getIndexes
 
4375
 *        get information about every index on a dumpable table
 
4376
 *
 
4377
 * Note: index data is not returned directly to the caller, but it
 
4378
 * does get entered into the DumpableObject tables.
 
4379
 */
 
4380
void
 
4381
getIndexes(TableInfo tblinfo[], int numTables)
 
4382
{
 
4383
        int                     i,
 
4384
                                j;
 
4385
        PQExpBuffer query = createPQExpBuffer();
 
4386
        PGresult   *res;
 
4387
        IndxInfo   *indxinfo;
 
4388
        ConstraintInfo *constrinfo;
 
4389
        int                     i_tableoid,
 
4390
                                i_oid,
 
4391
                                i_indexname,
 
4392
                                i_indexdef,
 
4393
                                i_indnkeys,
 
4394
                                i_indkey,
 
4395
                                i_indisclustered,
 
4396
                                i_contype,
 
4397
                                i_conname,
 
4398
                                i_condeferrable,
 
4399
                                i_condeferred,
 
4400
                                i_contableoid,
 
4401
                                i_conoid,
 
4402
                                i_condef,
 
4403
                                i_tablespace,
 
4404
                                i_options;
 
4405
        int                     ntups;
 
4406
 
 
4407
        for (i = 0; i < numTables; i++)
 
4408
        {
 
4409
                TableInfo  *tbinfo = &tblinfo[i];
 
4410
 
 
4411
                /* Only plain tables have indexes */
 
4412
                if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
 
4413
                        continue;
 
4414
 
 
4415
                /* Ignore indexes of tables not to be dumped */
 
4416
                if (!tbinfo->dobj.dump)
 
4417
                        continue;
 
4418
 
 
4419
                if (g_verbose)
 
4420
                        write_msg(NULL, "reading indexes for table \"%s\"\n",
 
4421
                                          tbinfo->dobj.name);
 
4422
 
 
4423
                /* Make sure we are in proper schema so indexdef is right */
 
4424
                selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
4425
 
 
4426
                /*
 
4427
                 * The point of the messy-looking outer join is to find a constraint
 
4428
                 * that is related by an internal dependency link to the index. If we
 
4429
                 * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
 
4430
                 * assume an index won't have more than one internal dependency.
 
4431
                 *
 
4432
                 * As of 9.0 we don't need to look at pg_depend but can check for a
 
4433
                 * match to pg_constraint.conindid.  The check on conrelid is
 
4434
                 * redundant but useful because that column is indexed while conindid
 
4435
                 * is not.
 
4436
                 */
 
4437
                resetPQExpBuffer(query);
 
4438
                if (g_fout->remoteVersion >= 90000)
 
4439
                {
 
4440
                        appendPQExpBuffer(query,
 
4441
                                                          "SELECT t.tableoid, t.oid, "
 
4442
                                                          "t.relname AS indexname, "
 
4443
                                         "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
 
4444
                                                          "t.relnatts AS indnkeys, "
 
4445
                                                          "i.indkey, i.indisclustered, "
 
4446
                                                          "c.contype, c.conname, "
 
4447
                                                          "c.condeferrable, c.condeferred, "
 
4448
                                                          "c.tableoid AS contableoid, "
 
4449
                                                          "c.oid AS conoid, "
 
4450
                                  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
 
4451
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
 
4452
                                                        "array_to_string(t.reloptions, ', ') AS options "
 
4453
                                                          "FROM pg_catalog.pg_index i "
 
4454
                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
 
4455
                                                          "LEFT JOIN pg_catalog.pg_constraint c "
 
4456
                                                          "ON (i.indrelid = c.conrelid AND "
 
4457
                                                          "i.indexrelid = c.conindid AND "
 
4458
                                                          "c.contype IN ('p','u','x')) "
 
4459
                                                          "WHERE i.indrelid = '%u'::pg_catalog.oid "
 
4460
                                                          "ORDER BY indexname",
 
4461
                                                          tbinfo->dobj.catId.oid);
 
4462
                }
 
4463
                else if (g_fout->remoteVersion >= 80200)
 
4464
                {
 
4465
                        appendPQExpBuffer(query,
 
4466
                                                          "SELECT t.tableoid, t.oid, "
 
4467
                                                          "t.relname AS indexname, "
 
4468
                                         "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
 
4469
                                                          "t.relnatts AS indnkeys, "
 
4470
                                                          "i.indkey, i.indisclustered, "
 
4471
                                                          "c.contype, c.conname, "
 
4472
                                                          "c.condeferrable, c.condeferred, "
 
4473
                                                          "c.tableoid AS contableoid, "
 
4474
                                                          "c.oid AS conoid, "
 
4475
                                                          "null AS condef, "
 
4476
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
 
4477
                                                        "array_to_string(t.reloptions, ', ') AS options "
 
4478
                                                          "FROM pg_catalog.pg_index i "
 
4479
                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
 
4480
                                                          "LEFT JOIN pg_catalog.pg_depend d "
 
4481
                                                          "ON (d.classid = t.tableoid "
 
4482
                                                          "AND d.objid = t.oid "
 
4483
                                                          "AND d.deptype = 'i') "
 
4484
                                                          "LEFT JOIN pg_catalog.pg_constraint c "
 
4485
                                                          "ON (d.refclassid = c.tableoid "
 
4486
                                                          "AND d.refobjid = c.oid) "
 
4487
                                                          "WHERE i.indrelid = '%u'::pg_catalog.oid "
 
4488
                                                          "ORDER BY indexname",
 
4489
                                                          tbinfo->dobj.catId.oid);
 
4490
                }
 
4491
                else if (g_fout->remoteVersion >= 80000)
 
4492
                {
 
4493
                        appendPQExpBuffer(query,
 
4494
                                                          "SELECT t.tableoid, t.oid, "
 
4495
                                                          "t.relname AS indexname, "
 
4496
                                         "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
 
4497
                                                          "t.relnatts AS indnkeys, "
 
4498
                                                          "i.indkey, i.indisclustered, "
 
4499
                                                          "c.contype, c.conname, "
 
4500
                                                          "c.condeferrable, c.condeferred, "
 
4501
                                                          "c.tableoid AS contableoid, "
 
4502
                                                          "c.oid AS conoid, "
 
4503
                                                          "null AS condef, "
 
4504
                                                          "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
 
4505
                                                          "null AS options "
 
4506
                                                          "FROM pg_catalog.pg_index i "
 
4507
                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
 
4508
                                                          "LEFT JOIN pg_catalog.pg_depend d "
 
4509
                                                          "ON (d.classid = t.tableoid "
 
4510
                                                          "AND d.objid = t.oid "
 
4511
                                                          "AND d.deptype = 'i') "
 
4512
                                                          "LEFT JOIN pg_catalog.pg_constraint c "
 
4513
                                                          "ON (d.refclassid = c.tableoid "
 
4514
                                                          "AND d.refobjid = c.oid) "
 
4515
                                                          "WHERE i.indrelid = '%u'::pg_catalog.oid "
 
4516
                                                          "ORDER BY indexname",
 
4517
                                                          tbinfo->dobj.catId.oid);
 
4518
                }
 
4519
                else if (g_fout->remoteVersion >= 70300)
 
4520
                {
 
4521
                        appendPQExpBuffer(query,
 
4522
                                                          "SELECT t.tableoid, t.oid, "
 
4523
                                                          "t.relname AS indexname, "
 
4524
                                         "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
 
4525
                                                          "t.relnatts AS indnkeys, "
 
4526
                                                          "i.indkey, i.indisclustered, "
 
4527
                                                          "c.contype, c.conname, "
 
4528
                                                          "c.condeferrable, c.condeferred, "
 
4529
                                                          "c.tableoid AS contableoid, "
 
4530
                                                          "c.oid AS conoid, "
 
4531
                                                          "null AS condef, "
 
4532
                                                          "NULL AS tablespace, "
 
4533
                                                          "null AS options "
 
4534
                                                          "FROM pg_catalog.pg_index i "
 
4535
                                          "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
 
4536
                                                          "LEFT JOIN pg_catalog.pg_depend d "
 
4537
                                                          "ON (d.classid = t.tableoid "
 
4538
                                                          "AND d.objid = t.oid "
 
4539
                                                          "AND d.deptype = 'i') "
 
4540
                                                          "LEFT JOIN pg_catalog.pg_constraint c "
 
4541
                                                          "ON (d.refclassid = c.tableoid "
 
4542
                                                          "AND d.refobjid = c.oid) "
 
4543
                                                          "WHERE i.indrelid = '%u'::pg_catalog.oid "
 
4544
                                                          "ORDER BY indexname",
 
4545
                                                          tbinfo->dobj.catId.oid);
 
4546
                }
 
4547
                else if (g_fout->remoteVersion >= 70100)
 
4548
                {
 
4549
                        appendPQExpBuffer(query,
 
4550
                                                          "SELECT t.tableoid, t.oid, "
 
4551
                                                          "t.relname AS indexname, "
 
4552
                                                          "pg_get_indexdef(i.indexrelid) AS indexdef, "
 
4553
                                                          "t.relnatts AS indnkeys, "
 
4554
                                                          "i.indkey, false AS indisclustered, "
 
4555
                                                          "CASE WHEN i.indisprimary THEN 'p'::char "
 
4556
                                                          "ELSE '0'::char END AS contype, "
 
4557
                                                          "t.relname AS conname, "
 
4558
                                                          "false AS condeferrable, "
 
4559
                                                          "false AS condeferred, "
 
4560
                                                          "0::oid AS contableoid, "
 
4561
                                                          "t.oid AS conoid, "
 
4562
                                                          "null AS condef, "
 
4563
                                                          "NULL AS tablespace, "
 
4564
                                                          "null AS options "
 
4565
                                                          "FROM pg_index i, pg_class t "
 
4566
                                                          "WHERE t.oid = i.indexrelid "
 
4567
                                                          "AND i.indrelid = '%u'::oid "
 
4568
                                                          "ORDER BY indexname",
 
4569
                                                          tbinfo->dobj.catId.oid);
 
4570
                }
 
4571
                else
 
4572
                {
 
4573
                        appendPQExpBuffer(query,
 
4574
                                                          "SELECT "
 
4575
                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
 
4576
                                                          "t.oid, "
 
4577
                                                          "t.relname AS indexname, "
 
4578
                                                          "pg_get_indexdef(i.indexrelid) AS indexdef, "
 
4579
                                                          "t.relnatts AS indnkeys, "
 
4580
                                                          "i.indkey, false AS indisclustered, "
 
4581
                                                          "CASE WHEN i.indisprimary THEN 'p'::char "
 
4582
                                                          "ELSE '0'::char END AS contype, "
 
4583
                                                          "t.relname AS conname, "
 
4584
                                                          "false AS condeferrable, "
 
4585
                                                          "false AS condeferred, "
 
4586
                                                          "0::oid AS contableoid, "
 
4587
                                                          "t.oid AS conoid, "
 
4588
                                                          "null AS condef, "
 
4589
                                                          "NULL AS tablespace, "
 
4590
                                                          "null AS options "
 
4591
                                                          "FROM pg_index i, pg_class t "
 
4592
                                                          "WHERE t.oid = i.indexrelid "
 
4593
                                                          "AND i.indrelid = '%u'::oid "
 
4594
                                                          "ORDER BY indexname",
 
4595
                                                          tbinfo->dobj.catId.oid);
 
4596
                }
 
4597
 
 
4598
                res = PQexec(g_conn, query->data);
 
4599
                check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
4600
 
 
4601
                ntups = PQntuples(res);
 
4602
 
 
4603
                i_tableoid = PQfnumber(res, "tableoid");
 
4604
                i_oid = PQfnumber(res, "oid");
 
4605
                i_indexname = PQfnumber(res, "indexname");
 
4606
                i_indexdef = PQfnumber(res, "indexdef");
 
4607
                i_indnkeys = PQfnumber(res, "indnkeys");
 
4608
                i_indkey = PQfnumber(res, "indkey");
 
4609
                i_indisclustered = PQfnumber(res, "indisclustered");
 
4610
                i_contype = PQfnumber(res, "contype");
 
4611
                i_conname = PQfnumber(res, "conname");
 
4612
                i_condeferrable = PQfnumber(res, "condeferrable");
 
4613
                i_condeferred = PQfnumber(res, "condeferred");
 
4614
                i_contableoid = PQfnumber(res, "contableoid");
 
4615
                i_conoid = PQfnumber(res, "conoid");
 
4616
                i_condef = PQfnumber(res, "condef");
 
4617
                i_tablespace = PQfnumber(res, "tablespace");
 
4618
                i_options = PQfnumber(res, "options");
 
4619
 
 
4620
                indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
 
4621
                constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
 
4622
 
 
4623
                for (j = 0; j < ntups; j++)
 
4624
                {
 
4625
                        char            contype;
 
4626
 
 
4627
                        indxinfo[j].dobj.objType = DO_INDEX;
 
4628
                        indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
 
4629
                        indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
 
4630
                        AssignDumpId(&indxinfo[j].dobj);
 
4631
                        indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
 
4632
                        indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
 
4633
                        indxinfo[j].indextable = tbinfo;
 
4634
                        indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
 
4635
                        indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
 
4636
                        indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
 
4637
                        indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
 
4638
 
 
4639
                        /*
 
4640
                         * In pre-7.4 releases, indkeys may contain more entries than
 
4641
                         * indnkeys says (since indnkeys will be 1 for a functional
 
4642
                         * index).      We don't actually care about this case since we don't
 
4643
                         * examine indkeys except for indexes associated with PRIMARY and
 
4644
                         * UNIQUE constraints, which are never functional indexes. But we
 
4645
                         * have to allocate enough space to keep parseOidArray from
 
4646
                         * complaining.
 
4647
                         */
 
4648
                        indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
 
4649
                        parseOidArray(PQgetvalue(res, j, i_indkey),
 
4650
                                                  indxinfo[j].indkeys, INDEX_MAX_KEYS);
 
4651
                        indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
 
4652
                        contype = *(PQgetvalue(res, j, i_contype));
 
4653
 
 
4654
                        if (contype == 'p' || contype == 'u' || contype == 'x')
 
4655
                        {
 
4656
                                /*
 
4657
                                 * If we found a constraint matching the index, create an
 
4658
                                 * entry for it.
 
4659
                                 *
 
4660
                                 * In a pre-7.3 database, we take this path iff the index was
 
4661
                                 * marked indisprimary.
 
4662
                                 */
 
4663
                                constrinfo[j].dobj.objType = DO_CONSTRAINT;
 
4664
                                constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
 
4665
                                constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
 
4666
                                AssignDumpId(&constrinfo[j].dobj);
 
4667
                                constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
 
4668
                                constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
 
4669
                                constrinfo[j].contable = tbinfo;
 
4670
                                constrinfo[j].condomain = NULL;
 
4671
                                constrinfo[j].contype = contype;
 
4672
                                if (contype == 'x')
 
4673
                                        constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
 
4674
                                else
 
4675
                                        constrinfo[j].condef = NULL;
 
4676
                                constrinfo[j].confrelid = InvalidOid;
 
4677
                                constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
 
4678
                                constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
 
4679
                                constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
 
4680
                                constrinfo[j].conislocal = true;
 
4681
                                constrinfo[j].separate = true;
 
4682
 
 
4683
                                indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
 
4684
 
 
4685
                                /* If pre-7.3 DB, better make sure table comes first */
 
4686
                                addObjectDependency(&constrinfo[j].dobj,
 
4687
                                                                        tbinfo->dobj.dumpId);
 
4688
                        }
 
4689
                        else
 
4690
                        {
 
4691
                                /* Plain secondary index */
 
4692
                                indxinfo[j].indexconstraint = 0;
 
4693
                        }
 
4694
                }
 
4695
 
 
4696
                PQclear(res);
 
4697
        }
 
4698
 
 
4699
        destroyPQExpBuffer(query);
 
4700
}
 
4701
 
 
4702
/*
 
4703
 * getConstraints
 
4704
 *
 
4705
 * Get info about constraints on dumpable tables.
 
4706
 *
 
4707
 * Currently handles foreign keys only.
 
4708
 * Unique and primary key constraints are handled with indexes,
 
4709
 * while check constraints are processed in getTableAttrs().
 
4710
 */
 
4711
void
 
4712
getConstraints(TableInfo tblinfo[], int numTables)
 
4713
{
 
4714
        int                     i,
 
4715
                                j;
 
4716
        ConstraintInfo *constrinfo;
 
4717
        PQExpBuffer query;
 
4718
        PGresult   *res;
 
4719
        int                     i_contableoid,
 
4720
                                i_conoid,
 
4721
                                i_conname,
 
4722
                                i_confrelid,
 
4723
                                i_condef;
 
4724
        int                     ntups;
 
4725
 
 
4726
        /* pg_constraint was created in 7.3, so nothing to do if older */
 
4727
        if (g_fout->remoteVersion < 70300)
 
4728
                return;
 
4729
 
 
4730
        query = createPQExpBuffer();
 
4731
 
 
4732
        for (i = 0; i < numTables; i++)
 
4733
        {
 
4734
                TableInfo  *tbinfo = &tblinfo[i];
 
4735
 
 
4736
                if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
 
4737
                        continue;
 
4738
 
 
4739
                if (g_verbose)
 
4740
                        write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
 
4741
                                          tbinfo->dobj.name);
 
4742
 
 
4743
                /*
 
4744
                 * select table schema to ensure constraint expr is qualified if
 
4745
                 * needed
 
4746
                 */
 
4747
                selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
4748
 
 
4749
                resetPQExpBuffer(query);
 
4750
                appendPQExpBuffer(query,
 
4751
                                                  "SELECT tableoid, oid, conname, confrelid, "
 
4752
                                                  "pg_catalog.pg_get_constraintdef(oid) AS condef "
 
4753
                                                  "FROM pg_catalog.pg_constraint "
 
4754
                                                  "WHERE conrelid = '%u'::pg_catalog.oid "
 
4755
                                                  "AND contype = 'f'",
 
4756
                                                  tbinfo->dobj.catId.oid);
 
4757
                res = PQexec(g_conn, query->data);
 
4758
                check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
4759
 
 
4760
                ntups = PQntuples(res);
 
4761
 
 
4762
                i_contableoid = PQfnumber(res, "tableoid");
 
4763
                i_conoid = PQfnumber(res, "oid");
 
4764
                i_conname = PQfnumber(res, "conname");
 
4765
                i_confrelid = PQfnumber(res, "confrelid");
 
4766
                i_condef = PQfnumber(res, "condef");
 
4767
 
 
4768
                constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
 
4769
 
 
4770
                for (j = 0; j < ntups; j++)
 
4771
                {
 
4772
                        constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
 
4773
                        constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
 
4774
                        constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
 
4775
                        AssignDumpId(&constrinfo[j].dobj);
 
4776
                        constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
 
4777
                        constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
 
4778
                        constrinfo[j].contable = tbinfo;
 
4779
                        constrinfo[j].condomain = NULL;
 
4780
                        constrinfo[j].contype = 'f';
 
4781
                        constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
 
4782
                        constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
 
4783
                        constrinfo[j].conindex = 0;
 
4784
                        constrinfo[j].condeferrable = false;
 
4785
                        constrinfo[j].condeferred = false;
 
4786
                        constrinfo[j].conislocal = true;
 
4787
                        constrinfo[j].separate = true;
 
4788
                }
 
4789
 
 
4790
                PQclear(res);
 
4791
        }
 
4792
 
 
4793
        destroyPQExpBuffer(query);
 
4794
}
 
4795
 
 
4796
/*
 
4797
 * getDomainConstraints
 
4798
 *
 
4799
 * Get info about constraints on a domain.
 
4800
 */
 
4801
static void
 
4802
getDomainConstraints(TypeInfo *tyinfo)
 
4803
{
 
4804
        int                     i;
 
4805
        ConstraintInfo *constrinfo;
 
4806
        PQExpBuffer query;
 
4807
        PGresult   *res;
 
4808
        int                     i_tableoid,
 
4809
                                i_oid,
 
4810
                                i_conname,
 
4811
                                i_consrc;
 
4812
        int                     ntups;
 
4813
 
 
4814
        /* pg_constraint was created in 7.3, so nothing to do if older */
 
4815
        if (g_fout->remoteVersion < 70300)
 
4816
                return;
 
4817
 
 
4818
        /*
 
4819
         * select appropriate schema to ensure names in constraint are properly
 
4820
         * qualified
 
4821
         */
 
4822
        selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
 
4823
 
 
4824
        query = createPQExpBuffer();
 
4825
 
 
4826
        if (g_fout->remoteVersion >= 70400)
 
4827
                appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
 
4828
                                                  "pg_catalog.pg_get_constraintdef(oid) AS consrc "
 
4829
                                                  "FROM pg_catalog.pg_constraint "
 
4830
                                                  "WHERE contypid = '%u'::pg_catalog.oid "
 
4831
                                                  "ORDER BY conname",
 
4832
                                                  tyinfo->dobj.catId.oid);
 
4833
        else
 
4834
                appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
 
4835
                                                  "'CHECK (' || consrc || ')' AS consrc "
 
4836
                                                  "FROM pg_catalog.pg_constraint "
 
4837
                                                  "WHERE contypid = '%u'::pg_catalog.oid "
 
4838
                                                  "ORDER BY conname",
 
4839
                                                  tyinfo->dobj.catId.oid);
 
4840
 
 
4841
        res = PQexec(g_conn, query->data);
 
4842
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
4843
 
 
4844
        ntups = PQntuples(res);
 
4845
 
 
4846
        i_tableoid = PQfnumber(res, "tableoid");
 
4847
        i_oid = PQfnumber(res, "oid");
 
4848
        i_conname = PQfnumber(res, "conname");
 
4849
        i_consrc = PQfnumber(res, "consrc");
 
4850
 
 
4851
        constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
 
4852
 
 
4853
        tyinfo->nDomChecks = ntups;
 
4854
        tyinfo->domChecks = constrinfo;
 
4855
 
 
4856
        for (i = 0; i < ntups; i++)
 
4857
        {
 
4858
                constrinfo[i].dobj.objType = DO_CONSTRAINT;
 
4859
                constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
4860
                constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
4861
                AssignDumpId(&constrinfo[i].dobj);
 
4862
                constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
 
4863
                constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
 
4864
                constrinfo[i].contable = NULL;
 
4865
                constrinfo[i].condomain = tyinfo;
 
4866
                constrinfo[i].contype = 'c';
 
4867
                constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
 
4868
                constrinfo[i].confrelid = InvalidOid;
 
4869
                constrinfo[i].conindex = 0;
 
4870
                constrinfo[i].condeferrable = false;
 
4871
                constrinfo[i].condeferred = false;
 
4872
                constrinfo[i].conislocal = true;
 
4873
                constrinfo[i].separate = false;
 
4874
 
 
4875
                /*
 
4876
                 * Make the domain depend on the constraint, ensuring it won't be
 
4877
                 * output till any constraint dependencies are OK.
 
4878
                 */
 
4879
                addObjectDependency(&tyinfo->dobj,
 
4880
                                                        constrinfo[i].dobj.dumpId);
 
4881
        }
 
4882
 
 
4883
        PQclear(res);
 
4884
 
 
4885
        destroyPQExpBuffer(query);
 
4886
}
 
4887
 
 
4888
/*
 
4889
 * getRules
 
4890
 *        get basic information about every rule in the system
 
4891
 *
 
4892
 * numRules is set to the number of rules read in
 
4893
 */
 
4894
RuleInfo *
 
4895
getRules(int *numRules)
 
4896
{
 
4897
        PGresult   *res;
 
4898
        int                     ntups;
 
4899
        int                     i;
 
4900
        PQExpBuffer query = createPQExpBuffer();
 
4901
        RuleInfo   *ruleinfo;
 
4902
        int                     i_tableoid;
 
4903
        int                     i_oid;
 
4904
        int                     i_rulename;
 
4905
        int                     i_ruletable;
 
4906
        int                     i_ev_type;
 
4907
        int                     i_is_instead;
 
4908
        int                     i_ev_enabled;
 
4909
 
 
4910
        /* Make sure we are in proper schema */
 
4911
        selectSourceSchema("pg_catalog");
 
4912
 
 
4913
        if (g_fout->remoteVersion >= 80300)
 
4914
        {
 
4915
                appendPQExpBuffer(query, "SELECT "
 
4916
                                                  "tableoid, oid, rulename, "
 
4917
                                                  "ev_class AS ruletable, ev_type, is_instead, "
 
4918
                                                  "ev_enabled "
 
4919
                                                  "FROM pg_rewrite "
 
4920
                                                  "ORDER BY oid");
 
4921
        }
 
4922
        else if (g_fout->remoteVersion >= 70100)
 
4923
        {
 
4924
                appendPQExpBuffer(query, "SELECT "
 
4925
                                                  "tableoid, oid, rulename, "
 
4926
                                                  "ev_class AS ruletable, ev_type, is_instead, "
 
4927
                                                  "'O'::char AS ev_enabled "
 
4928
                                                  "FROM pg_rewrite "
 
4929
                                                  "ORDER BY oid");
 
4930
        }
 
4931
        else
 
4932
        {
 
4933
                appendPQExpBuffer(query, "SELECT "
 
4934
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
 
4935
                                                  "oid, rulename, "
 
4936
                                                  "ev_class AS ruletable, ev_type, is_instead, "
 
4937
                                                  "'O'::char AS ev_enabled "
 
4938
                                                  "FROM pg_rewrite "
 
4939
                                                  "ORDER BY oid");
 
4940
        }
 
4941
 
 
4942
        res = PQexec(g_conn, query->data);
 
4943
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
4944
 
 
4945
        ntups = PQntuples(res);
 
4946
 
 
4947
        *numRules = ntups;
 
4948
 
 
4949
        ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
 
4950
 
 
4951
        i_tableoid = PQfnumber(res, "tableoid");
 
4952
        i_oid = PQfnumber(res, "oid");
 
4953
        i_rulename = PQfnumber(res, "rulename");
 
4954
        i_ruletable = PQfnumber(res, "ruletable");
 
4955
        i_ev_type = PQfnumber(res, "ev_type");
 
4956
        i_is_instead = PQfnumber(res, "is_instead");
 
4957
        i_ev_enabled = PQfnumber(res, "ev_enabled");
 
4958
 
 
4959
        for (i = 0; i < ntups; i++)
 
4960
        {
 
4961
                Oid                     ruletableoid;
 
4962
 
 
4963
                ruleinfo[i].dobj.objType = DO_RULE;
 
4964
                ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
4965
                ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
4966
                AssignDumpId(&ruleinfo[i].dobj);
 
4967
                ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
 
4968
                ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
 
4969
                ruleinfo[i].ruletable = findTableByOid(ruletableoid);
 
4970
                if (ruleinfo[i].ruletable == NULL)
 
4971
                {
 
4972
                        write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
 
4973
                                          ruletableoid,
 
4974
                                          ruleinfo[i].dobj.catId.oid);
 
4975
                        exit_nicely();
 
4976
                }
 
4977
                ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
 
4978
                ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
 
4979
                ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
 
4980
                ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
 
4981
                ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
 
4982
                if (ruleinfo[i].ruletable)
 
4983
                {
 
4984
                        /*
 
4985
                         * If the table is a view, force its ON SELECT rule to be sorted
 
4986
                         * before the view itself --- this ensures that any dependencies
 
4987
                         * for the rule affect the table's positioning. Other rules are
 
4988
                         * forced to appear after their table.
 
4989
                         */
 
4990
                        if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
 
4991
                                ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
 
4992
                        {
 
4993
                                addObjectDependency(&ruleinfo[i].ruletable->dobj,
 
4994
                                                                        ruleinfo[i].dobj.dumpId);
 
4995
                                /* We'll merge the rule into CREATE VIEW, if possible */
 
4996
                                ruleinfo[i].separate = false;
 
4997
                        }
 
4998
                        else
 
4999
                        {
 
5000
                                addObjectDependency(&ruleinfo[i].dobj,
 
5001
                                                                        ruleinfo[i].ruletable->dobj.dumpId);
 
5002
                                ruleinfo[i].separate = true;
 
5003
                        }
 
5004
                }
 
5005
                else
 
5006
                        ruleinfo[i].separate = true;
 
5007
        }
 
5008
 
 
5009
        PQclear(res);
 
5010
 
 
5011
        destroyPQExpBuffer(query);
 
5012
 
 
5013
        return ruleinfo;
 
5014
}
 
5015
 
 
5016
/*
 
5017
 * getTriggers
 
5018
 *        get information about every trigger on a dumpable table
 
5019
 *
 
5020
 * Note: trigger data is not returned directly to the caller, but it
 
5021
 * does get entered into the DumpableObject tables.
 
5022
 */
 
5023
void
 
5024
getTriggers(TableInfo tblinfo[], int numTables)
 
5025
{
 
5026
        int                     i,
 
5027
                                j;
 
5028
        PQExpBuffer query = createPQExpBuffer();
 
5029
        PGresult   *res;
 
5030
        TriggerInfo *tginfo;
 
5031
        int                     i_tableoid,
 
5032
                                i_oid,
 
5033
                                i_tgname,
 
5034
                                i_tgfname,
 
5035
                                i_tgtype,
 
5036
                                i_tgnargs,
 
5037
                                i_tgargs,
 
5038
                                i_tgisconstraint,
 
5039
                                i_tgconstrname,
 
5040
                                i_tgconstrrelid,
 
5041
                                i_tgconstrrelname,
 
5042
                                i_tgenabled,
 
5043
                                i_tgdeferrable,
 
5044
                                i_tginitdeferred,
 
5045
                                i_tgdef;
 
5046
        int                     ntups;
 
5047
 
 
5048
        for (i = 0; i < numTables; i++)
 
5049
        {
 
5050
                TableInfo  *tbinfo = &tblinfo[i];
 
5051
 
 
5052
                if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
 
5053
                        continue;
 
5054
 
 
5055
                if (g_verbose)
 
5056
                        write_msg(NULL, "reading triggers for table \"%s\"\n",
 
5057
                                          tbinfo->dobj.name);
 
5058
 
 
5059
                /*
 
5060
                 * select table schema to ensure regproc name is qualified if needed
 
5061
                 */
 
5062
                selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
5063
 
 
5064
                resetPQExpBuffer(query);
 
5065
                if (g_fout->remoteVersion >= 90000)
 
5066
                {
 
5067
                        /*
 
5068
                         * NB: think not to use pretty=true in pg_get_triggerdef.  It
 
5069
                         * could result in non-forward-compatible dumps of WHEN clauses
 
5070
                         * due to under-parenthesization.
 
5071
                         */
 
5072
                        appendPQExpBuffer(query,
 
5073
                                                          "SELECT tgname, "
 
5074
                                                          "tgfoid::pg_catalog.regproc AS tgfname, "
 
5075
                                                "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
 
5076
                                                          "tgenabled, tableoid, oid "
 
5077
                                                          "FROM pg_catalog.pg_trigger t "
 
5078
                                                          "WHERE tgrelid = '%u'::pg_catalog.oid "
 
5079
                                                          "AND NOT tgisinternal",
 
5080
                                                          tbinfo->dobj.catId.oid);
 
5081
                }
 
5082
                else if (g_fout->remoteVersion >= 80300)
 
5083
                {
 
5084
                        /*
 
5085
                         * We ignore triggers that are tied to a foreign-key constraint
 
5086
                         */
 
5087
                        appendPQExpBuffer(query,
 
5088
                                                          "SELECT tgname, "
 
5089
                                                          "tgfoid::pg_catalog.regproc AS tgfname, "
 
5090
                                                          "tgtype, tgnargs, tgargs, tgenabled, "
 
5091
                                                          "tgisconstraint, tgconstrname, tgdeferrable, "
 
5092
                                                          "tgconstrrelid, tginitdeferred, tableoid, oid, "
 
5093
                                         "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
 
5094
                                                          "FROM pg_catalog.pg_trigger t "
 
5095
                                                          "WHERE tgrelid = '%u'::pg_catalog.oid "
 
5096
                                                          "AND tgconstraint = 0",
 
5097
                                                          tbinfo->dobj.catId.oid);
 
5098
                }
 
5099
                else if (g_fout->remoteVersion >= 70300)
 
5100
                {
 
5101
                        /*
 
5102
                         * We ignore triggers that are tied to a foreign-key constraint,
 
5103
                         * but in these versions we have to grovel through pg_constraint
 
5104
                         * to find out
 
5105
                         */
 
5106
                        appendPQExpBuffer(query,
 
5107
                                                          "SELECT tgname, "
 
5108
                                                          "tgfoid::pg_catalog.regproc AS tgfname, "
 
5109
                                                          "tgtype, tgnargs, tgargs, tgenabled, "
 
5110
                                                          "tgisconstraint, tgconstrname, tgdeferrable, "
 
5111
                                                          "tgconstrrelid, tginitdeferred, tableoid, oid, "
 
5112
                                         "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
 
5113
                                                          "FROM pg_catalog.pg_trigger t "
 
5114
                                                          "WHERE tgrelid = '%u'::pg_catalog.oid "
 
5115
                                                          "AND (NOT tgisconstraint "
 
5116
                                                          " OR NOT EXISTS"
 
5117
                                                          "  (SELECT 1 FROM pg_catalog.pg_depend d "
 
5118
                                                          "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
 
5119
                                                          "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
 
5120
                                                          tbinfo->dobj.catId.oid);
 
5121
                }
 
5122
                else if (g_fout->remoteVersion >= 70100)
 
5123
                {
 
5124
                        appendPQExpBuffer(query,
 
5125
                                                          "SELECT tgname, tgfoid::regproc AS tgfname, "
 
5126
                                                          "tgtype, tgnargs, tgargs, tgenabled, "
 
5127
                                                          "tgisconstraint, tgconstrname, tgdeferrable, "
 
5128
                                                          "tgconstrrelid, tginitdeferred, tableoid, oid, "
 
5129
                                  "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
 
5130
                                                          "             AS tgconstrrelname "
 
5131
                                                          "FROM pg_trigger "
 
5132
                                                          "WHERE tgrelid = '%u'::oid",
 
5133
                                                          tbinfo->dobj.catId.oid);
 
5134
                }
 
5135
                else
 
5136
                {
 
5137
                        appendPQExpBuffer(query,
 
5138
                                                          "SELECT tgname, tgfoid::regproc AS tgfname, "
 
5139
                                                          "tgtype, tgnargs, tgargs, tgenabled, "
 
5140
                                                          "tgisconstraint, tgconstrname, tgdeferrable, "
 
5141
                                                          "tgconstrrelid, tginitdeferred, "
 
5142
                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
 
5143
                                                          "oid, "
 
5144
                                  "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
 
5145
                                                          "             AS tgconstrrelname "
 
5146
                                                          "FROM pg_trigger "
 
5147
                                                          "WHERE tgrelid = '%u'::oid",
 
5148
                                                          tbinfo->dobj.catId.oid);
 
5149
                }
 
5150
                res = PQexec(g_conn, query->data);
 
5151
                check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
5152
 
 
5153
                ntups = PQntuples(res);
 
5154
 
 
5155
                i_tableoid = PQfnumber(res, "tableoid");
 
5156
                i_oid = PQfnumber(res, "oid");
 
5157
                i_tgname = PQfnumber(res, "tgname");
 
5158
                i_tgfname = PQfnumber(res, "tgfname");
 
5159
                i_tgtype = PQfnumber(res, "tgtype");
 
5160
                i_tgnargs = PQfnumber(res, "tgnargs");
 
5161
                i_tgargs = PQfnumber(res, "tgargs");
 
5162
                i_tgisconstraint = PQfnumber(res, "tgisconstraint");
 
5163
                i_tgconstrname = PQfnumber(res, "tgconstrname");
 
5164
                i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
 
5165
                i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
 
5166
                i_tgenabled = PQfnumber(res, "tgenabled");
 
5167
                i_tgdeferrable = PQfnumber(res, "tgdeferrable");
 
5168
                i_tginitdeferred = PQfnumber(res, "tginitdeferred");
 
5169
                i_tgdef = PQfnumber(res, "tgdef");
 
5170
 
 
5171
                tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
 
5172
 
 
5173
                for (j = 0; j < ntups; j++)
 
5174
                {
 
5175
                        tginfo[j].dobj.objType = DO_TRIGGER;
 
5176
                        tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
 
5177
                        tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
 
5178
                        AssignDumpId(&tginfo[j].dobj);
 
5179
                        tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
 
5180
                        tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
 
5181
                        tginfo[j].tgtable = tbinfo;
 
5182
                        tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
 
5183
                        if (i_tgdef >= 0)
 
5184
                        {
 
5185
                                tginfo[j].tgdef = strdup(PQgetvalue(res, j, i_tgdef));
 
5186
 
 
5187
                                /* remaining fields are not valid if we have tgdef */
 
5188
                                tginfo[j].tgfname = NULL;
 
5189
                                tginfo[j].tgtype = 0;
 
5190
                                tginfo[j].tgnargs = 0;
 
5191
                                tginfo[j].tgargs = NULL;
 
5192
                                tginfo[j].tgisconstraint = false;
 
5193
                                tginfo[j].tgdeferrable = false;
 
5194
                                tginfo[j].tginitdeferred = false;
 
5195
                                tginfo[j].tgconstrname = NULL;
 
5196
                                tginfo[j].tgconstrrelid = InvalidOid;
 
5197
                                tginfo[j].tgconstrrelname = NULL;
 
5198
                        }
 
5199
                        else
 
5200
                        {
 
5201
                                tginfo[j].tgdef = NULL;
 
5202
 
 
5203
                                tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
 
5204
                                tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
 
5205
                                tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
 
5206
                                tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
 
5207
                                tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
 
5208
                                tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
 
5209
                                tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
 
5210
 
 
5211
                                if (tginfo[j].tgisconstraint)
 
5212
                                {
 
5213
                                        tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
 
5214
                                        tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
 
5215
                                        if (OidIsValid(tginfo[j].tgconstrrelid))
 
5216
                                        {
 
5217
                                                if (PQgetisnull(res, j, i_tgconstrrelname))
 
5218
                                                {
 
5219
                                                        write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
 
5220
                                                                          tginfo[j].dobj.name, tbinfo->dobj.name,
 
5221
                                                                          tginfo[j].tgconstrrelid);
 
5222
                                                        exit_nicely();
 
5223
                                                }
 
5224
                                                tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
 
5225
                                        }
 
5226
                                        else
 
5227
                                                tginfo[j].tgconstrrelname = NULL;
 
5228
                                }
 
5229
                                else
 
5230
                                {
 
5231
                                        tginfo[j].tgconstrname = NULL;
 
5232
                                        tginfo[j].tgconstrrelid = InvalidOid;
 
5233
                                        tginfo[j].tgconstrrelname = NULL;
 
5234
                                }
 
5235
                        }
 
5236
                }
 
5237
 
 
5238
                PQclear(res);
 
5239
        }
 
5240
 
 
5241
        destroyPQExpBuffer(query);
 
5242
}
 
5243
 
 
5244
/*
 
5245
 * getProcLangs
 
5246
 *        get basic information about every procedural language in the system
 
5247
 *
 
5248
 * numProcLangs is set to the number of langs read in
 
5249
 *
 
5250
 * NB: this must run after getFuncs() because we assume we can do
 
5251
 * findFuncByOid().
 
5252
 */
 
5253
ProcLangInfo *
 
5254
getProcLangs(int *numProcLangs)
 
5255
{
 
5256
        PGresult   *res;
 
5257
        int                     ntups;
 
5258
        int                     i;
 
5259
        PQExpBuffer query = createPQExpBuffer();
 
5260
        ProcLangInfo *planginfo;
 
5261
        int                     i_tableoid;
 
5262
        int                     i_oid;
 
5263
        int                     i_lanname;
 
5264
        int                     i_lanpltrusted;
 
5265
        int                     i_lanplcallfoid;
 
5266
        int                     i_laninline;
 
5267
        int                     i_lanvalidator;
 
5268
        int                     i_lanacl;
 
5269
        int                     i_lanowner;
 
5270
 
 
5271
        /* Make sure we are in proper schema */
 
5272
        selectSourceSchema("pg_catalog");
 
5273
 
 
5274
        if (g_fout->remoteVersion >= 90000)
 
5275
        {
 
5276
                /* pg_language has a laninline column */
 
5277
                appendPQExpBuffer(query, "SELECT tableoid, oid, "
 
5278
                                                  "lanname, lanpltrusted, lanplcallfoid, "
 
5279
                                                  "laninline, lanvalidator,  lanacl, "
 
5280
                                                  "(%s lanowner) AS lanowner "
 
5281
                                                  "FROM pg_language "
 
5282
                                                  "WHERE lanispl "
 
5283
                                                  "ORDER BY oid",
 
5284
                                                  username_subquery);
 
5285
        }
 
5286
        else if (g_fout->remoteVersion >= 80300)
 
5287
        {
 
5288
                /* pg_language has a lanowner column */
 
5289
                appendPQExpBuffer(query, "SELECT tableoid, oid, "
 
5290
                                                  "lanname, lanpltrusted, lanplcallfoid, "
 
5291
                                                  "lanvalidator,  lanacl, "
 
5292
                                                  "(%s lanowner) AS lanowner "
 
5293
                                                  "FROM pg_language "
 
5294
                                                  "WHERE lanispl "
 
5295
                                                  "ORDER BY oid",
 
5296
                                                  username_subquery);
 
5297
        }
 
5298
        else if (g_fout->remoteVersion >= 80100)
 
5299
        {
 
5300
                /* Languages are owned by the bootstrap superuser, OID 10 */
 
5301
                appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
 
5302
                                                  "(%s '10') AS lanowner "
 
5303
                                                  "FROM pg_language "
 
5304
                                                  "WHERE lanispl "
 
5305
                                                  "ORDER BY oid",
 
5306
                                                  username_subquery);
 
5307
        }
 
5308
        else if (g_fout->remoteVersion >= 70400)
 
5309
        {
 
5310
                /* Languages are owned by the bootstrap superuser, sysid 1 */
 
5311
                appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
 
5312
                                                  "(%s '1') AS lanowner "
 
5313
                                                  "FROM pg_language "
 
5314
                                                  "WHERE lanispl "
 
5315
                                                  "ORDER BY oid",
 
5316
                                                  username_subquery);
 
5317
        }
 
5318
        else if (g_fout->remoteVersion >= 70100)
 
5319
        {
 
5320
                /* No clear notion of an owner at all before 7.4 ... */
 
5321
                appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
 
5322
                                                  "WHERE lanispl "
 
5323
                                                  "ORDER BY oid");
 
5324
        }
 
5325
        else
 
5326
        {
 
5327
                appendPQExpBuffer(query, "SELECT "
 
5328
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
 
5329
                                                  "oid, * FROM pg_language "
 
5330
                                                  "WHERE lanispl "
 
5331
                                                  "ORDER BY oid");
 
5332
        }
 
5333
 
 
5334
        res = PQexec(g_conn, query->data);
 
5335
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
5336
 
 
5337
        ntups = PQntuples(res);
 
5338
 
 
5339
        *numProcLangs = ntups;
 
5340
 
 
5341
        planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
 
5342
 
 
5343
        i_tableoid = PQfnumber(res, "tableoid");
 
5344
        i_oid = PQfnumber(res, "oid");
 
5345
        i_lanname = PQfnumber(res, "lanname");
 
5346
        i_lanpltrusted = PQfnumber(res, "lanpltrusted");
 
5347
        i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
 
5348
        /* these may fail and return -1: */
 
5349
        i_laninline = PQfnumber(res, "laninline");
 
5350
        i_lanvalidator = PQfnumber(res, "lanvalidator");
 
5351
        i_lanacl = PQfnumber(res, "lanacl");
 
5352
        i_lanowner = PQfnumber(res, "lanowner");
 
5353
 
 
5354
        for (i = 0; i < ntups; i++)
 
5355
        {
 
5356
                planginfo[i].dobj.objType = DO_PROCLANG;
 
5357
                planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
5358
                planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
5359
                AssignDumpId(&planginfo[i].dobj);
 
5360
 
 
5361
                planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
 
5362
                planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
 
5363
                planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
 
5364
                if (i_laninline >= 0)
 
5365
                        planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
 
5366
                else
 
5367
                        planginfo[i].laninline = InvalidOid;
 
5368
                if (i_lanvalidator >= 0)
 
5369
                        planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
 
5370
                else
 
5371
                        planginfo[i].lanvalidator = InvalidOid;
 
5372
                if (i_lanacl >= 0)
 
5373
                        planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
 
5374
                else
 
5375
                        planginfo[i].lanacl = strdup("{=U}");
 
5376
                if (i_lanowner >= 0)
 
5377
                        planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
 
5378
                else
 
5379
                        planginfo[i].lanowner = strdup("");
 
5380
 
 
5381
                if (g_fout->remoteVersion < 70300)
 
5382
                {
 
5383
                        /*
 
5384
                         * We need to make a dependency to ensure the function will be
 
5385
                         * dumped first.  (In 7.3 and later the regular dependency
 
5386
                         * mechanism will handle this for us.)
 
5387
                         */
 
5388
                        FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
 
5389
 
 
5390
                        if (funcInfo)
 
5391
                                addObjectDependency(&planginfo[i].dobj,
 
5392
                                                                        funcInfo->dobj.dumpId);
 
5393
                }
 
5394
        }
 
5395
 
 
5396
        PQclear(res);
 
5397
 
 
5398
        destroyPQExpBuffer(query);
 
5399
 
 
5400
        return planginfo;
 
5401
}
 
5402
 
 
5403
/*
 
5404
 * getCasts
 
5405
 *        get basic information about every cast in the system
 
5406
 *
 
5407
 * numCasts is set to the number of casts read in
 
5408
 */
 
5409
CastInfo *
 
5410
getCasts(int *numCasts)
 
5411
{
 
5412
        PGresult   *res;
 
5413
        int                     ntups;
 
5414
        int                     i;
 
5415
        PQExpBuffer query = createPQExpBuffer();
 
5416
        CastInfo   *castinfo;
 
5417
        int                     i_tableoid;
 
5418
        int                     i_oid;
 
5419
        int                     i_castsource;
 
5420
        int                     i_casttarget;
 
5421
        int                     i_castfunc;
 
5422
        int                     i_castcontext;
 
5423
        int                     i_castmethod;
 
5424
 
 
5425
        /* Make sure we are in proper schema */
 
5426
        selectSourceSchema("pg_catalog");
 
5427
 
 
5428
        if (g_fout->remoteVersion >= 80400)
 
5429
        {
 
5430
                appendPQExpBuffer(query, "SELECT tableoid, oid, "
 
5431
                                                  "castsource, casttarget, castfunc, castcontext, "
 
5432
                                                  "castmethod "
 
5433
                                                  "FROM pg_cast ORDER BY 3,4");
 
5434
        }
 
5435
        else if (g_fout->remoteVersion >= 70300)
 
5436
        {
 
5437
                appendPQExpBuffer(query, "SELECT tableoid, oid, "
 
5438
                                                  "castsource, casttarget, castfunc, castcontext, "
 
5439
                                "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
 
5440
                                                  "FROM pg_cast ORDER BY 3,4");
 
5441
        }
 
5442
        else
 
5443
        {
 
5444
                appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
 
5445
                                                  "t1.oid AS castsource, t2.oid AS casttarget, "
 
5446
                                                  "p.oid AS castfunc, 'e' AS castcontext, "
 
5447
                                                  "'f' AS castmethod "
 
5448
                                                  "FROM pg_type t1, pg_type t2, pg_proc p "
 
5449
                                                  "WHERE p.pronargs = 1 AND "
 
5450
                                                  "p.proargtypes[0] = t1.oid AND "
 
5451
                                                  "p.prorettype = t2.oid AND p.proname = t2.typname "
 
5452
                                                  "ORDER BY 3,4");
 
5453
        }
 
5454
 
 
5455
        res = PQexec(g_conn, query->data);
 
5456
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
5457
 
 
5458
        ntups = PQntuples(res);
 
5459
 
 
5460
        *numCasts = ntups;
 
5461
 
 
5462
        castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
 
5463
 
 
5464
        i_tableoid = PQfnumber(res, "tableoid");
 
5465
        i_oid = PQfnumber(res, "oid");
 
5466
        i_castsource = PQfnumber(res, "castsource");
 
5467
        i_casttarget = PQfnumber(res, "casttarget");
 
5468
        i_castfunc = PQfnumber(res, "castfunc");
 
5469
        i_castcontext = PQfnumber(res, "castcontext");
 
5470
        i_castmethod = PQfnumber(res, "castmethod");
 
5471
 
 
5472
        for (i = 0; i < ntups; i++)
 
5473
        {
 
5474
                PQExpBufferData namebuf;
 
5475
                TypeInfo   *sTypeInfo;
 
5476
                TypeInfo   *tTypeInfo;
 
5477
 
 
5478
                castinfo[i].dobj.objType = DO_CAST;
 
5479
                castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
5480
                castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
5481
                AssignDumpId(&castinfo[i].dobj);
 
5482
                castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
 
5483
                castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
 
5484
                castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
 
5485
                castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
 
5486
                castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
 
5487
 
 
5488
                /*
 
5489
                 * Try to name cast as concatenation of typnames.  This is only used
 
5490
                 * for purposes of sorting.  If we fail to find either type, the name
 
5491
                 * will be an empty string.
 
5492
                 */
 
5493
                initPQExpBuffer(&namebuf);
 
5494
                sTypeInfo = findTypeByOid(castinfo[i].castsource);
 
5495
                tTypeInfo = findTypeByOid(castinfo[i].casttarget);
 
5496
                if (sTypeInfo && tTypeInfo)
 
5497
                        appendPQExpBuffer(&namebuf, "%s %s",
 
5498
                                                          sTypeInfo->dobj.name, tTypeInfo->dobj.name);
 
5499
                castinfo[i].dobj.name = namebuf.data;
 
5500
 
 
5501
                if (OidIsValid(castinfo[i].castfunc))
 
5502
                {
 
5503
                        /*
 
5504
                         * We need to make a dependency to ensure the function will be
 
5505
                         * dumped first.  (In 7.3 and later the regular dependency
 
5506
                         * mechanism will handle this for us.)
 
5507
                         */
 
5508
                        FuncInfo   *funcInfo;
 
5509
 
 
5510
                        funcInfo = findFuncByOid(castinfo[i].castfunc);
 
5511
                        if (funcInfo)
 
5512
                                addObjectDependency(&castinfo[i].dobj,
 
5513
                                                                        funcInfo->dobj.dumpId);
 
5514
                }
 
5515
        }
 
5516
 
 
5517
        PQclear(res);
 
5518
 
 
5519
        destroyPQExpBuffer(query);
 
5520
 
 
5521
        return castinfo;
 
5522
}
 
5523
 
 
5524
/*
 
5525
 * getTableAttrs -
 
5526
 *        for each interesting table, read info about its attributes
 
5527
 *        (names, types, default values, CHECK constraints, etc)
 
5528
 *
 
5529
 * This is implemented in a very inefficient way right now, looping
 
5530
 * through the tblinfo and doing a join per table to find the attrs and their
 
5531
 * types.  However, because we want type names and so forth to be named
 
5532
 * relative to the schema of each table, we couldn't do it in just one
 
5533
 * query.  (Maybe one query per schema?)
 
5534
 *
 
5535
 *      modifies tblinfo
 
5536
 */
 
5537
void
 
5538
getTableAttrs(TableInfo *tblinfo, int numTables)
 
5539
{
 
5540
        int                     i,
 
5541
                                j;
 
5542
        PQExpBuffer q = createPQExpBuffer();
 
5543
        int                     i_attnum;
 
5544
        int                     i_attname;
 
5545
        int                     i_atttypname;
 
5546
        int                     i_atttypmod;
 
5547
        int                     i_attstattarget;
 
5548
        int                     i_attstorage;
 
5549
        int                     i_typstorage;
 
5550
        int                     i_attnotnull;
 
5551
        int                     i_atthasdef;
 
5552
        int                     i_attisdropped;
 
5553
        int                     i_attlen;
 
5554
        int                     i_attalign;
 
5555
        int                     i_attislocal;
 
5556
        int                     i_attoptions;
 
5557
        int                     i_attcollation;
 
5558
        PGresult   *res;
 
5559
        int                     ntups;
 
5560
        bool            hasdefaults;
 
5561
 
 
5562
        for (i = 0; i < numTables; i++)
 
5563
        {
 
5564
                TableInfo  *tbinfo = &tblinfo[i];
 
5565
 
 
5566
                /* Don't bother to collect info for sequences */
 
5567
                if (tbinfo->relkind == RELKIND_SEQUENCE)
 
5568
                        continue;
 
5569
 
 
5570
                /* Don't bother with uninteresting tables, either */
 
5571
                if (!tbinfo->interesting)
 
5572
                        continue;
 
5573
 
 
5574
                /*
 
5575
                 * Make sure we are in proper schema for this table; this allows
 
5576
                 * correct retrieval of formatted type names and default exprs
 
5577
                 */
 
5578
                selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
5579
 
 
5580
                /* find all the user attributes and their types */
 
5581
 
 
5582
                /*
 
5583
                 * we must read the attribute names in attribute number order! because
 
5584
                 * we will use the attnum to index into the attnames array later.  We
 
5585
                 * actually ask to order by "attrelid, attnum" because (at least up to
 
5586
                 * 7.3) the planner is not smart enough to realize it needn't re-sort
 
5587
                 * the output of an indexscan on pg_attribute_relid_attnum_index.
 
5588
                 */
 
5589
                if (g_verbose)
 
5590
                        write_msg(NULL, "finding the columns and types of table \"%s\"\n",
 
5591
                                          tbinfo->dobj.name);
 
5592
 
 
5593
                resetPQExpBuffer(q);
 
5594
 
 
5595
                if (g_fout->remoteVersion >= 90100)
 
5596
                {
 
5597
                        /*
 
5598
                         * attcollation is new in 9.1.  Since we only want to dump COLLATE
 
5599
                         * clauses for attributes whose collation is different from their
 
5600
                         * type's default, we use a CASE here to suppress uninteresting
 
5601
                         * attcollations cheaply.
 
5602
                         */
 
5603
                        appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
 
5604
                                                          "a.attstattarget, a.attstorage, t.typstorage, "
 
5605
                                                          "a.attnotnull, a.atthasdef, a.attisdropped, "
 
5606
                                                          "a.attlen, a.attalign, a.attislocal, "
 
5607
                                  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
 
5608
                                                "array_to_string(a.attoptions, ', ') AS attoptions, "
 
5609
                                                          "CASE WHEN a.attcollation <> t.typcollation "
 
5610
                                                        "THEN a.attcollation ELSE 0 END AS attcollation "
 
5611
                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
 
5612
                                                          "ON a.atttypid = t.oid "
 
5613
                                                          "WHERE a.attrelid = '%u'::pg_catalog.oid "
 
5614
                                                          "AND a.attnum > 0::pg_catalog.int2 "
 
5615
                                                          "ORDER BY a.attrelid, a.attnum",
 
5616
                                                          tbinfo->dobj.catId.oid);
 
5617
                }
 
5618
                else if (g_fout->remoteVersion >= 90000)
 
5619
                {
 
5620
                        /* attoptions is new in 9.0 */
 
5621
                        appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
 
5622
                                                          "a.attstattarget, a.attstorage, t.typstorage, "
 
5623
                                                          "a.attnotnull, a.atthasdef, a.attisdropped, "
 
5624
                                                          "a.attlen, a.attalign, a.attislocal, "
 
5625
                                  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
 
5626
                                                "array_to_string(a.attoptions, ', ') AS attoptions, "
 
5627
                                                          "0 AS attcollation "
 
5628
                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
 
5629
                                                          "ON a.atttypid = t.oid "
 
5630
                                                          "WHERE a.attrelid = '%u'::pg_catalog.oid "
 
5631
                                                          "AND a.attnum > 0::pg_catalog.int2 "
 
5632
                                                          "ORDER BY a.attrelid, a.attnum",
 
5633
                                                          tbinfo->dobj.catId.oid);
 
5634
                }
 
5635
                else if (g_fout->remoteVersion >= 70300)
 
5636
                {
 
5637
                        /* need left join here to not fail on dropped columns ... */
 
5638
                        appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
 
5639
                                                          "a.attstattarget, a.attstorage, t.typstorage, "
 
5640
                                                          "a.attnotnull, a.atthasdef, a.attisdropped, "
 
5641
                                                          "a.attlen, a.attalign, a.attislocal, "
 
5642
                                  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
 
5643
                                                          "'' AS attoptions, 0 AS attcollation "
 
5644
                         "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
 
5645
                                                          "ON a.atttypid = t.oid "
 
5646
                                                          "WHERE a.attrelid = '%u'::pg_catalog.oid "
 
5647
                                                          "AND a.attnum > 0::pg_catalog.int2 "
 
5648
                                                          "ORDER BY a.attrelid, a.attnum",
 
5649
                                                          tbinfo->dobj.catId.oid);
 
5650
                }
 
5651
                else if (g_fout->remoteVersion >= 70100)
 
5652
                {
 
5653
                        /*
 
5654
                         * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
 
5655
                         * we don't dump it because we can't tell whether it's been
 
5656
                         * explicitly set or was just a default.
 
5657
                         */
 
5658
                        appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
 
5659
                                                          "-1 AS attstattarget, a.attstorage, "
 
5660
                                                          "t.typstorage, a.attnotnull, a.atthasdef, "
 
5661
                                                          "false AS attisdropped, a.attlen, "
 
5662
                                                          "a.attalign, false AS attislocal, "
 
5663
                                                          "format_type(t.oid,a.atttypmod) AS atttypname, "
 
5664
                                                          "'' AS attoptions, 0 AS attcollation "
 
5665
                                                          "FROM pg_attribute a LEFT JOIN pg_type t "
 
5666
                                                          "ON a.atttypid = t.oid "
 
5667
                                                          "WHERE a.attrelid = '%u'::oid "
 
5668
                                                          "AND a.attnum > 0::int2 "
 
5669
                                                          "ORDER BY a.attrelid, a.attnum",
 
5670
                                                          tbinfo->dobj.catId.oid);
 
5671
                }
 
5672
                else
 
5673
                {
 
5674
                        /* format_type not available before 7.1 */
 
5675
                        appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
 
5676
                                                          "-1 AS attstattarget, "
 
5677
                                                          "attstorage, attstorage AS typstorage, "
 
5678
                                                          "attnotnull, atthasdef, false AS attisdropped, "
 
5679
                                                          "attlen, attalign, "
 
5680
                                                          "false AS attislocal, "
 
5681
                                                          "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
 
5682
                                                          "'' AS attoptions, 0 AS attcollation "
 
5683
                                                          "FROM pg_attribute a "
 
5684
                                                          "WHERE attrelid = '%u'::oid "
 
5685
                                                          "AND attnum > 0::int2 "
 
5686
                                                          "ORDER BY attrelid, attnum",
 
5687
                                                          tbinfo->dobj.catId.oid);
 
5688
                }
 
5689
 
 
5690
                res = PQexec(g_conn, q->data);
 
5691
                check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
 
5692
 
 
5693
                ntups = PQntuples(res);
 
5694
 
 
5695
                i_attnum = PQfnumber(res, "attnum");
 
5696
                i_attname = PQfnumber(res, "attname");
 
5697
                i_atttypname = PQfnumber(res, "atttypname");
 
5698
                i_atttypmod = PQfnumber(res, "atttypmod");
 
5699
                i_attstattarget = PQfnumber(res, "attstattarget");
 
5700
                i_attstorage = PQfnumber(res, "attstorage");
 
5701
                i_typstorage = PQfnumber(res, "typstorage");
 
5702
                i_attnotnull = PQfnumber(res, "attnotnull");
 
5703
                i_atthasdef = PQfnumber(res, "atthasdef");
 
5704
                i_attisdropped = PQfnumber(res, "attisdropped");
 
5705
                i_attlen = PQfnumber(res, "attlen");
 
5706
                i_attalign = PQfnumber(res, "attalign");
 
5707
                i_attislocal = PQfnumber(res, "attislocal");
 
5708
                i_attoptions = PQfnumber(res, "attoptions");
 
5709
                i_attcollation = PQfnumber(res, "attcollation");
 
5710
 
 
5711
                tbinfo->numatts = ntups;
 
5712
                tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
 
5713
                tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
 
5714
                tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
 
5715
                tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
 
5716
                tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
 
5717
                tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
 
5718
                tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
 
5719
                tbinfo->attlen = (int *) malloc(ntups * sizeof(int));
 
5720
                tbinfo->attalign = (char *) malloc(ntups * sizeof(char));
 
5721
                tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
 
5722
                tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
 
5723
                tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
 
5724
                tbinfo->attoptions = (char **) malloc(ntups * sizeof(char *));
 
5725
                tbinfo->attcollation = (Oid *) malloc(ntups * sizeof(Oid));
 
5726
                tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
 
5727
                tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
 
5728
                tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
 
5729
                hasdefaults = false;
 
5730
 
 
5731
                for (j = 0; j < ntups; j++)
 
5732
                {
 
5733
                        if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
 
5734
                        {
 
5735
                                write_msg(NULL, "invalid column numbering in table \"%s\"\n",
 
5736
                                                  tbinfo->dobj.name);
 
5737
                                exit_nicely();
 
5738
                        }
 
5739
                        tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
 
5740
                        tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
 
5741
                        tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
 
5742
                        tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
 
5743
                        tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
 
5744
                        tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
 
5745
                        tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
 
5746
                        tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
 
5747
                        tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
 
5748
                        tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
 
5749
                        tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
 
5750
                        tbinfo->attoptions[j] = strdup(PQgetvalue(res, j, i_attoptions));
 
5751
                        tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
 
5752
                        tbinfo->attrdefs[j] = NULL; /* fix below */
 
5753
                        if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
 
5754
                                hasdefaults = true;
 
5755
                        /* these flags will be set in flagInhAttrs() */
 
5756
                        tbinfo->inhAttrs[j] = false;
 
5757
                        tbinfo->inhAttrDef[j] = false;
 
5758
                        tbinfo->inhNotNull[j] = false;
 
5759
                }
 
5760
 
 
5761
                PQclear(res);
 
5762
 
 
5763
                /*
 
5764
                 * Get info about column defaults
 
5765
                 */
 
5766
                if (hasdefaults)
 
5767
                {
 
5768
                        AttrDefInfo *attrdefs;
 
5769
                        int                     numDefaults;
 
5770
 
 
5771
                        if (g_verbose)
 
5772
                                write_msg(NULL, "finding default expressions of table \"%s\"\n",
 
5773
                                                  tbinfo->dobj.name);
 
5774
 
 
5775
                        resetPQExpBuffer(q);
 
5776
                        if (g_fout->remoteVersion >= 70300)
 
5777
                        {
 
5778
                                appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
 
5779
                                                   "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
 
5780
                                                                  "FROM pg_catalog.pg_attrdef "
 
5781
                                                                  "WHERE adrelid = '%u'::pg_catalog.oid",
 
5782
                                                                  tbinfo->dobj.catId.oid);
 
5783
                        }
 
5784
                        else if (g_fout->remoteVersion >= 70200)
 
5785
                        {
 
5786
                                /* 7.2 did not have OIDs in pg_attrdef */
 
5787
                                appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
 
5788
                                                                  "pg_get_expr(adbin, adrelid) AS adsrc "
 
5789
                                                                  "FROM pg_attrdef "
 
5790
                                                                  "WHERE adrelid = '%u'::oid",
 
5791
                                                                  tbinfo->dobj.catId.oid);
 
5792
                        }
 
5793
                        else if (g_fout->remoteVersion >= 70100)
 
5794
                        {
 
5795
                                /* no pg_get_expr, so must rely on adsrc */
 
5796
                                appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
 
5797
                                                                  "FROM pg_attrdef "
 
5798
                                                                  "WHERE adrelid = '%u'::oid",
 
5799
                                                                  tbinfo->dobj.catId.oid);
 
5800
                        }
 
5801
                        else
 
5802
                        {
 
5803
                                /* no pg_get_expr, no tableoid either */
 
5804
                                appendPQExpBuffer(q, "SELECT "
 
5805
                                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
 
5806
                                                                  "oid, adnum, adsrc "
 
5807
                                                                  "FROM pg_attrdef "
 
5808
                                                                  "WHERE adrelid = '%u'::oid",
 
5809
                                                                  tbinfo->dobj.catId.oid);
 
5810
                        }
 
5811
                        res = PQexec(g_conn, q->data);
 
5812
                        check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
 
5813
 
 
5814
                        numDefaults = PQntuples(res);
 
5815
                        attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
 
5816
 
 
5817
                        for (j = 0; j < numDefaults; j++)
 
5818
                        {
 
5819
                                int                     adnum;
 
5820
 
 
5821
                                attrdefs[j].dobj.objType = DO_ATTRDEF;
 
5822
                                attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
 
5823
                                attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
 
5824
                                AssignDumpId(&attrdefs[j].dobj);
 
5825
                                attrdefs[j].adtable = tbinfo;
 
5826
                                attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
 
5827
                                attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
 
5828
 
 
5829
                                attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
 
5830
                                attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
 
5831
 
 
5832
                                attrdefs[j].dobj.dump = tbinfo->dobj.dump;
 
5833
 
 
5834
                                /*
 
5835
                                 * Defaults on a VIEW must always be dumped as separate ALTER
 
5836
                                 * TABLE commands.      Defaults on regular tables are dumped as
 
5837
                                 * part of the CREATE TABLE if possible.  To check if it's
 
5838
                                 * safe, we mark the default as needing to appear before the
 
5839
                                 * CREATE.
 
5840
                                 */
 
5841
                                if (tbinfo->relkind == RELKIND_VIEW)
 
5842
                                {
 
5843
                                        attrdefs[j].separate = true;
 
5844
                                        /* needed in case pre-7.3 DB: */
 
5845
                                        addObjectDependency(&attrdefs[j].dobj,
 
5846
                                                                                tbinfo->dobj.dumpId);
 
5847
                                }
 
5848
                                else
 
5849
                                {
 
5850
                                        attrdefs[j].separate = false;
 
5851
                                        addObjectDependency(&tbinfo->dobj,
 
5852
                                                                                attrdefs[j].dobj.dumpId);
 
5853
                                }
 
5854
 
 
5855
                                if (adnum <= 0 || adnum > ntups)
 
5856
                                {
 
5857
                                        write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
 
5858
                                                          adnum, tbinfo->dobj.name);
 
5859
                                        exit_nicely();
 
5860
                                }
 
5861
                                tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
 
5862
                        }
 
5863
                        PQclear(res);
 
5864
                }
 
5865
 
 
5866
                /*
 
5867
                 * Get info about table CHECK constraints
 
5868
                 */
 
5869
                if (tbinfo->ncheck > 0)
 
5870
                {
 
5871
                        ConstraintInfo *constrs;
 
5872
                        int                     numConstrs;
 
5873
 
 
5874
                        if (g_verbose)
 
5875
                                write_msg(NULL, "finding check constraints for table \"%s\"\n",
 
5876
                                                  tbinfo->dobj.name);
 
5877
 
 
5878
                        resetPQExpBuffer(q);
 
5879
                        if (g_fout->remoteVersion >= 80400)
 
5880
                        {
 
5881
                                appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 
5882
                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
 
5883
                                                                  "conislocal "
 
5884
                                                                  "FROM pg_catalog.pg_constraint "
 
5885
                                                                  "WHERE conrelid = '%u'::pg_catalog.oid "
 
5886
                                                                  "   AND contype = 'c' "
 
5887
                                                                  "ORDER BY conname",
 
5888
                                                                  tbinfo->dobj.catId.oid);
 
5889
                        }
 
5890
                        else if (g_fout->remoteVersion >= 70400)
 
5891
                        {
 
5892
                                appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 
5893
                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
 
5894
                                                                  "true AS conislocal "
 
5895
                                                                  "FROM pg_catalog.pg_constraint "
 
5896
                                                                  "WHERE conrelid = '%u'::pg_catalog.oid "
 
5897
                                                                  "   AND contype = 'c' "
 
5898
                                                                  "ORDER BY conname",
 
5899
                                                                  tbinfo->dobj.catId.oid);
 
5900
                        }
 
5901
                        else if (g_fout->remoteVersion >= 70300)
 
5902
                        {
 
5903
                                /* no pg_get_constraintdef, must use consrc */
 
5904
                                appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
 
5905
                                                                  "'CHECK (' || consrc || ')' AS consrc, "
 
5906
                                                                  "true AS conislocal "
 
5907
                                                                  "FROM pg_catalog.pg_constraint "
 
5908
                                                                  "WHERE conrelid = '%u'::pg_catalog.oid "
 
5909
                                                                  "   AND contype = 'c' "
 
5910
                                                                  "ORDER BY conname",
 
5911
                                                                  tbinfo->dobj.catId.oid);
 
5912
                        }
 
5913
                        else if (g_fout->remoteVersion >= 70200)
 
5914
                        {
 
5915
                                /* 7.2 did not have OIDs in pg_relcheck */
 
5916
                                appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
 
5917
                                                                  "rcname AS conname, "
 
5918
                                                                  "'CHECK (' || rcsrc || ')' AS consrc, "
 
5919
                                                                  "true AS conislocal "
 
5920
                                                                  "FROM pg_relcheck "
 
5921
                                                                  "WHERE rcrelid = '%u'::oid "
 
5922
                                                                  "ORDER BY rcname",
 
5923
                                                                  tbinfo->dobj.catId.oid);
 
5924
                        }
 
5925
                        else if (g_fout->remoteVersion >= 70100)
 
5926
                        {
 
5927
                                appendPQExpBuffer(q, "SELECT tableoid, oid, "
 
5928
                                                                  "rcname AS conname, "
 
5929
                                                                  "'CHECK (' || rcsrc || ')' AS consrc, "
 
5930
                                                                  "true AS conislocal "
 
5931
                                                                  "FROM pg_relcheck "
 
5932
                                                                  "WHERE rcrelid = '%u'::oid "
 
5933
                                                                  "ORDER BY rcname",
 
5934
                                                                  tbinfo->dobj.catId.oid);
 
5935
                        }
 
5936
                        else
 
5937
                        {
 
5938
                                /* no tableoid in 7.0 */
 
5939
                                appendPQExpBuffer(q, "SELECT "
 
5940
                                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
 
5941
                                                                  "oid, rcname AS conname, "
 
5942
                                                                  "'CHECK (' || rcsrc || ')' AS consrc, "
 
5943
                                                                  "true AS conislocal "
 
5944
                                                                  "FROM pg_relcheck "
 
5945
                                                                  "WHERE rcrelid = '%u'::oid "
 
5946
                                                                  "ORDER BY rcname",
 
5947
                                                                  tbinfo->dobj.catId.oid);
 
5948
                        }
 
5949
                        res = PQexec(g_conn, q->data);
 
5950
                        check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
 
5951
 
 
5952
                        numConstrs = PQntuples(res);
 
5953
                        if (numConstrs != tbinfo->ncheck)
 
5954
                        {
 
5955
                                write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
 
5956
                                                                                 "expected %d check constraints on table \"%s\" but found %d\n",
 
5957
                                                                                 tbinfo->ncheck),
 
5958
                                                  tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
 
5959
                                write_msg(NULL, "(The system catalogs might be corrupted.)\n");
 
5960
                                exit_nicely();
 
5961
                        }
 
5962
 
 
5963
                        constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
 
5964
                        tbinfo->checkexprs = constrs;
 
5965
 
 
5966
                        for (j = 0; j < numConstrs; j++)
 
5967
                        {
 
5968
                                constrs[j].dobj.objType = DO_CONSTRAINT;
 
5969
                                constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
 
5970
                                constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
 
5971
                                AssignDumpId(&constrs[j].dobj);
 
5972
                                constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
 
5973
                                constrs[j].dobj.namespace = tbinfo->dobj.namespace;
 
5974
                                constrs[j].contable = tbinfo;
 
5975
                                constrs[j].condomain = NULL;
 
5976
                                constrs[j].contype = 'c';
 
5977
                                constrs[j].condef = strdup(PQgetvalue(res, j, 3));
 
5978
                                constrs[j].confrelid = InvalidOid;
 
5979
                                constrs[j].conindex = 0;
 
5980
                                constrs[j].condeferrable = false;
 
5981
                                constrs[j].condeferred = false;
 
5982
                                constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
 
5983
                                constrs[j].separate = false;
 
5984
 
 
5985
                                constrs[j].dobj.dump = tbinfo->dobj.dump;
 
5986
 
 
5987
                                /*
 
5988
                                 * Mark the constraint as needing to appear before the table
 
5989
                                 * --- this is so that any other dependencies of the
 
5990
                                 * constraint will be emitted before we try to create the
 
5991
                                 * table.
 
5992
                                 */
 
5993
                                addObjectDependency(&tbinfo->dobj,
 
5994
                                                                        constrs[j].dobj.dumpId);
 
5995
 
 
5996
                                /*
 
5997
                                 * If the constraint is inherited, this will be detected later
 
5998
                                 * (in pre-8.4 databases).      We also detect later if the
 
5999
                                 * constraint must be split out from the table definition.
 
6000
                                 */
 
6001
                        }
 
6002
                        PQclear(res);
 
6003
                }
 
6004
        }
 
6005
 
 
6006
        destroyPQExpBuffer(q);
 
6007
}
 
6008
 
 
6009
 
 
6010
/*
 
6011
 * getTSParsers:
 
6012
 *        read all text search parsers in the system catalogs and return them
 
6013
 *        in the TSParserInfo* structure
 
6014
 *
 
6015
 *      numTSParsers is set to the number of parsers read in
 
6016
 */
 
6017
TSParserInfo *
 
6018
getTSParsers(int *numTSParsers)
 
6019
{
 
6020
        PGresult   *res;
 
6021
        int                     ntups;
 
6022
        int                     i;
 
6023
        PQExpBuffer query = createPQExpBuffer();
 
6024
        TSParserInfo *prsinfo;
 
6025
        int                     i_tableoid;
 
6026
        int                     i_oid;
 
6027
        int                     i_prsname;
 
6028
        int                     i_prsnamespace;
 
6029
        int                     i_prsstart;
 
6030
        int                     i_prstoken;
 
6031
        int                     i_prsend;
 
6032
        int                     i_prsheadline;
 
6033
        int                     i_prslextype;
 
6034
 
 
6035
        /* Before 8.3, there is no built-in text search support */
 
6036
        if (g_fout->remoteVersion < 80300)
 
6037
        {
 
6038
                *numTSParsers = 0;
 
6039
                return NULL;
 
6040
        }
 
6041
 
 
6042
        /*
 
6043
         * find all text search objects, including builtin ones; we filter out
 
6044
         * system-defined objects at dump-out time.
 
6045
         */
 
6046
 
 
6047
        /* Make sure we are in proper schema */
 
6048
        selectSourceSchema("pg_catalog");
 
6049
 
 
6050
        appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
 
6051
                                          "prsstart::oid, prstoken::oid, "
 
6052
                                          "prsend::oid, prsheadline::oid, prslextype::oid "
 
6053
                                          "FROM pg_ts_parser");
 
6054
 
 
6055
        res = PQexec(g_conn, query->data);
 
6056
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6057
 
 
6058
        ntups = PQntuples(res);
 
6059
        *numTSParsers = ntups;
 
6060
 
 
6061
        prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
 
6062
 
 
6063
        i_tableoid = PQfnumber(res, "tableoid");
 
6064
        i_oid = PQfnumber(res, "oid");
 
6065
        i_prsname = PQfnumber(res, "prsname");
 
6066
        i_prsnamespace = PQfnumber(res, "prsnamespace");
 
6067
        i_prsstart = PQfnumber(res, "prsstart");
 
6068
        i_prstoken = PQfnumber(res, "prstoken");
 
6069
        i_prsend = PQfnumber(res, "prsend");
 
6070
        i_prsheadline = PQfnumber(res, "prsheadline");
 
6071
        i_prslextype = PQfnumber(res, "prslextype");
 
6072
 
 
6073
        for (i = 0; i < ntups; i++)
 
6074
        {
 
6075
                prsinfo[i].dobj.objType = DO_TSPARSER;
 
6076
                prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6077
                prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6078
                AssignDumpId(&prsinfo[i].dobj);
 
6079
                prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
 
6080
                prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
 
6081
                                                                                                  prsinfo[i].dobj.catId.oid);
 
6082
                prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
 
6083
                prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
 
6084
                prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
 
6085
                prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
 
6086
                prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
 
6087
 
 
6088
                /* Decide whether we want to dump it */
 
6089
                selectDumpableObject(&(prsinfo[i].dobj));
 
6090
        }
 
6091
 
 
6092
        PQclear(res);
 
6093
 
 
6094
        destroyPQExpBuffer(query);
 
6095
 
 
6096
        return prsinfo;
 
6097
}
 
6098
 
 
6099
/*
 
6100
 * getTSDictionaries:
 
6101
 *        read all text search dictionaries in the system catalogs and return them
 
6102
 *        in the TSDictInfo* structure
 
6103
 *
 
6104
 *      numTSDicts is set to the number of dictionaries read in
 
6105
 */
 
6106
TSDictInfo *
 
6107
getTSDictionaries(int *numTSDicts)
 
6108
{
 
6109
        PGresult   *res;
 
6110
        int                     ntups;
 
6111
        int                     i;
 
6112
        PQExpBuffer query = createPQExpBuffer();
 
6113
        TSDictInfo *dictinfo;
 
6114
        int                     i_tableoid;
 
6115
        int                     i_oid;
 
6116
        int                     i_dictname;
 
6117
        int                     i_dictnamespace;
 
6118
        int                     i_rolname;
 
6119
        int                     i_dicttemplate;
 
6120
        int                     i_dictinitoption;
 
6121
 
 
6122
        /* Before 8.3, there is no built-in text search support */
 
6123
        if (g_fout->remoteVersion < 80300)
 
6124
        {
 
6125
                *numTSDicts = 0;
 
6126
                return NULL;
 
6127
        }
 
6128
 
 
6129
        /* Make sure we are in proper schema */
 
6130
        selectSourceSchema("pg_catalog");
 
6131
 
 
6132
        appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
 
6133
                                          "dictnamespace, (%s dictowner) AS rolname, "
 
6134
                                          "dicttemplate, dictinitoption "
 
6135
                                          "FROM pg_ts_dict",
 
6136
                                          username_subquery);
 
6137
 
 
6138
        res = PQexec(g_conn, query->data);
 
6139
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6140
 
 
6141
        ntups = PQntuples(res);
 
6142
        *numTSDicts = ntups;
 
6143
 
 
6144
        dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
 
6145
 
 
6146
        i_tableoid = PQfnumber(res, "tableoid");
 
6147
        i_oid = PQfnumber(res, "oid");
 
6148
        i_dictname = PQfnumber(res, "dictname");
 
6149
        i_dictnamespace = PQfnumber(res, "dictnamespace");
 
6150
        i_rolname = PQfnumber(res, "rolname");
 
6151
        i_dictinitoption = PQfnumber(res, "dictinitoption");
 
6152
        i_dicttemplate = PQfnumber(res, "dicttemplate");
 
6153
 
 
6154
        for (i = 0; i < ntups; i++)
 
6155
        {
 
6156
                dictinfo[i].dobj.objType = DO_TSDICT;
 
6157
                dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6158
                dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6159
                AssignDumpId(&dictinfo[i].dobj);
 
6160
                dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
 
6161
                dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
 
6162
                                                                                                 dictinfo[i].dobj.catId.oid);
 
6163
                dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
6164
                dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
 
6165
                if (PQgetisnull(res, i, i_dictinitoption))
 
6166
                        dictinfo[i].dictinitoption = NULL;
 
6167
                else
 
6168
                        dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
 
6169
 
 
6170
                /* Decide whether we want to dump it */
 
6171
                selectDumpableObject(&(dictinfo[i].dobj));
 
6172
        }
 
6173
 
 
6174
        PQclear(res);
 
6175
 
 
6176
        destroyPQExpBuffer(query);
 
6177
 
 
6178
        return dictinfo;
 
6179
}
 
6180
 
 
6181
/*
 
6182
 * getTSTemplates:
 
6183
 *        read all text search templates in the system catalogs and return them
 
6184
 *        in the TSTemplateInfo* structure
 
6185
 *
 
6186
 *      numTSTemplates is set to the number of templates read in
 
6187
 */
 
6188
TSTemplateInfo *
 
6189
getTSTemplates(int *numTSTemplates)
 
6190
{
 
6191
        PGresult   *res;
 
6192
        int                     ntups;
 
6193
        int                     i;
 
6194
        PQExpBuffer query = createPQExpBuffer();
 
6195
        TSTemplateInfo *tmplinfo;
 
6196
        int                     i_tableoid;
 
6197
        int                     i_oid;
 
6198
        int                     i_tmplname;
 
6199
        int                     i_tmplnamespace;
 
6200
        int                     i_tmplinit;
 
6201
        int                     i_tmpllexize;
 
6202
 
 
6203
        /* Before 8.3, there is no built-in text search support */
 
6204
        if (g_fout->remoteVersion < 80300)
 
6205
        {
 
6206
                *numTSTemplates = 0;
 
6207
                return NULL;
 
6208
        }
 
6209
 
 
6210
        /* Make sure we are in proper schema */
 
6211
        selectSourceSchema("pg_catalog");
 
6212
 
 
6213
        appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
 
6214
                                          "tmplnamespace, tmplinit::oid, tmpllexize::oid "
 
6215
                                          "FROM pg_ts_template");
 
6216
 
 
6217
        res = PQexec(g_conn, query->data);
 
6218
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6219
 
 
6220
        ntups = PQntuples(res);
 
6221
        *numTSTemplates = ntups;
 
6222
 
 
6223
        tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
 
6224
 
 
6225
        i_tableoid = PQfnumber(res, "tableoid");
 
6226
        i_oid = PQfnumber(res, "oid");
 
6227
        i_tmplname = PQfnumber(res, "tmplname");
 
6228
        i_tmplnamespace = PQfnumber(res, "tmplnamespace");
 
6229
        i_tmplinit = PQfnumber(res, "tmplinit");
 
6230
        i_tmpllexize = PQfnumber(res, "tmpllexize");
 
6231
 
 
6232
        for (i = 0; i < ntups; i++)
 
6233
        {
 
6234
                tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
 
6235
                tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6236
                tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6237
                AssignDumpId(&tmplinfo[i].dobj);
 
6238
                tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
 
6239
                tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
 
6240
                                                                                                 tmplinfo[i].dobj.catId.oid);
 
6241
                tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
 
6242
                tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
 
6243
 
 
6244
                /* Decide whether we want to dump it */
 
6245
                selectDumpableObject(&(tmplinfo[i].dobj));
 
6246
        }
 
6247
 
 
6248
        PQclear(res);
 
6249
 
 
6250
        destroyPQExpBuffer(query);
 
6251
 
 
6252
        return tmplinfo;
 
6253
}
 
6254
 
 
6255
/*
 
6256
 * getTSConfigurations:
 
6257
 *        read all text search configurations in the system catalogs and return
 
6258
 *        them in the TSConfigInfo* structure
 
6259
 *
 
6260
 *      numTSConfigs is set to the number of configurations read in
 
6261
 */
 
6262
TSConfigInfo *
 
6263
getTSConfigurations(int *numTSConfigs)
 
6264
{
 
6265
        PGresult   *res;
 
6266
        int                     ntups;
 
6267
        int                     i;
 
6268
        PQExpBuffer query = createPQExpBuffer();
 
6269
        TSConfigInfo *cfginfo;
 
6270
        int                     i_tableoid;
 
6271
        int                     i_oid;
 
6272
        int                     i_cfgname;
 
6273
        int                     i_cfgnamespace;
 
6274
        int                     i_rolname;
 
6275
        int                     i_cfgparser;
 
6276
 
 
6277
        /* Before 8.3, there is no built-in text search support */
 
6278
        if (g_fout->remoteVersion < 80300)
 
6279
        {
 
6280
                *numTSConfigs = 0;
 
6281
                return NULL;
 
6282
        }
 
6283
 
 
6284
        /* Make sure we are in proper schema */
 
6285
        selectSourceSchema("pg_catalog");
 
6286
 
 
6287
        appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
 
6288
                                          "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
 
6289
                                          "FROM pg_ts_config",
 
6290
                                          username_subquery);
 
6291
 
 
6292
        res = PQexec(g_conn, query->data);
 
6293
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6294
 
 
6295
        ntups = PQntuples(res);
 
6296
        *numTSConfigs = ntups;
 
6297
 
 
6298
        cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
 
6299
 
 
6300
        i_tableoid = PQfnumber(res, "tableoid");
 
6301
        i_oid = PQfnumber(res, "oid");
 
6302
        i_cfgname = PQfnumber(res, "cfgname");
 
6303
        i_cfgnamespace = PQfnumber(res, "cfgnamespace");
 
6304
        i_rolname = PQfnumber(res, "rolname");
 
6305
        i_cfgparser = PQfnumber(res, "cfgparser");
 
6306
 
 
6307
        for (i = 0; i < ntups; i++)
 
6308
        {
 
6309
                cfginfo[i].dobj.objType = DO_TSCONFIG;
 
6310
                cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6311
                cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6312
                AssignDumpId(&cfginfo[i].dobj);
 
6313
                cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
 
6314
                cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
 
6315
                                                                                                  cfginfo[i].dobj.catId.oid);
 
6316
                cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
6317
                cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
 
6318
 
 
6319
                /* Decide whether we want to dump it */
 
6320
                selectDumpableObject(&(cfginfo[i].dobj));
 
6321
        }
 
6322
 
 
6323
        PQclear(res);
 
6324
 
 
6325
        destroyPQExpBuffer(query);
 
6326
 
 
6327
        return cfginfo;
 
6328
}
 
6329
 
 
6330
/*
 
6331
 * getForeignDataWrappers:
 
6332
 *        read all foreign-data wrappers in the system catalogs and return
 
6333
 *        them in the FdwInfo* structure
 
6334
 *
 
6335
 *      numForeignDataWrappers is set to the number of fdws read in
 
6336
 */
 
6337
FdwInfo *
 
6338
getForeignDataWrappers(int *numForeignDataWrappers)
 
6339
{
 
6340
        PGresult   *res;
 
6341
        int                     ntups;
 
6342
        int                     i;
 
6343
        PQExpBuffer query = createPQExpBuffer();
 
6344
        FdwInfo    *fdwinfo;
 
6345
        int                     i_tableoid;
 
6346
        int                     i_oid;
 
6347
        int                     i_fdwname;
 
6348
        int                     i_rolname;
 
6349
        int                     i_fdwhandler;
 
6350
        int                     i_fdwvalidator;
 
6351
        int                     i_fdwacl;
 
6352
        int                     i_fdwoptions;
 
6353
 
 
6354
        /* Before 8.4, there are no foreign-data wrappers */
 
6355
        if (g_fout->remoteVersion < 80400)
 
6356
        {
 
6357
                *numForeignDataWrappers = 0;
 
6358
                return NULL;
 
6359
        }
 
6360
 
 
6361
        /* Make sure we are in proper schema */
 
6362
        selectSourceSchema("pg_catalog");
 
6363
 
 
6364
        if (g_fout->remoteVersion >= 90100)
 
6365
        {
 
6366
                appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
 
6367
                                                  "(%s fdwowner) AS rolname, "
 
6368
                                                  "fdwhandler::pg_catalog.regproc, "
 
6369
                                                  "fdwvalidator::pg_catalog.regproc, fdwacl, "
 
6370
                                                  "array_to_string(ARRAY("
 
6371
                                                  "             SELECT option_name || ' ' || quote_literal(option_value) "
 
6372
                                                  "             FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
 
6373
                                                  "FROM pg_foreign_data_wrapper",
 
6374
                                                  username_subquery);
 
6375
        }
 
6376
        else
 
6377
        {
 
6378
                appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
 
6379
                                                  "(%s fdwowner) AS rolname, "
 
6380
                                                  "'-' AS fdwhandler, "
 
6381
                                                  "fdwvalidator::pg_catalog.regproc, fdwacl, "
 
6382
                                                  "array_to_string(ARRAY("
 
6383
                                                  "             SELECT option_name || ' ' || quote_literal(option_value) "
 
6384
                                                  "             FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
 
6385
                                                  "FROM pg_foreign_data_wrapper",
 
6386
                                                  username_subquery);
 
6387
        }
 
6388
 
 
6389
        res = PQexec(g_conn, query->data);
 
6390
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6391
 
 
6392
        ntups = PQntuples(res);
 
6393
        *numForeignDataWrappers = ntups;
 
6394
 
 
6395
        fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
 
6396
 
 
6397
        i_tableoid = PQfnumber(res, "tableoid");
 
6398
        i_oid = PQfnumber(res, "oid");
 
6399
        i_fdwname = PQfnumber(res, "fdwname");
 
6400
        i_rolname = PQfnumber(res, "rolname");
 
6401
        i_fdwhandler = PQfnumber(res, "fdwhandler");
 
6402
        i_fdwvalidator = PQfnumber(res, "fdwvalidator");
 
6403
        i_fdwacl = PQfnumber(res, "fdwacl");
 
6404
        i_fdwoptions = PQfnumber(res, "fdwoptions");
 
6405
 
 
6406
        for (i = 0; i < ntups; i++)
 
6407
        {
 
6408
                fdwinfo[i].dobj.objType = DO_FDW;
 
6409
                fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6410
                fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6411
                AssignDumpId(&fdwinfo[i].dobj);
 
6412
                fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
 
6413
                fdwinfo[i].dobj.namespace = NULL;
 
6414
                fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
6415
                fdwinfo[i].fdwhandler = strdup(PQgetvalue(res, i, i_fdwhandler));
 
6416
                fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
 
6417
                fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
 
6418
                fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
 
6419
 
 
6420
                /* Decide whether we want to dump it */
 
6421
                selectDumpableObject(&(fdwinfo[i].dobj));
 
6422
        }
 
6423
 
 
6424
        PQclear(res);
 
6425
 
 
6426
        destroyPQExpBuffer(query);
 
6427
 
 
6428
        return fdwinfo;
 
6429
}
 
6430
 
 
6431
/*
 
6432
 * getForeignServers:
 
6433
 *        read all foreign servers in the system catalogs and return
 
6434
 *        them in the ForeignServerInfo * structure
 
6435
 *
 
6436
 *      numForeignServers is set to the number of servers read in
 
6437
 */
 
6438
ForeignServerInfo *
 
6439
getForeignServers(int *numForeignServers)
 
6440
{
 
6441
        PGresult   *res;
 
6442
        int                     ntups;
 
6443
        int                     i;
 
6444
        PQExpBuffer query = createPQExpBuffer();
 
6445
        ForeignServerInfo *srvinfo;
 
6446
        int                     i_tableoid;
 
6447
        int                     i_oid;
 
6448
        int                     i_srvname;
 
6449
        int                     i_rolname;
 
6450
        int                     i_srvfdw;
 
6451
        int                     i_srvtype;
 
6452
        int                     i_srvversion;
 
6453
        int                     i_srvacl;
 
6454
        int                     i_srvoptions;
 
6455
 
 
6456
        /* Before 8.4, there are no foreign servers */
 
6457
        if (g_fout->remoteVersion < 80400)
 
6458
        {
 
6459
                *numForeignServers = 0;
 
6460
                return NULL;
 
6461
        }
 
6462
 
 
6463
        /* Make sure we are in proper schema */
 
6464
        selectSourceSchema("pg_catalog");
 
6465
 
 
6466
        appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
 
6467
                                          "(%s srvowner) AS rolname, "
 
6468
                                          "srvfdw, srvtype, srvversion, srvacl,"
 
6469
                                          "array_to_string(ARRAY("
 
6470
                 "              SELECT option_name || ' ' || quote_literal(option_value) "
 
6471
           "            FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
 
6472
                                          "FROM pg_foreign_server",
 
6473
                                          username_subquery);
 
6474
 
 
6475
        res = PQexec(g_conn, query->data);
 
6476
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6477
 
 
6478
        ntups = PQntuples(res);
 
6479
        *numForeignServers = ntups;
 
6480
 
 
6481
        srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
 
6482
 
 
6483
        i_tableoid = PQfnumber(res, "tableoid");
 
6484
        i_oid = PQfnumber(res, "oid");
 
6485
        i_srvname = PQfnumber(res, "srvname");
 
6486
        i_rolname = PQfnumber(res, "rolname");
 
6487
        i_srvfdw = PQfnumber(res, "srvfdw");
 
6488
        i_srvtype = PQfnumber(res, "srvtype");
 
6489
        i_srvversion = PQfnumber(res, "srvversion");
 
6490
        i_srvacl = PQfnumber(res, "srvacl");
 
6491
        i_srvoptions = PQfnumber(res, "srvoptions");
 
6492
 
 
6493
        for (i = 0; i < ntups; i++)
 
6494
        {
 
6495
                srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
 
6496
                srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6497
                srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6498
                AssignDumpId(&srvinfo[i].dobj);
 
6499
                srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
 
6500
                srvinfo[i].dobj.namespace = NULL;
 
6501
                srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
 
6502
                srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
 
6503
                srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
 
6504
                srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
 
6505
                srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
 
6506
                srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
 
6507
 
 
6508
                /* Decide whether we want to dump it */
 
6509
                selectDumpableObject(&(srvinfo[i].dobj));
 
6510
        }
 
6511
 
 
6512
        PQclear(res);
 
6513
 
 
6514
        destroyPQExpBuffer(query);
 
6515
 
 
6516
        return srvinfo;
 
6517
}
 
6518
 
 
6519
/*
 
6520
 * getDefaultACLs:
 
6521
 *        read all default ACL information in the system catalogs and return
 
6522
 *        them in the DefaultACLInfo structure
 
6523
 *
 
6524
 *      numDefaultACLs is set to the number of ACLs read in
 
6525
 */
 
6526
DefaultACLInfo *
 
6527
getDefaultACLs(int *numDefaultACLs)
 
6528
{
 
6529
        DefaultACLInfo *daclinfo;
 
6530
        PQExpBuffer query;
 
6531
        PGresult   *res;
 
6532
        int                     i_oid;
 
6533
        int                     i_tableoid;
 
6534
        int                     i_defaclrole;
 
6535
        int                     i_defaclnamespace;
 
6536
        int                     i_defaclobjtype;
 
6537
        int                     i_defaclacl;
 
6538
        int                     i,
 
6539
                                ntups;
 
6540
 
 
6541
        if (g_fout->remoteVersion < 90000)
 
6542
        {
 
6543
                *numDefaultACLs = 0;
 
6544
                return NULL;
 
6545
        }
 
6546
 
 
6547
        query = createPQExpBuffer();
 
6548
 
 
6549
        /* Make sure we are in proper schema */
 
6550
        selectSourceSchema("pg_catalog");
 
6551
 
 
6552
        appendPQExpBuffer(query, "SELECT oid, tableoid, "
 
6553
                                          "(%s defaclrole) AS defaclrole, "
 
6554
                                          "defaclnamespace, "
 
6555
                                          "defaclobjtype, "
 
6556
                                          "defaclacl "
 
6557
                                          "FROM pg_default_acl",
 
6558
                                          username_subquery);
 
6559
 
 
6560
        res = PQexec(g_conn, query->data);
 
6561
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6562
 
 
6563
        ntups = PQntuples(res);
 
6564
        *numDefaultACLs = ntups;
 
6565
 
 
6566
        daclinfo = (DefaultACLInfo *) malloc(ntups * sizeof(DefaultACLInfo));
 
6567
 
 
6568
        i_oid = PQfnumber(res, "oid");
 
6569
        i_tableoid = PQfnumber(res, "tableoid");
 
6570
        i_defaclrole = PQfnumber(res, "defaclrole");
 
6571
        i_defaclnamespace = PQfnumber(res, "defaclnamespace");
 
6572
        i_defaclobjtype = PQfnumber(res, "defaclobjtype");
 
6573
        i_defaclacl = PQfnumber(res, "defaclacl");
 
6574
 
 
6575
        for (i = 0; i < ntups; i++)
 
6576
        {
 
6577
                Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
 
6578
 
 
6579
                daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
 
6580
                daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
 
6581
                daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
 
6582
                AssignDumpId(&daclinfo[i].dobj);
 
6583
                /* cheesy ... is it worth coming up with a better object name? */
 
6584
                daclinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_defaclobjtype));
 
6585
 
 
6586
                if (nspid != InvalidOid)
 
6587
                        daclinfo[i].dobj.namespace = findNamespace(nspid,
 
6588
                                                                                                 daclinfo[i].dobj.catId.oid);
 
6589
                else
 
6590
                        daclinfo[i].dobj.namespace = NULL;
 
6591
 
 
6592
                daclinfo[i].defaclrole = strdup(PQgetvalue(res, i, i_defaclrole));
 
6593
                daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
 
6594
                daclinfo[i].defaclacl = strdup(PQgetvalue(res, i, i_defaclacl));
 
6595
 
 
6596
                /* Decide whether we want to dump it */
 
6597
                selectDumpableDefaultACL(&(daclinfo[i]));
 
6598
        }
 
6599
 
 
6600
        PQclear(res);
 
6601
 
 
6602
        destroyPQExpBuffer(query);
 
6603
 
 
6604
        return daclinfo;
 
6605
}
 
6606
 
 
6607
/*
 
6608
 * dumpComment --
 
6609
 *
 
6610
 * This routine is used to dump any comments associated with the
 
6611
 * object handed to this routine. The routine takes a constant character
 
6612
 * string for the target part of the comment-creation command, plus
 
6613
 * the namespace and owner of the object (for labeling the ArchiveEntry),
 
6614
 * plus catalog ID and subid which are the lookup key for pg_description,
 
6615
 * plus the dump ID for the object (for setting a dependency).
 
6616
 * If a matching pg_description entry is found, it is dumped.
 
6617
 *
 
6618
 * Note: although this routine takes a dumpId for dependency purposes,
 
6619
 * that purpose is just to mark the dependency in the emitted dump file
 
6620
 * for possible future use by pg_restore.  We do NOT use it for determining
 
6621
 * ordering of the comment in the dump file, because this routine is called
 
6622
 * after dependency sorting occurs.  This routine should be called just after
 
6623
 * calling ArchiveEntry() for the specified object.
 
6624
 */
 
6625
static void
 
6626
dumpComment(Archive *fout, const char *target,
 
6627
                        const char *namespace, const char *owner,
 
6628
                        CatalogId catalogId, int subid, DumpId dumpId)
 
6629
{
 
6630
        CommentItem *comments;
 
6631
        int                     ncomments;
 
6632
 
 
6633
        /* Comments are schema not data ... except blob comments are data */
 
6634
        if (strncmp(target, "LARGE OBJECT ", 13) != 0)
 
6635
        {
 
6636
                if (dataOnly)
 
6637
                        return;
 
6638
        }
 
6639
        else
 
6640
        {
 
6641
                if (schemaOnly)
 
6642
                        return;
 
6643
        }
 
6644
 
 
6645
        /* Search for comments associated with catalogId, using table */
 
6646
        ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
 
6647
                                                         &comments);
 
6648
 
 
6649
        /* Is there one matching the subid? */
 
6650
        while (ncomments > 0)
 
6651
        {
 
6652
                if (comments->objsubid == subid)
 
6653
                        break;
 
6654
                comments++;
 
6655
                ncomments--;
 
6656
        }
 
6657
 
 
6658
        /* If a comment exists, build COMMENT ON statement */
 
6659
        if (ncomments > 0)
 
6660
        {
 
6661
                PQExpBuffer query = createPQExpBuffer();
 
6662
 
 
6663
                appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
 
6664
                appendStringLiteralAH(query, comments->descr, fout);
 
6665
                appendPQExpBuffer(query, ";\n");
 
6666
 
 
6667
                /*
 
6668
                 * We mark comments as SECTION_NONE because they really belong in the
 
6669
                 * same section as their parent, whether that is pre-data or
 
6670
                 * post-data.
 
6671
                 */
 
6672
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
6673
                                         target, namespace, NULL, owner,
 
6674
                                         false, "COMMENT", SECTION_NONE,
 
6675
                                         query->data, "", NULL,
 
6676
                                         &(dumpId), 1,
 
6677
                                         NULL, NULL);
 
6678
 
 
6679
                destroyPQExpBuffer(query);
 
6680
        }
 
6681
}
 
6682
 
 
6683
/*
 
6684
 * dumpTableComment --
 
6685
 *
 
6686
 * As above, but dump comments for both the specified table (or view)
 
6687
 * and its columns.
 
6688
 */
 
6689
static void
 
6690
dumpTableComment(Archive *fout, TableInfo *tbinfo,
 
6691
                                 const char *reltypename)
 
6692
{
 
6693
        CommentItem *comments;
 
6694
        int                     ncomments;
 
6695
        PQExpBuffer query;
 
6696
        PQExpBuffer target;
 
6697
 
 
6698
        /* Comments are SCHEMA not data */
 
6699
        if (dataOnly)
 
6700
                return;
 
6701
 
 
6702
        /* Search for comments associated with relation, using table */
 
6703
        ncomments = findComments(fout,
 
6704
                                                         tbinfo->dobj.catId.tableoid,
 
6705
                                                         tbinfo->dobj.catId.oid,
 
6706
                                                         &comments);
 
6707
 
 
6708
        /* If comments exist, build COMMENT ON statements */
 
6709
        if (ncomments <= 0)
 
6710
                return;
 
6711
 
 
6712
        query = createPQExpBuffer();
 
6713
        target = createPQExpBuffer();
 
6714
 
 
6715
        while (ncomments > 0)
 
6716
        {
 
6717
                const char *descr = comments->descr;
 
6718
                int                     objsubid = comments->objsubid;
 
6719
 
 
6720
                if (objsubid == 0)
 
6721
                {
 
6722
                        resetPQExpBuffer(target);
 
6723
                        appendPQExpBuffer(target, "%s %s", reltypename,
 
6724
                                                          fmtId(tbinfo->dobj.name));
 
6725
 
 
6726
                        resetPQExpBuffer(query);
 
6727
                        appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
 
6728
                        appendStringLiteralAH(query, descr, fout);
 
6729
                        appendPQExpBuffer(query, ";\n");
 
6730
 
 
6731
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
6732
                                                 target->data,
 
6733
                                                 tbinfo->dobj.namespace->dobj.name,
 
6734
                                                 NULL, tbinfo->rolname,
 
6735
                                                 false, "COMMENT", SECTION_NONE,
 
6736
                                                 query->data, "", NULL,
 
6737
                                                 &(tbinfo->dobj.dumpId), 1,
 
6738
                                                 NULL, NULL);
 
6739
                }
 
6740
                else if (objsubid > 0 && objsubid <= tbinfo->numatts)
 
6741
                {
 
6742
                        resetPQExpBuffer(target);
 
6743
                        appendPQExpBuffer(target, "COLUMN %s.",
 
6744
                                                          fmtId(tbinfo->dobj.name));
 
6745
                        appendPQExpBuffer(target, "%s",
 
6746
                                                          fmtId(tbinfo->attnames[objsubid - 1]));
 
6747
 
 
6748
                        resetPQExpBuffer(query);
 
6749
                        appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
 
6750
                        appendStringLiteralAH(query, descr, fout);
 
6751
                        appendPQExpBuffer(query, ";\n");
 
6752
 
 
6753
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
6754
                                                 target->data,
 
6755
                                                 tbinfo->dobj.namespace->dobj.name,
 
6756
                                                 NULL, tbinfo->rolname,
 
6757
                                                 false, "COMMENT", SECTION_NONE,
 
6758
                                                 query->data, "", NULL,
 
6759
                                                 &(tbinfo->dobj.dumpId), 1,
 
6760
                                                 NULL, NULL);
 
6761
                }
 
6762
 
 
6763
                comments++;
 
6764
                ncomments--;
 
6765
        }
 
6766
 
 
6767
        destroyPQExpBuffer(query);
 
6768
        destroyPQExpBuffer(target);
 
6769
}
 
6770
 
 
6771
/*
 
6772
 * findComments --
 
6773
 *
 
6774
 * Find the comment(s), if any, associated with the given object.  All the
 
6775
 * objsubid values associated with the given classoid/objoid are found with
 
6776
 * one search.
 
6777
 */
 
6778
static int
 
6779
findComments(Archive *fout, Oid classoid, Oid objoid,
 
6780
                         CommentItem **items)
 
6781
{
 
6782
        /* static storage for table of comments */
 
6783
        static CommentItem *comments = NULL;
 
6784
        static int      ncomments = -1;
 
6785
 
 
6786
        CommentItem *middle = NULL;
 
6787
        CommentItem *low;
 
6788
        CommentItem *high;
 
6789
        int                     nmatch;
 
6790
 
 
6791
        /* Get comments if we didn't already */
 
6792
        if (ncomments < 0)
 
6793
                ncomments = collectComments(fout, &comments);
 
6794
 
 
6795
        /*
 
6796
         * Pre-7.2, pg_description does not contain classoid, so collectComments
 
6797
         * just stores a zero.  If there's a collision on object OID, well, you
 
6798
         * get duplicate comments.
 
6799
         */
 
6800
        if (fout->remoteVersion < 70200)
 
6801
                classoid = 0;
 
6802
 
 
6803
        /*
 
6804
         * Do binary search to find some item matching the object.
 
6805
         */
 
6806
        low = &comments[0];
 
6807
        high = &comments[ncomments - 1];
 
6808
        while (low <= high)
 
6809
        {
 
6810
                middle = low + (high - low) / 2;
 
6811
 
 
6812
                if (classoid < middle->classoid)
 
6813
                        high = middle - 1;
 
6814
                else if (classoid > middle->classoid)
 
6815
                        low = middle + 1;
 
6816
                else if (objoid < middle->objoid)
 
6817
                        high = middle - 1;
 
6818
                else if (objoid > middle->objoid)
 
6819
                        low = middle + 1;
 
6820
                else
 
6821
                        break;                          /* found a match */
 
6822
        }
 
6823
 
 
6824
        if (low > high)                         /* no matches */
 
6825
        {
 
6826
                *items = NULL;
 
6827
                return 0;
 
6828
        }
 
6829
 
 
6830
        /*
 
6831
         * Now determine how many items match the object.  The search loop
 
6832
         * invariant still holds: only items between low and high inclusive could
 
6833
         * match.
 
6834
         */
 
6835
        nmatch = 1;
 
6836
        while (middle > low)
 
6837
        {
 
6838
                if (classoid != middle[-1].classoid ||
 
6839
                        objoid != middle[-1].objoid)
 
6840
                        break;
 
6841
                middle--;
 
6842
                nmatch++;
 
6843
        }
 
6844
 
 
6845
        *items = middle;
 
6846
 
 
6847
        middle += nmatch;
 
6848
        while (middle <= high)
 
6849
        {
 
6850
                if (classoid != middle->classoid ||
 
6851
                        objoid != middle->objoid)
 
6852
                        break;
 
6853
                middle++;
 
6854
                nmatch++;
 
6855
        }
 
6856
 
 
6857
        return nmatch;
 
6858
}
 
6859
 
 
6860
/*
 
6861
 * collectComments --
 
6862
 *
 
6863
 * Construct a table of all comments available for database objects.
 
6864
 * We used to do per-object queries for the comments, but it's much faster
 
6865
 * to pull them all over at once, and on most databases the memory cost
 
6866
 * isn't high.
 
6867
 *
 
6868
 * The table is sorted by classoid/objid/objsubid for speed in lookup.
 
6869
 */
 
6870
static int
 
6871
collectComments(Archive *fout, CommentItem **items)
 
6872
{
 
6873
        PGresult   *res;
 
6874
        PQExpBuffer query;
 
6875
        int                     i_description;
 
6876
        int                     i_classoid;
 
6877
        int                     i_objoid;
 
6878
        int                     i_objsubid;
 
6879
        int                     ntups;
 
6880
        int                     i;
 
6881
        CommentItem *comments;
 
6882
 
 
6883
        /*
 
6884
         * Note we do NOT change source schema here; preserve the caller's
 
6885
         * setting, instead.
 
6886
         */
 
6887
 
 
6888
        query = createPQExpBuffer();
 
6889
 
 
6890
        if (fout->remoteVersion >= 70300)
 
6891
        {
 
6892
                appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
 
6893
                                                  "FROM pg_catalog.pg_description "
 
6894
                                                  "ORDER BY classoid, objoid, objsubid");
 
6895
        }
 
6896
        else if (fout->remoteVersion >= 70200)
 
6897
        {
 
6898
                appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
 
6899
                                                  "FROM pg_description "
 
6900
                                                  "ORDER BY classoid, objoid, objsubid");
 
6901
        }
 
6902
        else
 
6903
        {
 
6904
                /* Note: this will fail to find attribute comments in pre-7.2... */
 
6905
                appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
 
6906
                                                  "FROM pg_description "
 
6907
                                                  "ORDER BY objoid");
 
6908
        }
 
6909
 
 
6910
        res = PQexec(g_conn, query->data);
 
6911
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
6912
 
 
6913
        /* Construct lookup table containing OIDs in numeric form */
 
6914
 
 
6915
        i_description = PQfnumber(res, "description");
 
6916
        i_classoid = PQfnumber(res, "classoid");
 
6917
        i_objoid = PQfnumber(res, "objoid");
 
6918
        i_objsubid = PQfnumber(res, "objsubid");
 
6919
 
 
6920
        ntups = PQntuples(res);
 
6921
 
 
6922
        comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
 
6923
 
 
6924
        for (i = 0; i < ntups; i++)
 
6925
        {
 
6926
                comments[i].descr = PQgetvalue(res, i, i_description);
 
6927
                comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
 
6928
                comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
 
6929
                comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
 
6930
        }
 
6931
 
 
6932
        /* Do NOT free the PGresult since we are keeping pointers into it */
 
6933
        destroyPQExpBuffer(query);
 
6934
 
 
6935
        *items = comments;
 
6936
        return ntups;
 
6937
}
 
6938
 
 
6939
/*
 
6940
 * dumpDumpableObject
 
6941
 *
 
6942
 * This routine and its subsidiaries are responsible for creating
 
6943
 * ArchiveEntries (TOC objects) for each object to be dumped.
 
6944
 */
 
6945
static void
 
6946
dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 
6947
{
 
6948
        switch (dobj->objType)
 
6949
        {
 
6950
                case DO_NAMESPACE:
 
6951
                        dumpNamespace(fout, (NamespaceInfo *) dobj);
 
6952
                        break;
 
6953
                case DO_EXTENSION:
 
6954
                        dumpExtension(fout, (ExtensionInfo *) dobj);
 
6955
                        break;
 
6956
                case DO_TYPE:
 
6957
                        dumpType(fout, (TypeInfo *) dobj);
 
6958
                        break;
 
6959
                case DO_SHELL_TYPE:
 
6960
                        dumpShellType(fout, (ShellTypeInfo *) dobj);
 
6961
                        break;
 
6962
                case DO_FUNC:
 
6963
                        dumpFunc(fout, (FuncInfo *) dobj);
 
6964
                        break;
 
6965
                case DO_AGG:
 
6966
                        dumpAgg(fout, (AggInfo *) dobj);
 
6967
                        break;
 
6968
                case DO_OPERATOR:
 
6969
                        dumpOpr(fout, (OprInfo *) dobj);
 
6970
                        break;
 
6971
                case DO_OPCLASS:
 
6972
                        dumpOpclass(fout, (OpclassInfo *) dobj);
 
6973
                        break;
 
6974
                case DO_OPFAMILY:
 
6975
                        dumpOpfamily(fout, (OpfamilyInfo *) dobj);
 
6976
                        break;
 
6977
                case DO_COLLATION:
 
6978
                        dumpCollation(fout, (CollInfo *) dobj);
 
6979
                        break;
 
6980
                case DO_CONVERSION:
 
6981
                        dumpConversion(fout, (ConvInfo *) dobj);
 
6982
                        break;
 
6983
                case DO_TABLE:
 
6984
                        dumpTable(fout, (TableInfo *) dobj);
 
6985
                        break;
 
6986
                case DO_ATTRDEF:
 
6987
                        dumpAttrDef(fout, (AttrDefInfo *) dobj);
 
6988
                        break;
 
6989
                case DO_INDEX:
 
6990
                        dumpIndex(fout, (IndxInfo *) dobj);
 
6991
                        break;
 
6992
                case DO_RULE:
 
6993
                        dumpRule(fout, (RuleInfo *) dobj);
 
6994
                        break;
 
6995
                case DO_TRIGGER:
 
6996
                        dumpTrigger(fout, (TriggerInfo *) dobj);
 
6997
                        break;
 
6998
                case DO_CONSTRAINT:
 
6999
                        dumpConstraint(fout, (ConstraintInfo *) dobj);
 
7000
                        break;
 
7001
                case DO_FK_CONSTRAINT:
 
7002
                        dumpConstraint(fout, (ConstraintInfo *) dobj);
 
7003
                        break;
 
7004
                case DO_PROCLANG:
 
7005
                        dumpProcLang(fout, (ProcLangInfo *) dobj);
 
7006
                        break;
 
7007
                case DO_CAST:
 
7008
                        dumpCast(fout, (CastInfo *) dobj);
 
7009
                        break;
 
7010
                case DO_TABLE_DATA:
 
7011
                        dumpTableData(fout, (TableDataInfo *) dobj);
 
7012
                        break;
 
7013
                case DO_DUMMY_TYPE:
 
7014
                        /* table rowtypes and array types are never dumped separately */
 
7015
                        break;
 
7016
                case DO_TSPARSER:
 
7017
                        dumpTSParser(fout, (TSParserInfo *) dobj);
 
7018
                        break;
 
7019
                case DO_TSDICT:
 
7020
                        dumpTSDictionary(fout, (TSDictInfo *) dobj);
 
7021
                        break;
 
7022
                case DO_TSTEMPLATE:
 
7023
                        dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
 
7024
                        break;
 
7025
                case DO_TSCONFIG:
 
7026
                        dumpTSConfig(fout, (TSConfigInfo *) dobj);
 
7027
                        break;
 
7028
                case DO_FDW:
 
7029
                        dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
 
7030
                        break;
 
7031
                case DO_FOREIGN_SERVER:
 
7032
                        dumpForeignServer(fout, (ForeignServerInfo *) dobj);
 
7033
                        break;
 
7034
                case DO_DEFAULT_ACL:
 
7035
                        dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
 
7036
                        break;
 
7037
                case DO_BLOB:
 
7038
                        dumpBlob(fout, (BlobInfo *) dobj);
 
7039
                        break;
 
7040
                case DO_BLOB_DATA:
 
7041
                        ArchiveEntry(fout, dobj->catId, dobj->dumpId,
 
7042
                                                 dobj->name, NULL, NULL, "",
 
7043
                                                 false, "BLOBS", SECTION_DATA,
 
7044
                                                 "", "", NULL,
 
7045
                                                 dobj->dependencies, dobj->nDeps,
 
7046
                                                 dumpBlobs, NULL);
 
7047
                        break;
 
7048
        }
 
7049
}
 
7050
 
 
7051
/*
 
7052
 * dumpNamespace
 
7053
 *        writes out to fout the queries to recreate a user-defined namespace
 
7054
 */
 
7055
static void
 
7056
dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
 
7057
{
 
7058
        PQExpBuffer q;
 
7059
        PQExpBuffer delq;
 
7060
        PQExpBuffer labelq;
 
7061
        char       *qnspname;
 
7062
 
 
7063
        /* Skip if not to be dumped */
 
7064
        if (!nspinfo->dobj.dump || dataOnly)
 
7065
                return;
 
7066
 
 
7067
        /* don't dump dummy namespace from pre-7.3 source */
 
7068
        if (strlen(nspinfo->dobj.name) == 0)
 
7069
                return;
 
7070
 
 
7071
        q = createPQExpBuffer();
 
7072
        delq = createPQExpBuffer();
 
7073
        labelq = createPQExpBuffer();
 
7074
 
 
7075
        qnspname = strdup(fmtId(nspinfo->dobj.name));
 
7076
 
 
7077
        appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
 
7078
 
 
7079
        appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
 
7080
 
 
7081
        appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
 
7082
 
 
7083
        if (binary_upgrade)
 
7084
                binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
 
7085
 
 
7086
        ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
 
7087
                                 nspinfo->dobj.name,
 
7088
                                 NULL, NULL,
 
7089
                                 nspinfo->rolname,
 
7090
                                 false, "SCHEMA", SECTION_PRE_DATA,
 
7091
                                 q->data, delq->data, NULL,
 
7092
                                 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
 
7093
                                 NULL, NULL);
 
7094
 
 
7095
        /* Dump Schema Comments and Security Labels */
 
7096
        dumpComment(fout, labelq->data,
 
7097
                                NULL, nspinfo->rolname,
 
7098
                                nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
 
7099
        dumpSecLabel(fout, labelq->data,
 
7100
                                 NULL, nspinfo->rolname,
 
7101
                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
 
7102
 
 
7103
        dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
 
7104
                        qnspname, NULL, nspinfo->dobj.name, NULL,
 
7105
                        nspinfo->rolname, nspinfo->nspacl);
 
7106
 
 
7107
        free(qnspname);
 
7108
 
 
7109
        destroyPQExpBuffer(q);
 
7110
        destroyPQExpBuffer(delq);
 
7111
        destroyPQExpBuffer(labelq);
 
7112
}
 
7113
 
 
7114
/*
 
7115
 * dumpExtension
 
7116
 *        writes out to fout the queries to recreate an extension
 
7117
 */
 
7118
static void
 
7119
dumpExtension(Archive *fout, ExtensionInfo *extinfo)
 
7120
{
 
7121
        PQExpBuffer q;
 
7122
        PQExpBuffer delq;
 
7123
        PQExpBuffer labelq;
 
7124
        char       *qextname;
 
7125
 
 
7126
        /* Skip if not to be dumped */
 
7127
        if (!extinfo->dobj.dump || dataOnly)
 
7128
                return;
 
7129
 
 
7130
        q = createPQExpBuffer();
 
7131
        delq = createPQExpBuffer();
 
7132
        labelq = createPQExpBuffer();
 
7133
 
 
7134
        qextname = strdup(fmtId(extinfo->dobj.name));
 
7135
 
 
7136
        appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
 
7137
 
 
7138
        if (!binary_upgrade)
 
7139
        {
 
7140
                /*
 
7141
                 * In a regular dump, we use IF NOT EXISTS so that there isn't a
 
7142
                 * problem if the extension already exists in the target database;
 
7143
                 * this is essential for installed-by-default extensions such as
 
7144
                 * plpgsql.
 
7145
                 *
 
7146
                 * In binary-upgrade mode, that doesn't work well, so instead we skip
 
7147
                 * built-in extensions based on their OIDs; see
 
7148
                 * selectDumpableExtension.
 
7149
                 */
 
7150
                appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
 
7151
                                                  qextname, fmtId(extinfo->namespace));
 
7152
        }
 
7153
        else
 
7154
        {
 
7155
                int                     i;
 
7156
                int                     n;
 
7157
 
 
7158
                appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
 
7159
                appendPQExpBuffer(q,
 
7160
                                                  "SELECT binary_upgrade.create_empty_extension(");
 
7161
                appendStringLiteralAH(q, extinfo->dobj.name, fout);
 
7162
                appendPQExpBuffer(q, ", ");
 
7163
                appendStringLiteralAH(q, extinfo->namespace, fout);
 
7164
                appendPQExpBuffer(q, ", ");
 
7165
                appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
 
7166
                appendStringLiteralAH(q, extinfo->extversion, fout);
 
7167
                appendPQExpBuffer(q, ", ");
 
7168
 
 
7169
                /*
 
7170
                 * Note that we're pushing extconfig (an OID array) back into
 
7171
                 * pg_extension exactly as-is.  This is OK because pg_class OIDs are
 
7172
                 * preserved in binary upgrade.
 
7173
                 */
 
7174
                if (strlen(extinfo->extconfig) > 2)
 
7175
                        appendStringLiteralAH(q, extinfo->extconfig, fout);
 
7176
                else
 
7177
                        appendPQExpBuffer(q, "NULL");
 
7178
                appendPQExpBuffer(q, ", ");
 
7179
                if (strlen(extinfo->extcondition) > 2)
 
7180
                        appendStringLiteralAH(q, extinfo->extcondition, fout);
 
7181
                else
 
7182
                        appendPQExpBuffer(q, "NULL");
 
7183
                appendPQExpBuffer(q, ", ");
 
7184
                appendPQExpBuffer(q, "ARRAY[");
 
7185
                n = 0;
 
7186
                for (i = 0; i < extinfo->dobj.nDeps; i++)
 
7187
                {
 
7188
                        DumpableObject *extobj;
 
7189
 
 
7190
                        extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
 
7191
                        if (extobj && extobj->objType == DO_EXTENSION)
 
7192
                        {
 
7193
                                if (n++ > 0)
 
7194
                                        appendPQExpBuffer(q, ",");
 
7195
                                appendStringLiteralAH(q, extobj->name, fout);
 
7196
                        }
 
7197
                }
 
7198
                appendPQExpBuffer(q, "]::pg_catalog.text[]");
 
7199
                appendPQExpBuffer(q, ");\n");
 
7200
        }
 
7201
 
 
7202
        appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
 
7203
 
 
7204
        ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
 
7205
                                 extinfo->dobj.name,
 
7206
                                 NULL, NULL,
 
7207
                                 "",
 
7208
                                 false, "EXTENSION", SECTION_PRE_DATA,
 
7209
                                 q->data, delq->data, NULL,
 
7210
                                 extinfo->dobj.dependencies, extinfo->dobj.nDeps,
 
7211
                                 NULL, NULL);
 
7212
 
 
7213
        /* Dump Extension Comments and Security Labels */
 
7214
        dumpComment(fout, labelq->data,
 
7215
                                NULL, "",
 
7216
                                extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
 
7217
        dumpSecLabel(fout, labelq->data,
 
7218
                                 NULL, "",
 
7219
                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
 
7220
 
 
7221
        free(qextname);
 
7222
 
 
7223
        destroyPQExpBuffer(q);
 
7224
        destroyPQExpBuffer(delq);
 
7225
        destroyPQExpBuffer(labelq);
 
7226
}
 
7227
 
 
7228
/*
 
7229
 * dumpType
 
7230
 *        writes out to fout the queries to recreate a user-defined type
 
7231
 */
 
7232
static void
 
7233
dumpType(Archive *fout, TypeInfo *tyinfo)
 
7234
{
 
7235
        /* Skip if not to be dumped */
 
7236
        if (!tyinfo->dobj.dump || dataOnly)
 
7237
                return;
 
7238
 
 
7239
        /* Dump out in proper style */
 
7240
        if (tyinfo->typtype == TYPTYPE_BASE)
 
7241
                dumpBaseType(fout, tyinfo);
 
7242
        else if (tyinfo->typtype == TYPTYPE_DOMAIN)
 
7243
                dumpDomain(fout, tyinfo);
 
7244
        else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
 
7245
                dumpCompositeType(fout, tyinfo);
 
7246
        else if (tyinfo->typtype == TYPTYPE_ENUM)
 
7247
                dumpEnumType(fout, tyinfo);
 
7248
}
 
7249
 
 
7250
/*
 
7251
 * dumpEnumType
 
7252
 *        writes out to fout the queries to recreate a user-defined enum type
 
7253
 */
 
7254
static void
 
7255
dumpEnumType(Archive *fout, TypeInfo *tyinfo)
 
7256
{
 
7257
        PQExpBuffer q = createPQExpBuffer();
 
7258
        PQExpBuffer delq = createPQExpBuffer();
 
7259
        PQExpBuffer labelq = createPQExpBuffer();
 
7260
        PQExpBuffer query = createPQExpBuffer();
 
7261
        PGresult   *res;
 
7262
        int                     num,
 
7263
                                i;
 
7264
        Oid                     enum_oid;
 
7265
        char       *label;
 
7266
 
 
7267
        /* Set proper schema search path */
 
7268
        selectSourceSchema("pg_catalog");
 
7269
 
 
7270
        if (fout->remoteVersion >= 90100)
 
7271
                appendPQExpBuffer(query, "SELECT oid, enumlabel "
 
7272
                                                  "FROM pg_catalog.pg_enum "
 
7273
                                                  "WHERE enumtypid = '%u'"
 
7274
                                                  "ORDER BY enumsortorder",
 
7275
                                                  tyinfo->dobj.catId.oid);
 
7276
        else
 
7277
                appendPQExpBuffer(query, "SELECT oid, enumlabel "
 
7278
                                                  "FROM pg_catalog.pg_enum "
 
7279
                                                  "WHERE enumtypid = '%u'"
 
7280
                                                  "ORDER BY oid",
 
7281
                                                  tyinfo->dobj.catId.oid);
 
7282
 
 
7283
        res = PQexec(g_conn, query->data);
 
7284
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
7285
 
 
7286
        num = PQntuples(res);
 
7287
 
 
7288
        /*
 
7289
         * DROP must be fully qualified in case same name appears in pg_catalog.
 
7290
         * CASCADE shouldn't be required here as for normal types since the I/O
 
7291
         * functions are generic and do not get dropped.
 
7292
         */
 
7293
        appendPQExpBuffer(delq, "DROP TYPE %s.",
 
7294
                                          fmtId(tyinfo->dobj.namespace->dobj.name));
 
7295
        appendPQExpBuffer(delq, "%s;\n",
 
7296
                                          fmtId(tyinfo->dobj.name));
 
7297
 
 
7298
        if (binary_upgrade)
 
7299
                binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
 
7300
 
 
7301
        appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
 
7302
                                          fmtId(tyinfo->dobj.name));
 
7303
 
 
7304
        if (!binary_upgrade)
 
7305
        {
 
7306
                /* Labels with server-assigned oids */
 
7307
                for (i = 0; i < num; i++)
 
7308
                {
 
7309
                        label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
 
7310
                        if (i > 0)
 
7311
                                appendPQExpBuffer(q, ",");
 
7312
                        appendPQExpBuffer(q, "\n    ");
 
7313
                        appendStringLiteralAH(q, label, fout);
 
7314
                }
 
7315
        }
 
7316
 
 
7317
        appendPQExpBuffer(q, "\n);\n");
 
7318
 
 
7319
        if (binary_upgrade)
 
7320
        {
 
7321
                /* Labels with dump-assigned (preserved) oids */
 
7322
                for (i = 0; i < num; i++)
 
7323
                {
 
7324
                        enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
 
7325
                        label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
 
7326
 
 
7327
                        if (i == 0)
 
7328
                                appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
 
7329
                        appendPQExpBuffer(q,
 
7330
                                                          "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
 
7331
                                                          enum_oid);
 
7332
                        appendPQExpBuffer(q, "ALTER TYPE %s.",
 
7333
                                                          fmtId(tyinfo->dobj.namespace->dobj.name));
 
7334
                        appendPQExpBuffer(q, "%s ADD VALUE ",
 
7335
                                                          fmtId(tyinfo->dobj.name));
 
7336
                        appendStringLiteralAH(q, label, fout);
 
7337
                        appendPQExpBuffer(q, ";\n\n");
 
7338
                }
 
7339
        }
 
7340
 
 
7341
        appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
 
7342
 
 
7343
        if (binary_upgrade)
 
7344
                binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
7345
 
 
7346
        ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 
7347
                                 tyinfo->dobj.name,
 
7348
                                 tyinfo->dobj.namespace->dobj.name,
 
7349
                                 NULL,
 
7350
                                 tyinfo->rolname, false,
 
7351
                                 "TYPE", SECTION_PRE_DATA,
 
7352
                                 q->data, delq->data, NULL,
 
7353
                                 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
 
7354
                                 NULL, NULL);
 
7355
 
 
7356
        /* Dump Type Comments and Security Labels */
 
7357
        dumpComment(fout, labelq->data,
 
7358
                                tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
7359
                                tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
7360
        dumpSecLabel(fout, labelq->data,
 
7361
                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
7362
                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
7363
 
 
7364
        PQclear(res);
 
7365
        destroyPQExpBuffer(q);
 
7366
        destroyPQExpBuffer(delq);
 
7367
        destroyPQExpBuffer(labelq);
 
7368
        destroyPQExpBuffer(query);
 
7369
}
 
7370
 
 
7371
/*
 
7372
 * dumpBaseType
 
7373
 *        writes out to fout the queries to recreate a user-defined base type
 
7374
 */
 
7375
static void
 
7376
dumpBaseType(Archive *fout, TypeInfo *tyinfo)
 
7377
{
 
7378
        PQExpBuffer q = createPQExpBuffer();
 
7379
        PQExpBuffer delq = createPQExpBuffer();
 
7380
        PQExpBuffer labelq = createPQExpBuffer();
 
7381
        PQExpBuffer query = createPQExpBuffer();
 
7382
        PGresult   *res;
 
7383
        int                     ntups;
 
7384
        char       *typlen;
 
7385
        char       *typinput;
 
7386
        char       *typoutput;
 
7387
        char       *typreceive;
 
7388
        char       *typsend;
 
7389
        char       *typmodin;
 
7390
        char       *typmodout;
 
7391
        char       *typanalyze;
 
7392
        Oid                     typreceiveoid;
 
7393
        Oid                     typsendoid;
 
7394
        Oid                     typmodinoid;
 
7395
        Oid                     typmodoutoid;
 
7396
        Oid                     typanalyzeoid;
 
7397
        char       *typcategory;
 
7398
        char       *typispreferred;
 
7399
        char       *typdelim;
 
7400
        char       *typbyval;
 
7401
        char       *typalign;
 
7402
        char       *typstorage;
 
7403
        char       *typcollatable;
 
7404
        char       *typdefault;
 
7405
        bool            typdefault_is_literal = false;
 
7406
 
 
7407
        /* Set proper schema search path so regproc references list correctly */
 
7408
        selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
 
7409
 
 
7410
        /* Fetch type-specific details */
 
7411
        if (fout->remoteVersion >= 90100)
 
7412
        {
 
7413
                appendPQExpBuffer(query, "SELECT typlen, "
 
7414
                                                  "typinput, typoutput, typreceive, typsend, "
 
7415
                                                  "typmodin, typmodout, typanalyze, "
 
7416
                                                  "typreceive::pg_catalog.oid AS typreceiveoid, "
 
7417
                                                  "typsend::pg_catalog.oid AS typsendoid, "
 
7418
                                                  "typmodin::pg_catalog.oid AS typmodinoid, "
 
7419
                                                  "typmodout::pg_catalog.oid AS typmodoutoid, "
 
7420
                                                  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
 
7421
                                                  "typcategory, typispreferred, "
 
7422
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7423
                                                  "(typcollation <> 0) AS typcollatable, "
 
7424
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
 
7425
                                                  "FROM pg_catalog.pg_type "
 
7426
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7427
                                                  tyinfo->dobj.catId.oid);
 
7428
        }
 
7429
        else if (fout->remoteVersion >= 80400)
 
7430
        {
 
7431
                appendPQExpBuffer(query, "SELECT typlen, "
 
7432
                                                  "typinput, typoutput, typreceive, typsend, "
 
7433
                                                  "typmodin, typmodout, typanalyze, "
 
7434
                                                  "typreceive::pg_catalog.oid AS typreceiveoid, "
 
7435
                                                  "typsend::pg_catalog.oid AS typsendoid, "
 
7436
                                                  "typmodin::pg_catalog.oid AS typmodinoid, "
 
7437
                                                  "typmodout::pg_catalog.oid AS typmodoutoid, "
 
7438
                                                  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
 
7439
                                                  "typcategory, typispreferred, "
 
7440
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7441
                                                  "false AS typcollatable, "
 
7442
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
 
7443
                                                  "FROM pg_catalog.pg_type "
 
7444
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7445
                                                  tyinfo->dobj.catId.oid);
 
7446
        }
 
7447
        else if (fout->remoteVersion >= 80300)
 
7448
        {
 
7449
                /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
 
7450
                appendPQExpBuffer(query, "SELECT typlen, "
 
7451
                                                  "typinput, typoutput, typreceive, typsend, "
 
7452
                                                  "typmodin, typmodout, typanalyze, "
 
7453
                                                  "typreceive::pg_catalog.oid AS typreceiveoid, "
 
7454
                                                  "typsend::pg_catalog.oid AS typsendoid, "
 
7455
                                                  "typmodin::pg_catalog.oid AS typmodinoid, "
 
7456
                                                  "typmodout::pg_catalog.oid AS typmodoutoid, "
 
7457
                                                  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
 
7458
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7459
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7460
                                                  "false AS typcollatable, "
 
7461
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
 
7462
                                                  "FROM pg_catalog.pg_type "
 
7463
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7464
                                                  tyinfo->dobj.catId.oid);
 
7465
        }
 
7466
        else if (fout->remoteVersion >= 80000)
 
7467
        {
 
7468
                appendPQExpBuffer(query, "SELECT typlen, "
 
7469
                                                  "typinput, typoutput, typreceive, typsend, "
 
7470
                                                  "'-' AS typmodin, '-' AS typmodout, "
 
7471
                                                  "typanalyze, "
 
7472
                                                  "typreceive::pg_catalog.oid AS typreceiveoid, "
 
7473
                                                  "typsend::pg_catalog.oid AS typsendoid, "
 
7474
                                                  "0 AS typmodinoid, 0 AS typmodoutoid, "
 
7475
                                                  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
 
7476
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7477
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7478
                                                  "false AS typcollatable, "
 
7479
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
 
7480
                                                  "FROM pg_catalog.pg_type "
 
7481
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7482
                                                  tyinfo->dobj.catId.oid);
 
7483
        }
 
7484
        else if (fout->remoteVersion >= 70400)
 
7485
        {
 
7486
                appendPQExpBuffer(query, "SELECT typlen, "
 
7487
                                                  "typinput, typoutput, typreceive, typsend, "
 
7488
                                                  "'-' AS typmodin, '-' AS typmodout, "
 
7489
                                                  "'-' AS typanalyze, "
 
7490
                                                  "typreceive::pg_catalog.oid AS typreceiveoid, "
 
7491
                                                  "typsend::pg_catalog.oid AS typsendoid, "
 
7492
                                                  "0 AS typmodinoid, 0 AS typmodoutoid, "
 
7493
                                                  "0 AS typanalyzeoid, "
 
7494
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7495
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7496
                                                  "false AS typcollatable, "
 
7497
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
 
7498
                                                  "FROM pg_catalog.pg_type "
 
7499
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7500
                                                  tyinfo->dobj.catId.oid);
 
7501
        }
 
7502
        else if (fout->remoteVersion >= 70300)
 
7503
        {
 
7504
                appendPQExpBuffer(query, "SELECT typlen, "
 
7505
                                                  "typinput, typoutput, "
 
7506
                                                  "'-' AS typreceive, '-' AS typsend, "
 
7507
                                                  "'-' AS typmodin, '-' AS typmodout, "
 
7508
                                                  "'-' AS typanalyze, "
 
7509
                                                  "0 AS typreceiveoid, 0 AS typsendoid, "
 
7510
                                                  "0 AS typmodinoid, 0 AS typmodoutoid, "
 
7511
                                                  "0 AS typanalyzeoid, "
 
7512
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7513
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7514
                                                  "false AS typcollatable, "
 
7515
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
 
7516
                                                  "FROM pg_catalog.pg_type "
 
7517
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7518
                                                  tyinfo->dobj.catId.oid);
 
7519
        }
 
7520
        else if (fout->remoteVersion >= 70200)
 
7521
        {
 
7522
                /*
 
7523
                 * Note: although pre-7.3 catalogs contain typreceive and typsend,
 
7524
                 * ignore them because they are not right.
 
7525
                 */
 
7526
                appendPQExpBuffer(query, "SELECT typlen, "
 
7527
                                                  "typinput, typoutput, "
 
7528
                                                  "'-' AS typreceive, '-' AS typsend, "
 
7529
                                                  "'-' AS typmodin, '-' AS typmodout, "
 
7530
                                                  "'-' AS typanalyze, "
 
7531
                                                  "0 AS typreceiveoid, 0 AS typsendoid, "
 
7532
                                                  "0 AS typmodinoid, 0 AS typmodoutoid, "
 
7533
                                                  "0 AS typanalyzeoid, "
 
7534
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7535
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7536
                                                  "false AS typcollatable, "
 
7537
                                                  "NULL AS typdefaultbin, typdefault "
 
7538
                                                  "FROM pg_type "
 
7539
                                                  "WHERE oid = '%u'::oid",
 
7540
                                                  tyinfo->dobj.catId.oid);
 
7541
        }
 
7542
        else if (fout->remoteVersion >= 70100)
 
7543
        {
 
7544
                /*
 
7545
                 * Ignore pre-7.2 typdefault; the field exists but has an unusable
 
7546
                 * representation.
 
7547
                 */
 
7548
                appendPQExpBuffer(query, "SELECT typlen, "
 
7549
                                                  "typinput, typoutput, "
 
7550
                                                  "'-' AS typreceive, '-' AS typsend, "
 
7551
                                                  "'-' AS typmodin, '-' AS typmodout, "
 
7552
                                                  "'-' AS typanalyze, "
 
7553
                                                  "0 AS typreceiveoid, 0 AS typsendoid, "
 
7554
                                                  "0 AS typmodinoid, 0 AS typmodoutoid, "
 
7555
                                                  "0 AS typanalyzeoid, "
 
7556
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7557
                                                  "typdelim, typbyval, typalign, typstorage, "
 
7558
                                                  "false AS typcollatable, "
 
7559
                                                  "NULL AS typdefaultbin, NULL AS typdefault "
 
7560
                                                  "FROM pg_type "
 
7561
                                                  "WHERE oid = '%u'::oid",
 
7562
                                                  tyinfo->dobj.catId.oid);
 
7563
        }
 
7564
        else
 
7565
        {
 
7566
                appendPQExpBuffer(query, "SELECT typlen, "
 
7567
                                                  "typinput, typoutput, "
 
7568
                                                  "'-' AS typreceive, '-' AS typsend, "
 
7569
                                                  "'-' AS typmodin, '-' AS typmodout, "
 
7570
                                                  "'-' AS typanalyze, "
 
7571
                                                  "0 AS typreceiveoid, 0 AS typsendoid, "
 
7572
                                                  "0 AS typmodinoid, 0 AS typmodoutoid, "
 
7573
                                                  "0 AS typanalyzeoid, "
 
7574
                                                  "'U' AS typcategory, false AS typispreferred, "
 
7575
                                                  "typdelim, typbyval, typalign, "
 
7576
                                                  "'p'::char AS typstorage, "
 
7577
                                                  "false AS typcollatable, "
 
7578
                                                  "NULL AS typdefaultbin, NULL AS typdefault "
 
7579
                                                  "FROM pg_type "
 
7580
                                                  "WHERE oid = '%u'::oid",
 
7581
                                                  tyinfo->dobj.catId.oid);
 
7582
        }
 
7583
 
 
7584
        res = PQexec(g_conn, query->data);
 
7585
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
7586
 
 
7587
        /* Expecting a single result only */
 
7588
        ntups = PQntuples(res);
 
7589
        if (ntups != 1)
 
7590
        {
 
7591
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
7592
                                                           "query returned %d rows instead of one: %s\n",
 
7593
                                                                 ntups),
 
7594
                                  ntups, query->data);
 
7595
                exit_nicely();
 
7596
        }
 
7597
 
 
7598
        typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
 
7599
        typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
 
7600
        typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
 
7601
        typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
 
7602
        typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
 
7603
        typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
 
7604
        typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
 
7605
        typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
 
7606
        typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
 
7607
        typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
 
7608
        typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
 
7609
        typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
 
7610
        typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
 
7611
        typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
 
7612
        typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
 
7613
        typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
 
7614
        typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
 
7615
        typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
 
7616
        typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
 
7617
        typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
 
7618
        if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
 
7619
                typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
 
7620
        else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
 
7621
        {
 
7622
                typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
 
7623
                typdefault_is_literal = true;   /* it needs quotes */
 
7624
        }
 
7625
        else
 
7626
                typdefault = NULL;
 
7627
 
 
7628
        /*
 
7629
         * DROP must be fully qualified in case same name appears in pg_catalog.
 
7630
         * The reason we include CASCADE is that the circular dependency between
 
7631
         * the type and its I/O functions makes it impossible to drop the type any
 
7632
         * other way.
 
7633
         */
 
7634
        appendPQExpBuffer(delq, "DROP TYPE %s.",
 
7635
                                          fmtId(tyinfo->dobj.namespace->dobj.name));
 
7636
        appendPQExpBuffer(delq, "%s CASCADE;\n",
 
7637
                                          fmtId(tyinfo->dobj.name));
 
7638
 
 
7639
        /* We might already have a shell type, but setting pg_type_oid is harmless */
 
7640
        if (binary_upgrade)
 
7641
                binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
 
7642
 
 
7643
        appendPQExpBuffer(q,
 
7644
                                          "CREATE TYPE %s (\n"
 
7645
                                          "    INTERNALLENGTH = %s",
 
7646
                                          fmtId(tyinfo->dobj.name),
 
7647
                                          (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
 
7648
 
 
7649
        if (fout->remoteVersion >= 70300)
 
7650
        {
 
7651
                /* regproc result is correctly quoted as of 7.3 */
 
7652
                appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
 
7653
                appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
 
7654
                if (OidIsValid(typreceiveoid))
 
7655
                        appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
 
7656
                if (OidIsValid(typsendoid))
 
7657
                        appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
 
7658
                if (OidIsValid(typmodinoid))
 
7659
                        appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
 
7660
                if (OidIsValid(typmodoutoid))
 
7661
                        appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
 
7662
                if (OidIsValid(typanalyzeoid))
 
7663
                        appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
 
7664
        }
 
7665
        else
 
7666
        {
 
7667
                /* regproc delivers an unquoted name before 7.3 */
 
7668
                /* cannot combine these because fmtId uses static result area */
 
7669
                appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
 
7670
                appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
 
7671
                /* receive/send/typmodin/typmodout/analyze need not be printed */
 
7672
        }
 
7673
 
 
7674
        if (strcmp(typcollatable, "t") == 0)
 
7675
                appendPQExpBuffer(q, ",\n    COLLATABLE = true");
 
7676
 
 
7677
        if (typdefault != NULL)
 
7678
        {
 
7679
                appendPQExpBuffer(q, ",\n    DEFAULT = ");
 
7680
                if (typdefault_is_literal)
 
7681
                        appendStringLiteralAH(q, typdefault, fout);
 
7682
                else
 
7683
                        appendPQExpBufferStr(q, typdefault);
 
7684
        }
 
7685
 
 
7686
        if (OidIsValid(tyinfo->typelem))
 
7687
        {
 
7688
                char       *elemType;
 
7689
 
 
7690
                /* reselect schema in case changed by function dump */
 
7691
                selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
 
7692
                elemType = getFormattedTypeName(tyinfo->typelem, zeroAsOpaque);
 
7693
                appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
 
7694
                free(elemType);
 
7695
        }
 
7696
 
 
7697
        if (strcmp(typcategory, "U") != 0)
 
7698
        {
 
7699
                appendPQExpBuffer(q, ",\n    CATEGORY = ");
 
7700
                appendStringLiteralAH(q, typcategory, fout);
 
7701
        }
 
7702
 
 
7703
        if (strcmp(typispreferred, "t") == 0)
 
7704
                appendPQExpBuffer(q, ",\n    PREFERRED = true");
 
7705
 
 
7706
        if (typdelim && strcmp(typdelim, ",") != 0)
 
7707
        {
 
7708
                appendPQExpBuffer(q, ",\n    DELIMITER = ");
 
7709
                appendStringLiteralAH(q, typdelim, fout);
 
7710
        }
 
7711
 
 
7712
        if (strcmp(typalign, "c") == 0)
 
7713
                appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
 
7714
        else if (strcmp(typalign, "s") == 0)
 
7715
                appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
 
7716
        else if (strcmp(typalign, "i") == 0)
 
7717
                appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
 
7718
        else if (strcmp(typalign, "d") == 0)
 
7719
                appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
 
7720
 
 
7721
        if (strcmp(typstorage, "p") == 0)
 
7722
                appendPQExpBuffer(q, ",\n    STORAGE = plain");
 
7723
        else if (strcmp(typstorage, "e") == 0)
 
7724
                appendPQExpBuffer(q, ",\n    STORAGE = external");
 
7725
        else if (strcmp(typstorage, "x") == 0)
 
7726
                appendPQExpBuffer(q, ",\n    STORAGE = extended");
 
7727
        else if (strcmp(typstorage, "m") == 0)
 
7728
                appendPQExpBuffer(q, ",\n    STORAGE = main");
 
7729
 
 
7730
        if (strcmp(typbyval, "t") == 0)
 
7731
                appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
 
7732
 
 
7733
        appendPQExpBuffer(q, "\n);\n");
 
7734
 
 
7735
        appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
 
7736
 
 
7737
        if (binary_upgrade)
 
7738
                binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
7739
 
 
7740
        ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 
7741
                                 tyinfo->dobj.name,
 
7742
                                 tyinfo->dobj.namespace->dobj.name,
 
7743
                                 NULL,
 
7744
                                 tyinfo->rolname, false,
 
7745
                                 "TYPE", SECTION_PRE_DATA,
 
7746
                                 q->data, delq->data, NULL,
 
7747
                                 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
 
7748
                                 NULL, NULL);
 
7749
 
 
7750
        /* Dump Type Comments and Security Labels */
 
7751
        dumpComment(fout, labelq->data,
 
7752
                                tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
7753
                                tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
7754
        dumpSecLabel(fout, labelq->data,
 
7755
                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
7756
                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
7757
 
 
7758
        PQclear(res);
 
7759
        destroyPQExpBuffer(q);
 
7760
        destroyPQExpBuffer(delq);
 
7761
        destroyPQExpBuffer(labelq);
 
7762
        destroyPQExpBuffer(query);
 
7763
}
 
7764
 
 
7765
/*
 
7766
 * dumpDomain
 
7767
 *        writes out to fout the queries to recreate a user-defined domain
 
7768
 */
 
7769
static void
 
7770
dumpDomain(Archive *fout, TypeInfo *tyinfo)
 
7771
{
 
7772
        PQExpBuffer q = createPQExpBuffer();
 
7773
        PQExpBuffer delq = createPQExpBuffer();
 
7774
        PQExpBuffer labelq = createPQExpBuffer();
 
7775
        PQExpBuffer query = createPQExpBuffer();
 
7776
        PGresult   *res;
 
7777
        int                     ntups;
 
7778
        int                     i;
 
7779
        char       *typnotnull;
 
7780
        char       *typdefn;
 
7781
        char       *typdefault;
 
7782
        Oid                     typcollation;
 
7783
        bool            typdefault_is_literal = false;
 
7784
 
 
7785
        /* Set proper schema search path so type references list correctly */
 
7786
        selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
 
7787
 
 
7788
        /* Fetch domain specific details */
 
7789
        if (g_fout->remoteVersion >= 90100)
 
7790
        {
 
7791
                /* typcollation is new in 9.1 */
 
7792
                appendPQExpBuffer(query, "SELECT t.typnotnull, "
 
7793
                        "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
 
7794
                                                  "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
 
7795
                                                  "t.typdefault, "
 
7796
                                                  "CASE WHEN t.typcollation <> u.typcollation "
 
7797
                                                  "THEN t.typcollation ELSE 0 END AS typcollation "
 
7798
                                                  "FROM pg_catalog.pg_type t "
 
7799
                                 "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
 
7800
                                                  "WHERE t.oid = '%u'::pg_catalog.oid",
 
7801
                                                  tyinfo->dobj.catId.oid);
 
7802
        }
 
7803
        else
 
7804
        {
 
7805
                /* We assume here that remoteVersion must be at least 70300 */
 
7806
                appendPQExpBuffer(query, "SELECT typnotnull, "
 
7807
                                "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
 
7808
                                                  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
 
7809
                                                  "typdefault, 0 AS typcollation "
 
7810
                                                  "FROM pg_catalog.pg_type "
 
7811
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
7812
                                                  tyinfo->dobj.catId.oid);
 
7813
        }
 
7814
 
 
7815
        res = PQexec(g_conn, query->data);
 
7816
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
7817
 
 
7818
        /* Expecting a single result only */
 
7819
        ntups = PQntuples(res);
 
7820
        if (ntups != 1)
 
7821
        {
 
7822
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
7823
                                                           "query returned %d rows instead of one: %s\n",
 
7824
                                                                 ntups),
 
7825
                                  ntups, query->data);
 
7826
                exit_nicely();
 
7827
        }
 
7828
 
 
7829
        typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
 
7830
        typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
 
7831
        if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
 
7832
                typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
 
7833
        else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
 
7834
        {
 
7835
                typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
 
7836
                typdefault_is_literal = true;   /* it needs quotes */
 
7837
        }
 
7838
        else
 
7839
                typdefault = NULL;
 
7840
        typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
 
7841
 
 
7842
        if (binary_upgrade)
 
7843
                binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
 
7844
 
 
7845
        appendPQExpBuffer(q,
 
7846
                                          "CREATE DOMAIN %s AS %s",
 
7847
                                          fmtId(tyinfo->dobj.name),
 
7848
                                          typdefn);
 
7849
 
 
7850
        /* Print collation only if different from base type's collation */
 
7851
        if (OidIsValid(typcollation))
 
7852
        {
 
7853
                CollInfo   *coll;
 
7854
 
 
7855
                coll = findCollationByOid(typcollation);
 
7856
                if (coll)
 
7857
                {
 
7858
                        /* always schema-qualify, don't try to be smart */
 
7859
                        appendPQExpBuffer(q, " COLLATE %s.",
 
7860
                                                          fmtId(coll->dobj.namespace->dobj.name));
 
7861
                        appendPQExpBuffer(q, "%s",
 
7862
                                                          fmtId(coll->dobj.name));
 
7863
                }
 
7864
        }
 
7865
 
 
7866
        if (typnotnull[0] == 't')
 
7867
                appendPQExpBuffer(q, " NOT NULL");
 
7868
 
 
7869
        if (typdefault != NULL)
 
7870
        {
 
7871
                appendPQExpBuffer(q, " DEFAULT ");
 
7872
                if (typdefault_is_literal)
 
7873
                        appendStringLiteralAH(q, typdefault, fout);
 
7874
                else
 
7875
                        appendPQExpBufferStr(q, typdefault);
 
7876
        }
 
7877
 
 
7878
        PQclear(res);
 
7879
 
 
7880
        /*
 
7881
         * Add any CHECK constraints for the domain
 
7882
         */
 
7883
        for (i = 0; i < tyinfo->nDomChecks; i++)
 
7884
        {
 
7885
                ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
 
7886
 
 
7887
                if (!domcheck->separate)
 
7888
                        appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
 
7889
                                                          fmtId(domcheck->dobj.name), domcheck->condef);
 
7890
        }
 
7891
 
 
7892
        appendPQExpBuffer(q, ";\n");
 
7893
 
 
7894
        /*
 
7895
         * DROP must be fully qualified in case same name appears in pg_catalog
 
7896
         */
 
7897
        appendPQExpBuffer(delq, "DROP DOMAIN %s.",
 
7898
                                          fmtId(tyinfo->dobj.namespace->dobj.name));
 
7899
        appendPQExpBuffer(delq, "%s;\n",
 
7900
                                          fmtId(tyinfo->dobj.name));
 
7901
 
 
7902
        appendPQExpBuffer(labelq, "DOMAIN %s", fmtId(tyinfo->dobj.name));
 
7903
 
 
7904
        if (binary_upgrade)
 
7905
                binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
7906
 
 
7907
        ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 
7908
                                 tyinfo->dobj.name,
 
7909
                                 tyinfo->dobj.namespace->dobj.name,
 
7910
                                 NULL,
 
7911
                                 tyinfo->rolname, false,
 
7912
                                 "DOMAIN", SECTION_PRE_DATA,
 
7913
                                 q->data, delq->data, NULL,
 
7914
                                 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
 
7915
                                 NULL, NULL);
 
7916
 
 
7917
        /* Dump Domain Comments and Security Labels */
 
7918
        dumpComment(fout, labelq->data,
 
7919
                                tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
7920
                                tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
7921
        dumpSecLabel(fout, labelq->data,
 
7922
                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
7923
                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
7924
 
 
7925
        destroyPQExpBuffer(q);
 
7926
        destroyPQExpBuffer(delq);
 
7927
        destroyPQExpBuffer(labelq);
 
7928
        destroyPQExpBuffer(query);
 
7929
}
 
7930
 
 
7931
/*
 
7932
 * dumpCompositeType
 
7933
 *        writes out to fout the queries to recreate a user-defined stand-alone
 
7934
 *        composite type
 
7935
 */
 
7936
static void
 
7937
dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
 
7938
{
 
7939
        PQExpBuffer q = createPQExpBuffer();
 
7940
        PQExpBuffer delq = createPQExpBuffer();
 
7941
        PQExpBuffer labelq = createPQExpBuffer();
 
7942
        PQExpBuffer query = createPQExpBuffer();
 
7943
        PGresult   *res;
 
7944
        int                     ntups;
 
7945
        int                     i_attname;
 
7946
        int                     i_atttypdefn;
 
7947
        int                     i_attcollation;
 
7948
        int                     i_typrelid;
 
7949
        int                     i;
 
7950
 
 
7951
        /* Set proper schema search path so type references list correctly */
 
7952
        selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
 
7953
 
 
7954
        /* Fetch type specific details */
 
7955
        if (fout->remoteVersion >= 90100)
 
7956
        {
 
7957
                /*
 
7958
                 * attcollation is new in 9.1.  Since we only want to dump COLLATE
 
7959
                 * clauses for attributes whose collation is different from their
 
7960
                 * type's default, we use a CASE here to suppress uninteresting
 
7961
                 * attcollations cheaply.
 
7962
                 */
 
7963
                appendPQExpBuffer(query, "SELECT a.attname, "
 
7964
                                                  "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
 
7965
                                                  "CASE WHEN a.attcollation <> at.typcollation "
 
7966
                                                  "THEN a.attcollation ELSE 0 END AS attcollation, "
 
7967
                                                  "ct.typrelid "
 
7968
                                                  "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a, "
 
7969
                                                  "pg_catalog.pg_type at "
 
7970
                                                  "WHERE ct.oid = '%u'::pg_catalog.oid "
 
7971
                                                  "AND a.attrelid = ct.typrelid "
 
7972
                                                  "AND a.atttypid = at.oid "
 
7973
                                                  "AND NOT a.attisdropped "
 
7974
                                                  "ORDER BY a.attnum ",
 
7975
                                                  tyinfo->dobj.catId.oid);
 
7976
        }
 
7977
        else
 
7978
        {
 
7979
                /* We assume here that remoteVersion must be at least 70300 */
 
7980
                appendPQExpBuffer(query, "SELECT a.attname, "
 
7981
                                                  "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
 
7982
                                                  "0 AS attcollation, "
 
7983
                                                  "ct.typrelid "
 
7984
                                                  "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
 
7985
                                                  "WHERE ct.oid = '%u'::pg_catalog.oid "
 
7986
                                                  "AND a.attrelid = ct.typrelid "
 
7987
                                                  "AND NOT a.attisdropped "
 
7988
                                                  "ORDER BY a.attnum ",
 
7989
                                                  tyinfo->dobj.catId.oid);
 
7990
        }
 
7991
 
 
7992
        res = PQexec(g_conn, query->data);
 
7993
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
7994
 
 
7995
        ntups = PQntuples(res);
 
7996
 
 
7997
        i_attname = PQfnumber(res, "attname");
 
7998
        i_atttypdefn = PQfnumber(res, "atttypdefn");
 
7999
        i_attcollation = PQfnumber(res, "attcollation");
 
8000
        i_typrelid = PQfnumber(res, "typrelid");
 
8001
 
 
8002
        if (binary_upgrade)
 
8003
        {
 
8004
                Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
 
8005
 
 
8006
                binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
 
8007
                binary_upgrade_set_pg_class_oids(q, typrelid, false);
 
8008
        }
 
8009
 
 
8010
        appendPQExpBuffer(q, "CREATE TYPE %s AS (",
 
8011
                                          fmtId(tyinfo->dobj.name));
 
8012
 
 
8013
        for (i = 0; i < ntups; i++)
 
8014
        {
 
8015
                char       *attname;
 
8016
                char       *atttypdefn;
 
8017
                Oid                     attcollation;
 
8018
 
 
8019
                attname = PQgetvalue(res, i, i_attname);
 
8020
                atttypdefn = PQgetvalue(res, i, i_atttypdefn);
 
8021
                attcollation = atooid(PQgetvalue(res, i, i_attcollation));
 
8022
 
 
8023
                appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
 
8024
 
 
8025
                /* Add collation if not default for the column type */
 
8026
                if (OidIsValid(attcollation))
 
8027
                {
 
8028
                        CollInfo   *coll;
 
8029
 
 
8030
                        coll = findCollationByOid(attcollation);
 
8031
                        if (coll)
 
8032
                        {
 
8033
                                /* always schema-qualify, don't try to be smart */
 
8034
                                appendPQExpBuffer(q, " COLLATE %s.",
 
8035
                                                                  fmtId(coll->dobj.namespace->dobj.name));
 
8036
                                appendPQExpBuffer(q, "%s",
 
8037
                                                                  fmtId(coll->dobj.name));
 
8038
                        }
 
8039
                }
 
8040
 
 
8041
                if (i < ntups - 1)
 
8042
                        appendPQExpBuffer(q, ",");
 
8043
        }
 
8044
        appendPQExpBuffer(q, "\n);\n");
 
8045
 
 
8046
        /*
 
8047
         * DROP must be fully qualified in case same name appears in pg_catalog
 
8048
         */
 
8049
        appendPQExpBuffer(delq, "DROP TYPE %s.",
 
8050
                                          fmtId(tyinfo->dobj.namespace->dobj.name));
 
8051
        appendPQExpBuffer(delq, "%s;\n",
 
8052
                                          fmtId(tyinfo->dobj.name));
 
8053
 
 
8054
        appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
 
8055
 
 
8056
        if (binary_upgrade)
 
8057
                binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
 
8058
 
 
8059
        ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
 
8060
                                 tyinfo->dobj.name,
 
8061
                                 tyinfo->dobj.namespace->dobj.name,
 
8062
                                 NULL,
 
8063
                                 tyinfo->rolname, false,
 
8064
                                 "TYPE", SECTION_PRE_DATA,
 
8065
                                 q->data, delq->data, NULL,
 
8066
                                 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
 
8067
                                 NULL, NULL);
 
8068
 
 
8069
 
 
8070
        /* Dump Type Comments and Security Labels */
 
8071
        dumpComment(fout, labelq->data,
 
8072
                                tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
8073
                                tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
8074
        dumpSecLabel(fout, labelq->data,
 
8075
                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
 
8076
                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
 
8077
 
 
8078
        PQclear(res);
 
8079
        destroyPQExpBuffer(q);
 
8080
        destroyPQExpBuffer(delq);
 
8081
        destroyPQExpBuffer(labelq);
 
8082
        destroyPQExpBuffer(query);
 
8083
 
 
8084
        /* Dump any per-column comments */
 
8085
        dumpCompositeTypeColComments(fout, tyinfo);
 
8086
}
 
8087
 
 
8088
/*
 
8089
 * dumpCompositeTypeColComments
 
8090
 *        writes out to fout the queries to recreate comments on the columns of
 
8091
 *        a user-defined stand-alone composite type
 
8092
 */
 
8093
static void
 
8094
dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
 
8095
{
 
8096
        CommentItem *comments;
 
8097
        int                     ncomments;
 
8098
        PGresult   *res;
 
8099
        PQExpBuffer query;
 
8100
        PQExpBuffer target;
 
8101
        Oid                     pgClassOid;
 
8102
        int                     i;
 
8103
        int                     ntups;
 
8104
        int                     i_attname;
 
8105
        int                     i_attnum;
 
8106
 
 
8107
        query = createPQExpBuffer();
 
8108
 
 
8109
        /* We assume here that remoteVersion must be at least 70300 */
 
8110
        appendPQExpBuffer(query,
 
8111
                                          "SELECT c.tableoid, a.attname, a.attnum "
 
8112
                                          "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
 
8113
                                          "WHERE c.oid = '%u' AND c.oid = a.attrelid "
 
8114
                                          "  AND NOT a.attisdropped "
 
8115
                                          "ORDER BY a.attnum ",
 
8116
                                          tyinfo->typrelid);
 
8117
 
 
8118
        /* Fetch column attnames */
 
8119
        res = PQexec(g_conn, query->data);
 
8120
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
8121
 
 
8122
        ntups = PQntuples(res);
 
8123
        if (ntups < 1)
 
8124
        {
 
8125
                PQclear(res);
 
8126
                destroyPQExpBuffer(query);
 
8127
                return;
 
8128
        }
 
8129
 
 
8130
        pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
 
8131
 
 
8132
        /* Search for comments associated with type's pg_class OID */
 
8133
        ncomments = findComments(fout,
 
8134
                                                         pgClassOid,
 
8135
                                                         tyinfo->typrelid,
 
8136
                                                         &comments);
 
8137
 
 
8138
        /* If no comments exist, we're done */
 
8139
        if (ncomments <= 0)
 
8140
        {
 
8141
                PQclear(res);
 
8142
                destroyPQExpBuffer(query);
 
8143
                return;
 
8144
        }
 
8145
 
 
8146
        /* Build COMMENT ON statements */
 
8147
        target = createPQExpBuffer();
 
8148
 
 
8149
        i_attnum = PQfnumber(res, "attnum");
 
8150
        i_attname = PQfnumber(res, "attname");
 
8151
        while (ncomments > 0)
 
8152
        {
 
8153
                const char *attname;
 
8154
 
 
8155
                attname = NULL;
 
8156
                for (i = 0; i < ntups; i++)
 
8157
                {
 
8158
                        if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
 
8159
                        {
 
8160
                                attname = PQgetvalue(res, i, i_attname);
 
8161
                                break;
 
8162
                        }
 
8163
                }
 
8164
                if (attname)                    /* just in case we don't find it */
 
8165
                {
 
8166
                        const char *descr = comments->descr;
 
8167
 
 
8168
                        resetPQExpBuffer(target);
 
8169
                        appendPQExpBuffer(target, "COLUMN %s.",
 
8170
                                                          fmtId(tyinfo->dobj.name));
 
8171
                        appendPQExpBuffer(target, "%s",
 
8172
                                                          fmtId(attname));
 
8173
 
 
8174
                        resetPQExpBuffer(query);
 
8175
                        appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
 
8176
                        appendStringLiteralAH(query, descr, fout);
 
8177
                        appendPQExpBuffer(query, ";\n");
 
8178
 
 
8179
                        ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
8180
                                                 target->data,
 
8181
                                                 tyinfo->dobj.namespace->dobj.name,
 
8182
                                                 NULL, tyinfo->rolname,
 
8183
                                                 false, "COMMENT", SECTION_NONE,
 
8184
                                                 query->data, "", NULL,
 
8185
                                                 &(tyinfo->dobj.dumpId), 1,
 
8186
                                                 NULL, NULL);
 
8187
                }
 
8188
 
 
8189
                comments++;
 
8190
                ncomments--;
 
8191
        }
 
8192
 
 
8193
        PQclear(res);
 
8194
        destroyPQExpBuffer(query);
 
8195
        destroyPQExpBuffer(target);
 
8196
}
 
8197
 
 
8198
/*
 
8199
 * dumpShellType
 
8200
 *        writes out to fout the queries to create a shell type
 
8201
 *
 
8202
 * We dump a shell definition in advance of the I/O functions for the type.
 
8203
 */
 
8204
static void
 
8205
dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
 
8206
{
 
8207
        PQExpBuffer q;
 
8208
 
 
8209
        /* Skip if not to be dumped */
 
8210
        if (!stinfo->dobj.dump || dataOnly)
 
8211
                return;
 
8212
 
 
8213
        q = createPQExpBuffer();
 
8214
 
 
8215
        /*
 
8216
         * Note the lack of a DROP command for the shell type; any required DROP
 
8217
         * is driven off the base type entry, instead.  This interacts with
 
8218
         * _printTocEntry()'s use of the presence of a DROP command to decide
 
8219
         * whether an entry needs an ALTER OWNER command.  We don't want to alter
 
8220
         * the shell type's owner immediately on creation; that should happen only
 
8221
         * after it's filled in, otherwise the backend complains.
 
8222
         */
 
8223
 
 
8224
        if (binary_upgrade)
 
8225
                binary_upgrade_set_type_oids_by_type_oid(q,
 
8226
                                                                                   stinfo->baseType->dobj.catId.oid);
 
8227
 
 
8228
        appendPQExpBuffer(q, "CREATE TYPE %s;\n",
 
8229
                                          fmtId(stinfo->dobj.name));
 
8230
 
 
8231
        ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
 
8232
                                 stinfo->dobj.name,
 
8233
                                 stinfo->dobj.namespace->dobj.name,
 
8234
                                 NULL,
 
8235
                                 stinfo->baseType->rolname, false,
 
8236
                                 "SHELL TYPE", SECTION_PRE_DATA,
 
8237
                                 q->data, "", NULL,
 
8238
                                 stinfo->dobj.dependencies, stinfo->dobj.nDeps,
 
8239
                                 NULL, NULL);
 
8240
 
 
8241
        destroyPQExpBuffer(q);
 
8242
}
 
8243
 
 
8244
/*
 
8245
 * Determine whether we want to dump definitions for procedural languages.
 
8246
 * Since the languages themselves don't have schemas, we can't rely on
 
8247
 * the normal schema-based selection mechanism.  We choose to dump them
 
8248
 * whenever neither --schema nor --table was given.  (Before 8.1, we used
 
8249
 * the dump flag of the PL's call handler function, but in 8.1 this will
 
8250
 * probably always be false since call handlers are created in pg_catalog.)
 
8251
 *
 
8252
 * For some backwards compatibility with the older behavior, we forcibly
 
8253
 * dump a PL if its handler function (and validator if any) are in a
 
8254
 * dumpable namespace.  That case is not checked here.
 
8255
 */
 
8256
static bool
 
8257
shouldDumpProcLangs(void)
 
8258
{
 
8259
        if (!include_everything)
 
8260
                return false;
 
8261
        /* And they're schema not data */
 
8262
        if (dataOnly)
 
8263
                return false;
 
8264
        return true;
 
8265
}
 
8266
 
 
8267
/*
 
8268
 * dumpProcLang
 
8269
 *                writes out to fout the queries to recreate a user-defined
 
8270
 *                procedural language
 
8271
 */
 
8272
static void
 
8273
dumpProcLang(Archive *fout, ProcLangInfo *plang)
 
8274
{
 
8275
        PQExpBuffer defqry;
 
8276
        PQExpBuffer delqry;
 
8277
        PQExpBuffer labelq;
 
8278
        bool            useParams;
 
8279
        char       *qlanname;
 
8280
        char       *lanschema;
 
8281
        FuncInfo   *funcInfo;
 
8282
        FuncInfo   *inlineInfo = NULL;
 
8283
        FuncInfo   *validatorInfo = NULL;
 
8284
 
 
8285
        /* Skip if not to be dumped */
 
8286
        if (!plang->dobj.dump || dataOnly)
 
8287
                return;
 
8288
 
 
8289
        /*
 
8290
         * Try to find the support function(s).  It is not an error if we don't
 
8291
         * find them --- if the functions are in the pg_catalog schema, as is
 
8292
         * standard in 8.1 and up, then we won't have loaded them. (In this case
 
8293
         * we will emit a parameterless CREATE LANGUAGE command, which will
 
8294
         * require PL template knowledge in the backend to reload.)
 
8295
         */
 
8296
 
 
8297
        funcInfo = findFuncByOid(plang->lanplcallfoid);
 
8298
        if (funcInfo != NULL && !funcInfo->dobj.dump)
 
8299
                funcInfo = NULL;                /* treat not-dumped same as not-found */
 
8300
 
 
8301
        if (OidIsValid(plang->laninline))
 
8302
        {
 
8303
                inlineInfo = findFuncByOid(plang->laninline);
 
8304
                if (inlineInfo != NULL && !inlineInfo->dobj.dump)
 
8305
                        inlineInfo = NULL;
 
8306
        }
 
8307
 
 
8308
        if (OidIsValid(plang->lanvalidator))
 
8309
        {
 
8310
                validatorInfo = findFuncByOid(plang->lanvalidator);
 
8311
                if (validatorInfo != NULL && !validatorInfo->dobj.dump)
 
8312
                        validatorInfo = NULL;
 
8313
        }
 
8314
 
 
8315
        /*
 
8316
         * If the functions are dumpable then emit a traditional CREATE LANGUAGE
 
8317
         * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
 
8318
         * dump it.
 
8319
         */
 
8320
        useParams = (funcInfo != NULL &&
 
8321
                                 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
 
8322
                                 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
 
8323
 
 
8324
        if (!useParams && !shouldDumpProcLangs())
 
8325
                return;
 
8326
 
 
8327
        defqry = createPQExpBuffer();
 
8328
        delqry = createPQExpBuffer();
 
8329
        labelq = createPQExpBuffer();
 
8330
 
 
8331
        qlanname = strdup(fmtId(plang->dobj.name));
 
8332
 
 
8333
        /*
 
8334
         * If dumping a HANDLER clause, treat the language as being in the handler
 
8335
         * function's schema; this avoids cluttering the HANDLER clause. Otherwise
 
8336
         * it doesn't really have a schema.
 
8337
         */
 
8338
        if (useParams)
 
8339
                lanschema = funcInfo->dobj.namespace->dobj.name;
 
8340
        else
 
8341
                lanschema = NULL;
 
8342
 
 
8343
        appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
 
8344
                                          qlanname);
 
8345
 
 
8346
        if (useParams)
 
8347
        {
 
8348
                appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
 
8349
                                                  plang->lanpltrusted ? "TRUSTED " : "",
 
8350
                                                  qlanname);
 
8351
                appendPQExpBuffer(defqry, " HANDLER %s",
 
8352
                                                  fmtId(funcInfo->dobj.name));
 
8353
                if (OidIsValid(plang->laninline))
 
8354
                {
 
8355
                        appendPQExpBuffer(defqry, " INLINE ");
 
8356
                        /* Cope with possibility that inline is in different schema */
 
8357
                        if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
 
8358
                                appendPQExpBuffer(defqry, "%s.",
 
8359
                                                           fmtId(inlineInfo->dobj.namespace->dobj.name));
 
8360
                        appendPQExpBuffer(defqry, "%s",
 
8361
                                                          fmtId(inlineInfo->dobj.name));
 
8362
                }
 
8363
                if (OidIsValid(plang->lanvalidator))
 
8364
                {
 
8365
                        appendPQExpBuffer(defqry, " VALIDATOR ");
 
8366
                        /* Cope with possibility that validator is in different schema */
 
8367
                        if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
 
8368
                                appendPQExpBuffer(defqry, "%s.",
 
8369
                                                        fmtId(validatorInfo->dobj.namespace->dobj.name));
 
8370
                        appendPQExpBuffer(defqry, "%s",
 
8371
                                                          fmtId(validatorInfo->dobj.name));
 
8372
                }
 
8373
        }
 
8374
        else
 
8375
        {
 
8376
                /*
 
8377
                 * If not dumping parameters, then use CREATE OR REPLACE so that the
 
8378
                 * command will not fail if the language is preinstalled in the target
 
8379
                 * database.  We restrict the use of REPLACE to this case so as to
 
8380
                 * eliminate the risk of replacing a language with incompatible
 
8381
                 * parameter settings: this command will only succeed at all if there
 
8382
                 * is a pg_pltemplate entry, and if there is one, the existing entry
 
8383
                 * must match it too.
 
8384
                 */
 
8385
                appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
 
8386
                                                  qlanname);
 
8387
        }
 
8388
        appendPQExpBuffer(defqry, ";\n");
 
8389
 
 
8390
        appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
 
8391
 
 
8392
        if (binary_upgrade)
 
8393
                binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
 
8394
 
 
8395
        ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
 
8396
                                 plang->dobj.name,
 
8397
                                 lanschema, NULL, plang->lanowner,
 
8398
                                 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
 
8399
                                 defqry->data, delqry->data, NULL,
 
8400
                                 plang->dobj.dependencies, plang->dobj.nDeps,
 
8401
                                 NULL, NULL);
 
8402
 
 
8403
        /* Dump Proc Lang Comments and Security Labels */
 
8404
        dumpComment(fout, labelq->data,
 
8405
                                NULL, "",
 
8406
                                plang->dobj.catId, 0, plang->dobj.dumpId);
 
8407
        dumpSecLabel(fout, labelq->data,
 
8408
                                 NULL, "",
 
8409
                                 plang->dobj.catId, 0, plang->dobj.dumpId);
 
8410
 
 
8411
        if (plang->lanpltrusted)
 
8412
                dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
 
8413
                                qlanname, NULL, plang->dobj.name,
 
8414
                                lanschema,
 
8415
                                plang->lanowner, plang->lanacl);
 
8416
 
 
8417
        free(qlanname);
 
8418
 
 
8419
        destroyPQExpBuffer(defqry);
 
8420
        destroyPQExpBuffer(delqry);
 
8421
        destroyPQExpBuffer(labelq);
 
8422
}
 
8423
 
 
8424
/*
 
8425
 * format_function_arguments: generate function name and argument list
 
8426
 *
 
8427
 * This is used when we can rely on pg_get_function_arguments to format
 
8428
 * the argument list.
 
8429
 */
 
8430
static char *
 
8431
format_function_arguments(FuncInfo *finfo, char *funcargs)
 
8432
{
 
8433
        PQExpBufferData fn;
 
8434
 
 
8435
        initPQExpBuffer(&fn);
 
8436
        appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
 
8437
        return fn.data;
 
8438
}
 
8439
 
 
8440
/*
 
8441
 * format_function_arguments_old: generate function name and argument list
 
8442
 *
 
8443
 * The argument type names are qualified if needed.  The function name
 
8444
 * is never qualified.
 
8445
 *
 
8446
 * This is used only with pre-8.4 servers, so we aren't expecting to see
 
8447
 * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
 
8448
 *
 
8449
 * Any or all of allargtypes, argmodes, argnames may be NULL.
 
8450
 */
 
8451
static char *
 
8452
format_function_arguments_old(FuncInfo *finfo, int nallargs,
 
8453
                                                          char **allargtypes,
 
8454
                                                          char **argmodes,
 
8455
                                                          char **argnames)
 
8456
{
 
8457
        PQExpBufferData fn;
 
8458
        int                     j;
 
8459
 
 
8460
        initPQExpBuffer(&fn);
 
8461
        appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
 
8462
        for (j = 0; j < nallargs; j++)
 
8463
        {
 
8464
                Oid                     typid;
 
8465
                char       *typname;
 
8466
                const char *argmode;
 
8467
                const char *argname;
 
8468
 
 
8469
                typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
 
8470
                typname = getFormattedTypeName(typid, zeroAsOpaque);
 
8471
 
 
8472
                if (argmodes)
 
8473
                {
 
8474
                        switch (argmodes[j][0])
 
8475
                        {
 
8476
                                case PROARGMODE_IN:
 
8477
                                        argmode = "";
 
8478
                                        break;
 
8479
                                case PROARGMODE_OUT:
 
8480
                                        argmode = "OUT ";
 
8481
                                        break;
 
8482
                                case PROARGMODE_INOUT:
 
8483
                                        argmode = "INOUT ";
 
8484
                                        break;
 
8485
                                default:
 
8486
                                        write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
 
8487
                                        argmode = "";
 
8488
                                        break;
 
8489
                        }
 
8490
                }
 
8491
                else
 
8492
                        argmode = "";
 
8493
 
 
8494
                argname = argnames ? argnames[j] : (char *) NULL;
 
8495
                if (argname && argname[0] == '\0')
 
8496
                        argname = NULL;
 
8497
 
 
8498
                appendPQExpBuffer(&fn, "%s%s%s%s%s",
 
8499
                                                  (j > 0) ? ", " : "",
 
8500
                                                  argmode,
 
8501
                                                  argname ? fmtId(argname) : "",
 
8502
                                                  argname ? " " : "",
 
8503
                                                  typname);
 
8504
                free(typname);
 
8505
        }
 
8506
        appendPQExpBuffer(&fn, ")");
 
8507
        return fn.data;
 
8508
}
 
8509
 
 
8510
/*
 
8511
 * format_function_signature: generate function name and argument list
 
8512
 *
 
8513
 * This is like format_function_arguments_old except that only a minimal
 
8514
 * list of input argument types is generated; this is sufficient to
 
8515
 * reference the function, but not to define it.
 
8516
 *
 
8517
 * If honor_quotes is false then the function name is never quoted.
 
8518
 * This is appropriate for use in TOC tags, but not in SQL commands.
 
8519
 */
 
8520
static char *
 
8521
format_function_signature(FuncInfo *finfo, bool honor_quotes)
 
8522
{
 
8523
        PQExpBufferData fn;
 
8524
        int                     j;
 
8525
 
 
8526
        initPQExpBuffer(&fn);
 
8527
        if (honor_quotes)
 
8528
                appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
 
8529
        else
 
8530
                appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
 
8531
        for (j = 0; j < finfo->nargs; j++)
 
8532
        {
 
8533
                char       *typname;
 
8534
 
 
8535
                typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
 
8536
 
 
8537
                appendPQExpBuffer(&fn, "%s%s",
 
8538
                                                  (j > 0) ? ", " : "",
 
8539
                                                  typname);
 
8540
                free(typname);
 
8541
        }
 
8542
        appendPQExpBuffer(&fn, ")");
 
8543
        return fn.data;
 
8544
}
 
8545
 
 
8546
 
 
8547
/*
 
8548
 * dumpFunc:
 
8549
 *        dump out one function
 
8550
 */
 
8551
static void
 
8552
dumpFunc(Archive *fout, FuncInfo *finfo)
 
8553
{
 
8554
        PQExpBuffer query;
 
8555
        PQExpBuffer q;
 
8556
        PQExpBuffer delqry;
 
8557
        PQExpBuffer labelq;
 
8558
        PQExpBuffer asPart;
 
8559
        PGresult   *res;
 
8560
        char       *funcsig;            /* identity signature */
 
8561
        char       *funcfullsig;        /* full signature */
 
8562
        char       *funcsig_tag;
 
8563
        int                     ntups;
 
8564
        char       *proretset;
 
8565
        char       *prosrc;
 
8566
        char       *probin;
 
8567
        char       *funcargs;
 
8568
        char       *funciargs;
 
8569
        char       *funcresult;
 
8570
        char       *proallargtypes;
 
8571
        char       *proargmodes;
 
8572
        char       *proargnames;
 
8573
        char       *proiswindow;
 
8574
        char       *provolatile;
 
8575
        char       *proisstrict;
 
8576
        char       *prosecdef;
 
8577
        char       *proconfig;
 
8578
        char       *procost;
 
8579
        char       *prorows;
 
8580
        char       *lanname;
 
8581
        char       *rettypename;
 
8582
        int                     nallargs;
 
8583
        char      **allargtypes = NULL;
 
8584
        char      **argmodes = NULL;
 
8585
        char      **argnames = NULL;
 
8586
        char      **configitems = NULL;
 
8587
        int                     nconfigitems = 0;
 
8588
        int                     i;
 
8589
 
 
8590
        /* Skip if not to be dumped */
 
8591
        if (!finfo->dobj.dump || dataOnly)
 
8592
                return;
 
8593
 
 
8594
        query = createPQExpBuffer();
 
8595
        q = createPQExpBuffer();
 
8596
        delqry = createPQExpBuffer();
 
8597
        labelq = createPQExpBuffer();
 
8598
        asPart = createPQExpBuffer();
 
8599
 
 
8600
        /* Set proper schema search path so type references list correctly */
 
8601
        selectSourceSchema(finfo->dobj.namespace->dobj.name);
 
8602
 
 
8603
        /* Fetch function-specific details */
 
8604
        if (g_fout->remoteVersion >= 80400)
 
8605
        {
 
8606
                /*
 
8607
                 * In 8.4 and up we rely on pg_get_function_arguments and
 
8608
                 * pg_get_function_result instead of examining proallargtypes etc.
 
8609
                 */
 
8610
                appendPQExpBuffer(query,
 
8611
                                                  "SELECT proretset, prosrc, probin, "
 
8612
                                        "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
 
8613
                  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
 
8614
                                         "pg_catalog.pg_get_function_result(oid) AS funcresult, "
 
8615
                                                  "proiswindow, provolatile, proisstrict, prosecdef, "
 
8616
                                                  "proconfig, procost, prorows, "
 
8617
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
 
8618
                                                  "FROM pg_catalog.pg_proc "
 
8619
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
8620
                                                  finfo->dobj.catId.oid);
 
8621
        }
 
8622
        else if (g_fout->remoteVersion >= 80300)
 
8623
        {
 
8624
                appendPQExpBuffer(query,
 
8625
                                                  "SELECT proretset, prosrc, probin, "
 
8626
                                                  "proallargtypes, proargmodes, proargnames, "
 
8627
                                                  "false AS proiswindow, "
 
8628
                                                  "provolatile, proisstrict, prosecdef, "
 
8629
                                                  "proconfig, procost, prorows, "
 
8630
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
 
8631
                                                  "FROM pg_catalog.pg_proc "
 
8632
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
8633
                                                  finfo->dobj.catId.oid);
 
8634
        }
 
8635
        else if (g_fout->remoteVersion >= 80100)
 
8636
        {
 
8637
                appendPQExpBuffer(query,
 
8638
                                                  "SELECT proretset, prosrc, probin, "
 
8639
                                                  "proallargtypes, proargmodes, proargnames, "
 
8640
                                                  "false AS proiswindow, "
 
8641
                                                  "provolatile, proisstrict, prosecdef, "
 
8642
                                                  "null AS proconfig, 0 AS procost, 0 AS prorows, "
 
8643
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
 
8644
                                                  "FROM pg_catalog.pg_proc "
 
8645
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
8646
                                                  finfo->dobj.catId.oid);
 
8647
        }
 
8648
        else if (g_fout->remoteVersion >= 80000)
 
8649
        {
 
8650
                appendPQExpBuffer(query,
 
8651
                                                  "SELECT proretset, prosrc, probin, "
 
8652
                                                  "null AS proallargtypes, "
 
8653
                                                  "null AS proargmodes, "
 
8654
                                                  "proargnames, "
 
8655
                                                  "false AS proiswindow, "
 
8656
                                                  "provolatile, proisstrict, prosecdef, "
 
8657
                                                  "null AS proconfig, 0 AS procost, 0 AS prorows, "
 
8658
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
 
8659
                                                  "FROM pg_catalog.pg_proc "
 
8660
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
8661
                                                  finfo->dobj.catId.oid);
 
8662
        }
 
8663
        else if (g_fout->remoteVersion >= 70300)
 
8664
        {
 
8665
                appendPQExpBuffer(query,
 
8666
                                                  "SELECT proretset, prosrc, probin, "
 
8667
                                                  "null AS proallargtypes, "
 
8668
                                                  "null AS proargmodes, "
 
8669
                                                  "null AS proargnames, "
 
8670
                                                  "false AS proiswindow, "
 
8671
                                                  "provolatile, proisstrict, prosecdef, "
 
8672
                                                  "null AS proconfig, 0 AS procost, 0 AS prorows, "
 
8673
                                                  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
 
8674
                                                  "FROM pg_catalog.pg_proc "
 
8675
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
8676
                                                  finfo->dobj.catId.oid);
 
8677
        }
 
8678
        else if (g_fout->remoteVersion >= 70100)
 
8679
        {
 
8680
                appendPQExpBuffer(query,
 
8681
                                                  "SELECT proretset, prosrc, probin, "
 
8682
                                                  "null AS proallargtypes, "
 
8683
                                                  "null AS proargmodes, "
 
8684
                                                  "null AS proargnames, "
 
8685
                                                  "false AS proiswindow, "
 
8686
                         "case when proiscachable then 'i' else 'v' end AS provolatile, "
 
8687
                                                  "proisstrict, "
 
8688
                                                  "false AS prosecdef, "
 
8689
                                                  "null AS proconfig, 0 AS procost, 0 AS prorows, "
 
8690
                  "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
 
8691
                                                  "FROM pg_proc "
 
8692
                                                  "WHERE oid = '%u'::oid",
 
8693
                                                  finfo->dobj.catId.oid);
 
8694
        }
 
8695
        else
 
8696
        {
 
8697
                appendPQExpBuffer(query,
 
8698
                                                  "SELECT proretset, prosrc, probin, "
 
8699
                                                  "null AS proallargtypes, "
 
8700
                                                  "null AS proargmodes, "
 
8701
                                                  "null AS proargnames, "
 
8702
                                                  "false AS proiswindow, "
 
8703
                         "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
 
8704
                                                  "false AS proisstrict, "
 
8705
                                                  "false AS prosecdef, "
 
8706
                                                  "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
 
8707
                  "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
 
8708
                                                  "FROM pg_proc "
 
8709
                                                  "WHERE oid = '%u'::oid",
 
8710
                                                  finfo->dobj.catId.oid);
 
8711
        }
 
8712
 
 
8713
        res = PQexec(g_conn, query->data);
 
8714
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
8715
 
 
8716
        /* Expecting a single result only */
 
8717
        ntups = PQntuples(res);
 
8718
        if (ntups != 1)
 
8719
        {
 
8720
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
8721
                                                           "query returned %d rows instead of one: %s\n",
 
8722
                                                                 ntups),
 
8723
                                  ntups, query->data);
 
8724
                exit_nicely();
 
8725
        }
 
8726
 
 
8727
        proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
 
8728
        prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
 
8729
        probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
 
8730
        if (g_fout->remoteVersion >= 80400)
 
8731
        {
 
8732
                funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
 
8733
                funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
 
8734
                funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
 
8735
                proallargtypes = proargmodes = proargnames = NULL;
 
8736
        }
 
8737
        else
 
8738
        {
 
8739
                proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
 
8740
                proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
 
8741
                proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
 
8742
                funcargs = funciargs = funcresult = NULL;
 
8743
        }
 
8744
        proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
 
8745
        provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
 
8746
        proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
 
8747
        prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
 
8748
        proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
 
8749
        procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
 
8750
        prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
 
8751
        lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
 
8752
 
 
8753
        /*
 
8754
         * See backend/commands/functioncmds.c for details of how the 'AS' clause
 
8755
         * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
 
8756
         * versions would set it to "-".  There are no known cases in which prosrc
 
8757
         * is unused, so the tests below for "-" are probably useless.
 
8758
         */
 
8759
        if (probin[0] != '\0' && strcmp(probin, "-") != 0)
 
8760
        {
 
8761
                appendPQExpBuffer(asPart, "AS ");
 
8762
                appendStringLiteralAH(asPart, probin, fout);
 
8763
                if (strcmp(prosrc, "-") != 0)
 
8764
                {
 
8765
                        appendPQExpBuffer(asPart, ", ");
 
8766
 
 
8767
                        /*
 
8768
                         * where we have bin, use dollar quoting if allowed and src
 
8769
                         * contains quote or backslash; else use regular quoting.
 
8770
                         */
 
8771
                        if (disable_dollar_quoting ||
 
8772
                          (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
 
8773
                                appendStringLiteralAH(asPart, prosrc, fout);
 
8774
                        else
 
8775
                                appendStringLiteralDQ(asPart, prosrc, NULL);
 
8776
                }
 
8777
        }
 
8778
        else
 
8779
        {
 
8780
                if (strcmp(prosrc, "-") != 0)
 
8781
                {
 
8782
                        appendPQExpBuffer(asPart, "AS ");
 
8783
                        /* with no bin, dollar quote src unconditionally if allowed */
 
8784
                        if (disable_dollar_quoting)
 
8785
                                appendStringLiteralAH(asPart, prosrc, fout);
 
8786
                        else
 
8787
                                appendStringLiteralDQ(asPart, prosrc, NULL);
 
8788
                }
 
8789
        }
 
8790
 
 
8791
        nallargs = finfo->nargs;        /* unless we learn different from allargs */
 
8792
 
 
8793
        if (proallargtypes && *proallargtypes)
 
8794
        {
 
8795
                int                     nitems = 0;
 
8796
 
 
8797
                if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
 
8798
                        nitems < finfo->nargs)
 
8799
                {
 
8800
                        write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
 
8801
                        if (allargtypes)
 
8802
                                free(allargtypes);
 
8803
                        allargtypes = NULL;
 
8804
                }
 
8805
                else
 
8806
                        nallargs = nitems;
 
8807
        }
 
8808
 
 
8809
        if (proargmodes && *proargmodes)
 
8810
        {
 
8811
                int                     nitems = 0;
 
8812
 
 
8813
                if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
 
8814
                        nitems != nallargs)
 
8815
                {
 
8816
                        write_msg(NULL, "WARNING: could not parse proargmodes array\n");
 
8817
                        if (argmodes)
 
8818
                                free(argmodes);
 
8819
                        argmodes = NULL;
 
8820
                }
 
8821
        }
 
8822
 
 
8823
        if (proargnames && *proargnames)
 
8824
        {
 
8825
                int                     nitems = 0;
 
8826
 
 
8827
                if (!parsePGArray(proargnames, &argnames, &nitems) ||
 
8828
                        nitems != nallargs)
 
8829
                {
 
8830
                        write_msg(NULL, "WARNING: could not parse proargnames array\n");
 
8831
                        if (argnames)
 
8832
                                free(argnames);
 
8833
                        argnames = NULL;
 
8834
                }
 
8835
        }
 
8836
 
 
8837
        if (proconfig && *proconfig)
 
8838
        {
 
8839
                if (!parsePGArray(proconfig, &configitems, &nconfigitems))
 
8840
                {
 
8841
                        write_msg(NULL, "WARNING: could not parse proconfig array\n");
 
8842
                        if (configitems)
 
8843
                                free(configitems);
 
8844
                        configitems = NULL;
 
8845
                        nconfigitems = 0;
 
8846
                }
 
8847
        }
 
8848
 
 
8849
        if (funcargs)
 
8850
        {
 
8851
                /* 8.4 or later; we rely on server-side code for most of the work */
 
8852
                funcfullsig = format_function_arguments(finfo, funcargs);
 
8853
                funcsig = format_function_arguments(finfo, funciargs);
 
8854
        }
 
8855
        else
 
8856
        {
 
8857
                /* pre-8.4, do it ourselves */
 
8858
                funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
 
8859
                                                                                                argmodes, argnames);
 
8860
                funcfullsig = funcsig;
 
8861
        }
 
8862
 
 
8863
        funcsig_tag = format_function_signature(finfo, false);
 
8864
 
 
8865
        /*
 
8866
         * DROP must be fully qualified in case same name appears in pg_catalog
 
8867
         */
 
8868
        appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
 
8869
                                          fmtId(finfo->dobj.namespace->dobj.name),
 
8870
                                          funcsig);
 
8871
 
 
8872
        appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
 
8873
        if (funcresult)
 
8874
                appendPQExpBuffer(q, "RETURNS %s", funcresult);
 
8875
        else
 
8876
        {
 
8877
                rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
 
8878
                appendPQExpBuffer(q, "RETURNS %s%s",
 
8879
                                                  (proretset[0] == 't') ? "SETOF " : "",
 
8880
                                                  rettypename);
 
8881
                free(rettypename);
 
8882
        }
 
8883
 
 
8884
        appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
 
8885
 
 
8886
        if (proiswindow[0] == 't')
 
8887
                appendPQExpBuffer(q, " WINDOW");
 
8888
 
 
8889
        if (provolatile[0] != PROVOLATILE_VOLATILE)
 
8890
        {
 
8891
                if (provolatile[0] == PROVOLATILE_IMMUTABLE)
 
8892
                        appendPQExpBuffer(q, " IMMUTABLE");
 
8893
                else if (provolatile[0] == PROVOLATILE_STABLE)
 
8894
                        appendPQExpBuffer(q, " STABLE");
 
8895
                else if (provolatile[0] != PROVOLATILE_VOLATILE)
 
8896
                {
 
8897
                        write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
 
8898
                                          finfo->dobj.name);
 
8899
                        exit_nicely();
 
8900
                }
 
8901
        }
 
8902
 
 
8903
        if (proisstrict[0] == 't')
 
8904
                appendPQExpBuffer(q, " STRICT");
 
8905
 
 
8906
        if (prosecdef[0] == 't')
 
8907
                appendPQExpBuffer(q, " SECURITY DEFINER");
 
8908
 
 
8909
        /*
 
8910
         * COST and ROWS are emitted only if present and not default, so as not to
 
8911
         * break backwards-compatibility of the dump without need.      Keep this code
 
8912
         * in sync with the defaults in functioncmds.c.
 
8913
         */
 
8914
        if (strcmp(procost, "0") != 0)
 
8915
        {
 
8916
                if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
 
8917
                {
 
8918
                        /* default cost is 1 */
 
8919
                        if (strcmp(procost, "1") != 0)
 
8920
                                appendPQExpBuffer(q, " COST %s", procost);
 
8921
                }
 
8922
                else
 
8923
                {
 
8924
                        /* default cost is 100 */
 
8925
                        if (strcmp(procost, "100") != 0)
 
8926
                                appendPQExpBuffer(q, " COST %s", procost);
 
8927
                }
 
8928
        }
 
8929
        if (proretset[0] == 't' &&
 
8930
                strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
 
8931
                appendPQExpBuffer(q, " ROWS %s", prorows);
 
8932
 
 
8933
        for (i = 0; i < nconfigitems; i++)
 
8934
        {
 
8935
                /* we feel free to scribble on configitems[] here */
 
8936
                char       *configitem = configitems[i];
 
8937
                char       *pos;
 
8938
 
 
8939
                pos = strchr(configitem, '=');
 
8940
                if (pos == NULL)
 
8941
                        continue;
 
8942
                *pos++ = '\0';
 
8943
                appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
 
8944
 
 
8945
                /*
 
8946
                 * Some GUC variable names are 'LIST' type and hence must not be
 
8947
                 * quoted.
 
8948
                 */
 
8949
                if (pg_strcasecmp(configitem, "DateStyle") == 0
 
8950
                        || pg_strcasecmp(configitem, "search_path") == 0)
 
8951
                        appendPQExpBuffer(q, "%s", pos);
 
8952
                else
 
8953
                        appendStringLiteralAH(q, pos, fout);
 
8954
        }
 
8955
 
 
8956
        appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
 
8957
 
 
8958
        appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
 
8959
 
 
8960
        if (binary_upgrade)
 
8961
                binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
 
8962
 
 
8963
        ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
 
8964
                                 funcsig_tag,
 
8965
                                 finfo->dobj.namespace->dobj.name,
 
8966
                                 NULL,
 
8967
                                 finfo->rolname, false,
 
8968
                                 "FUNCTION", SECTION_PRE_DATA,
 
8969
                                 q->data, delqry->data, NULL,
 
8970
                                 finfo->dobj.dependencies, finfo->dobj.nDeps,
 
8971
                                 NULL, NULL);
 
8972
 
 
8973
        /* Dump Function Comments and Security Labels */
 
8974
        dumpComment(fout, labelq->data,
 
8975
                                finfo->dobj.namespace->dobj.name, finfo->rolname,
 
8976
                                finfo->dobj.catId, 0, finfo->dobj.dumpId);
 
8977
        dumpSecLabel(fout, labelq->data,
 
8978
                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
 
8979
                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
 
8980
 
 
8981
        dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
 
8982
                        funcsig, NULL, funcsig_tag,
 
8983
                        finfo->dobj.namespace->dobj.name,
 
8984
                        finfo->rolname, finfo->proacl);
 
8985
 
 
8986
        PQclear(res);
 
8987
 
 
8988
        destroyPQExpBuffer(query);
 
8989
        destroyPQExpBuffer(q);
 
8990
        destroyPQExpBuffer(delqry);
 
8991
        destroyPQExpBuffer(labelq);
 
8992
        destroyPQExpBuffer(asPart);
 
8993
        free(funcsig);
 
8994
        free(funcsig_tag);
 
8995
        if (allargtypes)
 
8996
                free(allargtypes);
 
8997
        if (argmodes)
 
8998
                free(argmodes);
 
8999
        if (argnames)
 
9000
                free(argnames);
 
9001
        if (configitems)
 
9002
                free(configitems);
 
9003
}
 
9004
 
 
9005
 
 
9006
/*
 
9007
 * Dump a user-defined cast
 
9008
 */
 
9009
static void
 
9010
dumpCast(Archive *fout, CastInfo *cast)
 
9011
{
 
9012
        PQExpBuffer defqry;
 
9013
        PQExpBuffer delqry;
 
9014
        PQExpBuffer labelq;
 
9015
        FuncInfo   *funcInfo = NULL;
 
9016
        TypeInfo   *sourceInfo;
 
9017
        TypeInfo   *targetInfo;
 
9018
 
 
9019
        /* Skip if not to be dumped */
 
9020
        if (!cast->dobj.dump || dataOnly)
 
9021
                return;
 
9022
 
 
9023
        if (OidIsValid(cast->castfunc))
 
9024
        {
 
9025
                funcInfo = findFuncByOid(cast->castfunc);
 
9026
                if (funcInfo == NULL)
 
9027
                        return;
 
9028
        }
 
9029
 
 
9030
        /*
 
9031
         * As per discussion we dump casts if one or more of the underlying
 
9032
         * objects (the conversion function and the two data types) are not
 
9033
         * builtin AND if all of the non-builtin objects are included in the dump.
 
9034
         * Builtin meaning, the namespace name does not start with "pg_".
 
9035
         */
 
9036
        sourceInfo = findTypeByOid(cast->castsource);
 
9037
        targetInfo = findTypeByOid(cast->casttarget);
 
9038
 
 
9039
        if (sourceInfo == NULL || targetInfo == NULL)
 
9040
                return;
 
9041
 
 
9042
        /*
 
9043
         * Skip this cast if all objects are from pg_
 
9044
         */
 
9045
        if ((funcInfo == NULL ||
 
9046
                 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
 
9047
                strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
 
9048
                strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
 
9049
                return;
 
9050
 
 
9051
        /*
 
9052
         * Skip cast if function isn't from pg_ and is not to be dumped.
 
9053
         */
 
9054
        if (funcInfo &&
 
9055
                strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
 
9056
                !funcInfo->dobj.dump)
 
9057
                return;
 
9058
 
 
9059
        /*
 
9060
         * Same for the source type
 
9061
         */
 
9062
        if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
 
9063
                !sourceInfo->dobj.dump)
 
9064
                return;
 
9065
 
 
9066
        /*
 
9067
         * and the target type.
 
9068
         */
 
9069
        if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
 
9070
                !targetInfo->dobj.dump)
 
9071
                return;
 
9072
 
 
9073
        /* Make sure we are in proper schema (needed for getFormattedTypeName) */
 
9074
        selectSourceSchema("pg_catalog");
 
9075
 
 
9076
        defqry = createPQExpBuffer();
 
9077
        delqry = createPQExpBuffer();
 
9078
        labelq = createPQExpBuffer();
 
9079
 
 
9080
        appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
 
9081
                                          getFormattedTypeName(cast->castsource, zeroAsNone),
 
9082
                                          getFormattedTypeName(cast->casttarget, zeroAsNone));
 
9083
 
 
9084
        appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
 
9085
                                          getFormattedTypeName(cast->castsource, zeroAsNone),
 
9086
                                          getFormattedTypeName(cast->casttarget, zeroAsNone));
 
9087
 
 
9088
        switch (cast->castmethod)
 
9089
        {
 
9090
                case COERCION_METHOD_BINARY:
 
9091
                        appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
 
9092
                        break;
 
9093
                case COERCION_METHOD_INOUT:
 
9094
                        appendPQExpBuffer(defqry, "WITH INOUT");
 
9095
                        break;
 
9096
                case COERCION_METHOD_FUNCTION:
 
9097
 
 
9098
                        /*
 
9099
                         * Always qualify the function name, in case it is not in
 
9100
                         * pg_catalog schema (format_function_signature won't qualify it).
 
9101
                         */
 
9102
                        appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
 
9103
                                                          fmtId(funcInfo->dobj.namespace->dobj.name));
 
9104
                        appendPQExpBuffer(defqry, "%s",
 
9105
                                                          format_function_signature(funcInfo, true));
 
9106
                        break;
 
9107
                default:
 
9108
                        write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
 
9109
        }
 
9110
 
 
9111
        if (cast->castcontext == 'a')
 
9112
                appendPQExpBuffer(defqry, " AS ASSIGNMENT");
 
9113
        else if (cast->castcontext == 'i')
 
9114
                appendPQExpBuffer(defqry, " AS IMPLICIT");
 
9115
        appendPQExpBuffer(defqry, ";\n");
 
9116
 
 
9117
        appendPQExpBuffer(labelq, "CAST (%s AS %s)",
 
9118
                                          getFormattedTypeName(cast->castsource, zeroAsNone),
 
9119
                                          getFormattedTypeName(cast->casttarget, zeroAsNone));
 
9120
 
 
9121
        if (binary_upgrade)
 
9122
                binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
 
9123
 
 
9124
        ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
 
9125
                                 labelq->data,
 
9126
                                 "pg_catalog", NULL, "",
 
9127
                                 false, "CAST", SECTION_PRE_DATA,
 
9128
                                 defqry->data, delqry->data, NULL,
 
9129
                                 cast->dobj.dependencies, cast->dobj.nDeps,
 
9130
                                 NULL, NULL);
 
9131
 
 
9132
        /* Dump Cast Comments */
 
9133
        dumpComment(fout, labelq->data,
 
9134
                                NULL, "",
 
9135
                                cast->dobj.catId, 0, cast->dobj.dumpId);
 
9136
 
 
9137
        destroyPQExpBuffer(defqry);
 
9138
        destroyPQExpBuffer(delqry);
 
9139
        destroyPQExpBuffer(labelq);
 
9140
}
 
9141
 
 
9142
/*
 
9143
 * dumpOpr
 
9144
 *        write out a single operator definition
 
9145
 */
 
9146
static void
 
9147
dumpOpr(Archive *fout, OprInfo *oprinfo)
 
9148
{
 
9149
        PQExpBuffer query;
 
9150
        PQExpBuffer q;
 
9151
        PQExpBuffer delq;
 
9152
        PQExpBuffer labelq;
 
9153
        PQExpBuffer oprid;
 
9154
        PQExpBuffer details;
 
9155
        const char *name;
 
9156
        PGresult   *res;
 
9157
        int                     ntups;
 
9158
        int                     i_oprkind;
 
9159
        int                     i_oprcode;
 
9160
        int                     i_oprleft;
 
9161
        int                     i_oprright;
 
9162
        int                     i_oprcom;
 
9163
        int                     i_oprnegate;
 
9164
        int                     i_oprrest;
 
9165
        int                     i_oprjoin;
 
9166
        int                     i_oprcanmerge;
 
9167
        int                     i_oprcanhash;
 
9168
        char       *oprkind;
 
9169
        char       *oprcode;
 
9170
        char       *oprleft;
 
9171
        char       *oprright;
 
9172
        char       *oprcom;
 
9173
        char       *oprnegate;
 
9174
        char       *oprrest;
 
9175
        char       *oprjoin;
 
9176
        char       *oprcanmerge;
 
9177
        char       *oprcanhash;
 
9178
 
 
9179
        /* Skip if not to be dumped */
 
9180
        if (!oprinfo->dobj.dump || dataOnly)
 
9181
                return;
 
9182
 
 
9183
        /*
 
9184
         * some operators are invalid because they were the result of user
 
9185
         * defining operators before commutators exist
 
9186
         */
 
9187
        if (!OidIsValid(oprinfo->oprcode))
 
9188
                return;
 
9189
 
 
9190
        query = createPQExpBuffer();
 
9191
        q = createPQExpBuffer();
 
9192
        delq = createPQExpBuffer();
 
9193
        labelq = createPQExpBuffer();
 
9194
        oprid = createPQExpBuffer();
 
9195
        details = createPQExpBuffer();
 
9196
 
 
9197
        /* Make sure we are in proper schema so regoperator works correctly */
 
9198
        selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
 
9199
 
 
9200
        if (g_fout->remoteVersion >= 80300)
 
9201
        {
 
9202
                appendPQExpBuffer(query, "SELECT oprkind, "
 
9203
                                                  "oprcode::pg_catalog.regprocedure, "
 
9204
                                                  "oprleft::pg_catalog.regtype, "
 
9205
                                                  "oprright::pg_catalog.regtype, "
 
9206
                                                  "oprcom::pg_catalog.regoperator, "
 
9207
                                                  "oprnegate::pg_catalog.regoperator, "
 
9208
                                                  "oprrest::pg_catalog.regprocedure, "
 
9209
                                                  "oprjoin::pg_catalog.regprocedure, "
 
9210
                                                  "oprcanmerge, oprcanhash "
 
9211
                                                  "FROM pg_catalog.pg_operator "
 
9212
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
9213
                                                  oprinfo->dobj.catId.oid);
 
9214
        }
 
9215
        else if (g_fout->remoteVersion >= 70300)
 
9216
        {
 
9217
                appendPQExpBuffer(query, "SELECT oprkind, "
 
9218
                                                  "oprcode::pg_catalog.regprocedure, "
 
9219
                                                  "oprleft::pg_catalog.regtype, "
 
9220
                                                  "oprright::pg_catalog.regtype, "
 
9221
                                                  "oprcom::pg_catalog.regoperator, "
 
9222
                                                  "oprnegate::pg_catalog.regoperator, "
 
9223
                                                  "oprrest::pg_catalog.regprocedure, "
 
9224
                                                  "oprjoin::pg_catalog.regprocedure, "
 
9225
                                                  "(oprlsortop != 0) AS oprcanmerge, "
 
9226
                                                  "oprcanhash "
 
9227
                                                  "FROM pg_catalog.pg_operator "
 
9228
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
9229
                                                  oprinfo->dobj.catId.oid);
 
9230
        }
 
9231
        else if (g_fout->remoteVersion >= 70100)
 
9232
        {
 
9233
                appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
 
9234
                                                  "CASE WHEN oprleft = 0 THEN '-' "
 
9235
                                                  "ELSE format_type(oprleft, NULL) END AS oprleft, "
 
9236
                                                  "CASE WHEN oprright = 0 THEN '-' "
 
9237
                                                  "ELSE format_type(oprright, NULL) END AS oprright, "
 
9238
                                                  "oprcom, oprnegate, oprrest, oprjoin, "
 
9239
                                                  "(oprlsortop != 0) AS oprcanmerge, "
 
9240
                                                  "oprcanhash "
 
9241
                                                  "FROM pg_operator "
 
9242
                                                  "WHERE oid = '%u'::oid",
 
9243
                                                  oprinfo->dobj.catId.oid);
 
9244
        }
 
9245
        else
 
9246
        {
 
9247
                appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
 
9248
                                                  "CASE WHEN oprleft = 0 THEN '-'::name "
 
9249
                                                  "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
 
9250
                                                  "CASE WHEN oprright = 0 THEN '-'::name "
 
9251
                                                  "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
 
9252
                                                  "oprcom, oprnegate, oprrest, oprjoin, "
 
9253
                                                  "(oprlsortop != 0) AS oprcanmerge, "
 
9254
                                                  "oprcanhash "
 
9255
                                                  "FROM pg_operator "
 
9256
                                                  "WHERE oid = '%u'::oid",
 
9257
                                                  oprinfo->dobj.catId.oid);
 
9258
        }
 
9259
 
 
9260
        res = PQexec(g_conn, query->data);
 
9261
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
9262
 
 
9263
        /* Expecting a single result only */
 
9264
        ntups = PQntuples(res);
 
9265
        if (ntups != 1)
 
9266
        {
 
9267
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
9268
                                                           "query returned %d rows instead of one: %s\n",
 
9269
                                                                 ntups),
 
9270
                                  ntups, query->data);
 
9271
                exit_nicely();
 
9272
        }
 
9273
 
 
9274
        i_oprkind = PQfnumber(res, "oprkind");
 
9275
        i_oprcode = PQfnumber(res, "oprcode");
 
9276
        i_oprleft = PQfnumber(res, "oprleft");
 
9277
        i_oprright = PQfnumber(res, "oprright");
 
9278
        i_oprcom = PQfnumber(res, "oprcom");
 
9279
        i_oprnegate = PQfnumber(res, "oprnegate");
 
9280
        i_oprrest = PQfnumber(res, "oprrest");
 
9281
        i_oprjoin = PQfnumber(res, "oprjoin");
 
9282
        i_oprcanmerge = PQfnumber(res, "oprcanmerge");
 
9283
        i_oprcanhash = PQfnumber(res, "oprcanhash");
 
9284
 
 
9285
        oprkind = PQgetvalue(res, 0, i_oprkind);
 
9286
        oprcode = PQgetvalue(res, 0, i_oprcode);
 
9287
        oprleft = PQgetvalue(res, 0, i_oprleft);
 
9288
        oprright = PQgetvalue(res, 0, i_oprright);
 
9289
        oprcom = PQgetvalue(res, 0, i_oprcom);
 
9290
        oprnegate = PQgetvalue(res, 0, i_oprnegate);
 
9291
        oprrest = PQgetvalue(res, 0, i_oprrest);
 
9292
        oprjoin = PQgetvalue(res, 0, i_oprjoin);
 
9293
        oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
 
9294
        oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
 
9295
 
 
9296
        appendPQExpBuffer(details, "    PROCEDURE = %s",
 
9297
                                          convertRegProcReference(oprcode));
 
9298
 
 
9299
        appendPQExpBuffer(oprid, "%s (",
 
9300
                                          oprinfo->dobj.name);
 
9301
 
 
9302
        /*
 
9303
         * right unary means there's a left arg and left unary means there's a
 
9304
         * right arg
 
9305
         */
 
9306
        if (strcmp(oprkind, "r") == 0 ||
 
9307
                strcmp(oprkind, "b") == 0)
 
9308
        {
 
9309
                if (g_fout->remoteVersion >= 70100)
 
9310
                        name = oprleft;
 
9311
                else
 
9312
                        name = fmtId(oprleft);
 
9313
                appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
 
9314
                appendPQExpBuffer(oprid, "%s", name);
 
9315
        }
 
9316
        else
 
9317
                appendPQExpBuffer(oprid, "NONE");
 
9318
 
 
9319
        if (strcmp(oprkind, "l") == 0 ||
 
9320
                strcmp(oprkind, "b") == 0)
 
9321
        {
 
9322
                if (g_fout->remoteVersion >= 70100)
 
9323
                        name = oprright;
 
9324
                else
 
9325
                        name = fmtId(oprright);
 
9326
                appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
 
9327
                appendPQExpBuffer(oprid, ", %s)", name);
 
9328
        }
 
9329
        else
 
9330
                appendPQExpBuffer(oprid, ", NONE)");
 
9331
 
 
9332
        name = convertOperatorReference(oprcom);
 
9333
        if (name)
 
9334
                appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
 
9335
 
 
9336
        name = convertOperatorReference(oprnegate);
 
9337
        if (name)
 
9338
                appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
 
9339
 
 
9340
        if (strcmp(oprcanmerge, "t") == 0)
 
9341
                appendPQExpBuffer(details, ",\n    MERGES");
 
9342
 
 
9343
        if (strcmp(oprcanhash, "t") == 0)
 
9344
                appendPQExpBuffer(details, ",\n    HASHES");
 
9345
 
 
9346
        name = convertRegProcReference(oprrest);
 
9347
        if (name)
 
9348
                appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
 
9349
 
 
9350
        name = convertRegProcReference(oprjoin);
 
9351
        if (name)
 
9352
                appendPQExpBuffer(details, ",\n    JOIN = %s", name);
 
9353
 
 
9354
        /*
 
9355
         * DROP must be fully qualified in case same name appears in pg_catalog
 
9356
         */
 
9357
        appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
 
9358
                                          fmtId(oprinfo->dobj.namespace->dobj.name),
 
9359
                                          oprid->data);
 
9360
 
 
9361
        appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
 
9362
                                          oprinfo->dobj.name, details->data);
 
9363
 
 
9364
        appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
 
9365
 
 
9366
        if (binary_upgrade)
 
9367
                binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
 
9368
 
 
9369
        ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
 
9370
                                 oprinfo->dobj.name,
 
9371
                                 oprinfo->dobj.namespace->dobj.name,
 
9372
                                 NULL,
 
9373
                                 oprinfo->rolname,
 
9374
                                 false, "OPERATOR", SECTION_PRE_DATA,
 
9375
                                 q->data, delq->data, NULL,
 
9376
                                 oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
 
9377
                                 NULL, NULL);
 
9378
 
 
9379
        /* Dump Operator Comments */
 
9380
        dumpComment(fout, labelq->data,
 
9381
                                oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
 
9382
                                oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
 
9383
 
 
9384
        PQclear(res);
 
9385
 
 
9386
        destroyPQExpBuffer(query);
 
9387
        destroyPQExpBuffer(q);
 
9388
        destroyPQExpBuffer(delq);
 
9389
        destroyPQExpBuffer(labelq);
 
9390
        destroyPQExpBuffer(oprid);
 
9391
        destroyPQExpBuffer(details);
 
9392
}
 
9393
 
 
9394
/*
 
9395
 * Convert a function reference obtained from pg_operator
 
9396
 *
 
9397
 * Returns what to print, or NULL if function references is InvalidOid
 
9398
 *
 
9399
 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
 
9400
 * argument-types part.  In prior versions, the input is a REGPROC display.
 
9401
 */
 
9402
static const char *
 
9403
convertRegProcReference(const char *proc)
 
9404
{
 
9405
        /* In all cases "-" means a null reference */
 
9406
        if (strcmp(proc, "-") == 0)
 
9407
                return NULL;
 
9408
 
 
9409
        if (g_fout->remoteVersion >= 70300)
 
9410
        {
 
9411
                char       *name;
 
9412
                char       *paren;
 
9413
                bool            inquote;
 
9414
 
 
9415
                name = strdup(proc);
 
9416
                /* find non-double-quoted left paren */
 
9417
                inquote = false;
 
9418
                for (paren = name; *paren; paren++)
 
9419
                {
 
9420
                        if (*paren == '(' && !inquote)
 
9421
                        {
 
9422
                                *paren = '\0';
 
9423
                                break;
 
9424
                        }
 
9425
                        if (*paren == '"')
 
9426
                                inquote = !inquote;
 
9427
                }
 
9428
                return name;
 
9429
        }
 
9430
 
 
9431
        /* REGPROC before 7.3 does not quote its result */
 
9432
        return fmtId(proc);
 
9433
}
 
9434
 
 
9435
/*
 
9436
 * Convert an operator cross-reference obtained from pg_operator
 
9437
 *
 
9438
 * Returns what to print, or NULL to print nothing
 
9439
 *
 
9440
 * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
 
9441
 * argument-types part, and add OPERATOR() decoration if the name is
 
9442
 * schema-qualified.  In older versions, the input is just a numeric OID,
 
9443
 * which we search our operator list for.
 
9444
 */
 
9445
static const char *
 
9446
convertOperatorReference(const char *opr)
 
9447
{
 
9448
        OprInfo    *oprInfo;
 
9449
 
 
9450
        /* In all cases "0" means a null reference */
 
9451
        if (strcmp(opr, "0") == 0)
 
9452
                return NULL;
 
9453
 
 
9454
        if (g_fout->remoteVersion >= 70300)
 
9455
        {
 
9456
                char       *name;
 
9457
                char       *oname;
 
9458
                char       *ptr;
 
9459
                bool            inquote;
 
9460
                bool            sawdot;
 
9461
 
 
9462
                name = strdup(opr);
 
9463
                /* find non-double-quoted left paren, and check for non-quoted dot */
 
9464
                inquote = false;
 
9465
                sawdot = false;
 
9466
                for (ptr = name; *ptr; ptr++)
 
9467
                {
 
9468
                        if (*ptr == '"')
 
9469
                                inquote = !inquote;
 
9470
                        else if (*ptr == '.' && !inquote)
 
9471
                                sawdot = true;
 
9472
                        else if (*ptr == '(' && !inquote)
 
9473
                        {
 
9474
                                *ptr = '\0';
 
9475
                                break;
 
9476
                        }
 
9477
                }
 
9478
                /* If not schema-qualified, don't need to add OPERATOR() */
 
9479
                if (!sawdot)
 
9480
                        return name;
 
9481
                oname = malloc(strlen(name) + 11);
 
9482
                sprintf(oname, "OPERATOR(%s)", name);
 
9483
                free(name);
 
9484
                return oname;
 
9485
        }
 
9486
 
 
9487
        oprInfo = findOprByOid(atooid(opr));
 
9488
        if (oprInfo == NULL)
 
9489
        {
 
9490
                write_msg(NULL, "WARNING: could not find operator with OID %s\n",
 
9491
                                  opr);
 
9492
                return NULL;
 
9493
        }
 
9494
        return oprInfo->dobj.name;
 
9495
}
 
9496
 
 
9497
/*
 
9498
 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
 
9499
 *
 
9500
 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
 
9501
 * argument lists of these functions are predetermined.  Note that the
 
9502
 * caller should ensure we are in the proper schema, because the results
 
9503
 * are search path dependent!
 
9504
 */
 
9505
static const char *
 
9506
convertTSFunction(Oid funcOid)
 
9507
{
 
9508
        char       *result;
 
9509
        char            query[128];
 
9510
        PGresult   *res;
 
9511
        int                     ntups;
 
9512
 
 
9513
        snprintf(query, sizeof(query),
 
9514
                         "SELECT '%u'::pg_catalog.regproc", funcOid);
 
9515
        res = PQexec(g_conn, query);
 
9516
        check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
 
9517
 
 
9518
        ntups = PQntuples(res);
 
9519
        if (ntups != 1)
 
9520
        {
 
9521
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
9522
                                                           "query returned %d rows instead of one: %s\n",
 
9523
                                                                 ntups),
 
9524
                                  ntups, query);
 
9525
                exit_nicely();
 
9526
        }
 
9527
 
 
9528
        result = strdup(PQgetvalue(res, 0, 0));
 
9529
 
 
9530
        PQclear(res);
 
9531
 
 
9532
        return result;
 
9533
}
 
9534
 
 
9535
 
 
9536
/*
 
9537
 * dumpOpclass
 
9538
 *        write out a single operator class definition
 
9539
 */
 
9540
static void
 
9541
dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
 
9542
{
 
9543
        PQExpBuffer query;
 
9544
        PQExpBuffer q;
 
9545
        PQExpBuffer delq;
 
9546
        PQExpBuffer labelq;
 
9547
        PGresult   *res;
 
9548
        int                     ntups;
 
9549
        int                     i_opcintype;
 
9550
        int                     i_opckeytype;
 
9551
        int                     i_opcdefault;
 
9552
        int                     i_opcfamily;
 
9553
        int                     i_opcfamilyname;
 
9554
        int                     i_opcfamilynsp;
 
9555
        int                     i_amname;
 
9556
        int                     i_amopstrategy;
 
9557
        int                     i_amopreqcheck;
 
9558
        int                     i_amopopr;
 
9559
        int                     i_sortfamily;
 
9560
        int                     i_sortfamilynsp;
 
9561
        int                     i_amprocnum;
 
9562
        int                     i_amproc;
 
9563
        char       *opcintype;
 
9564
        char       *opckeytype;
 
9565
        char       *opcdefault;
 
9566
        char       *opcfamily;
 
9567
        char       *opcfamilyname;
 
9568
        char       *opcfamilynsp;
 
9569
        char       *amname;
 
9570
        char       *amopstrategy;
 
9571
        char       *amopreqcheck;
 
9572
        char       *amopopr;
 
9573
        char       *sortfamily;
 
9574
        char       *sortfamilynsp;
 
9575
        char       *amprocnum;
 
9576
        char       *amproc;
 
9577
        bool            needComma;
 
9578
        int                     i;
 
9579
 
 
9580
        /* Skip if not to be dumped */
 
9581
        if (!opcinfo->dobj.dump || dataOnly)
 
9582
                return;
 
9583
 
 
9584
        /*
 
9585
         * XXX currently we do not implement dumping of operator classes from
 
9586
         * pre-7.3 databases.  This could be done but it seems not worth the
 
9587
         * trouble.
 
9588
         */
 
9589
        if (g_fout->remoteVersion < 70300)
 
9590
                return;
 
9591
 
 
9592
        query = createPQExpBuffer();
 
9593
        q = createPQExpBuffer();
 
9594
        delq = createPQExpBuffer();
 
9595
        labelq = createPQExpBuffer();
 
9596
 
 
9597
        /* Make sure we are in proper schema so regoperator works correctly */
 
9598
        selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
 
9599
 
 
9600
        /* Get additional fields from the pg_opclass row */
 
9601
        if (g_fout->remoteVersion >= 80300)
 
9602
        {
 
9603
                appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
 
9604
                                                  "opckeytype::pg_catalog.regtype, "
 
9605
                                                  "opcdefault, opcfamily, "
 
9606
                                                  "opfname AS opcfamilyname, "
 
9607
                                                  "nspname AS opcfamilynsp, "
 
9608
                                                  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
 
9609
                                                  "FROM pg_catalog.pg_opclass c "
 
9610
                                   "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
 
9611
                           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
 
9612
                                                  "WHERE c.oid = '%u'::pg_catalog.oid",
 
9613
                                                  opcinfo->dobj.catId.oid);
 
9614
        }
 
9615
        else
 
9616
        {
 
9617
                appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
 
9618
                                                  "opckeytype::pg_catalog.regtype, "
 
9619
                                                  "opcdefault, NULL AS opcfamily, "
 
9620
                                                  "NULL AS opcfamilyname, "
 
9621
                                                  "NULL AS opcfamilynsp, "
 
9622
                "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
 
9623
                                                  "FROM pg_catalog.pg_opclass "
 
9624
                                                  "WHERE oid = '%u'::pg_catalog.oid",
 
9625
                                                  opcinfo->dobj.catId.oid);
 
9626
        }
 
9627
 
 
9628
        res = PQexec(g_conn, query->data);
 
9629
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
9630
 
 
9631
        /* Expecting a single result only */
 
9632
        ntups = PQntuples(res);
 
9633
        if (ntups != 1)
 
9634
        {
 
9635
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
9636
                                                           "query returned %d rows instead of one: %s\n",
 
9637
                                                                 ntups),
 
9638
                                  ntups, query->data);
 
9639
                exit_nicely();
 
9640
        }
 
9641
 
 
9642
        i_opcintype = PQfnumber(res, "opcintype");
 
9643
        i_opckeytype = PQfnumber(res, "opckeytype");
 
9644
        i_opcdefault = PQfnumber(res, "opcdefault");
 
9645
        i_opcfamily = PQfnumber(res, "opcfamily");
 
9646
        i_opcfamilyname = PQfnumber(res, "opcfamilyname");
 
9647
        i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
 
9648
        i_amname = PQfnumber(res, "amname");
 
9649
 
 
9650
        opcintype = PQgetvalue(res, 0, i_opcintype);
 
9651
        opckeytype = PQgetvalue(res, 0, i_opckeytype);
 
9652
        opcdefault = PQgetvalue(res, 0, i_opcdefault);
 
9653
        /* opcfamily will still be needed after we PQclear res */
 
9654
        opcfamily = strdup(PQgetvalue(res, 0, i_opcfamily));
 
9655
        opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
 
9656
        opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
 
9657
        /* amname will still be needed after we PQclear res */
 
9658
        amname = strdup(PQgetvalue(res, 0, i_amname));
 
9659
 
 
9660
        /*
 
9661
         * DROP must be fully qualified in case same name appears in pg_catalog
 
9662
         */
 
9663
        appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
 
9664
                                          fmtId(opcinfo->dobj.namespace->dobj.name));
 
9665
        appendPQExpBuffer(delq, ".%s",
 
9666
                                          fmtId(opcinfo->dobj.name));
 
9667
        appendPQExpBuffer(delq, " USING %s;\n",
 
9668
                                          fmtId(amname));
 
9669
 
 
9670
        /* Build the fixed portion of the CREATE command */
 
9671
        appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
 
9672
                                          fmtId(opcinfo->dobj.name));
 
9673
        if (strcmp(opcdefault, "t") == 0)
 
9674
                appendPQExpBuffer(q, "DEFAULT ");
 
9675
        appendPQExpBuffer(q, "FOR TYPE %s USING %s",
 
9676
                                          opcintype,
 
9677
                                          fmtId(amname));
 
9678
        if (strlen(opcfamilyname) > 0 &&
 
9679
                (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
 
9680
                 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
 
9681
        {
 
9682
                appendPQExpBuffer(q, " FAMILY ");
 
9683
                if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
 
9684
                        appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
 
9685
                appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
 
9686
        }
 
9687
        appendPQExpBuffer(q, " AS\n    ");
 
9688
 
 
9689
        needComma = false;
 
9690
 
 
9691
        if (strcmp(opckeytype, "-") != 0)
 
9692
        {
 
9693
                appendPQExpBuffer(q, "STORAGE %s",
 
9694
                                                  opckeytype);
 
9695
                needComma = true;
 
9696
        }
 
9697
 
 
9698
        PQclear(res);
 
9699
 
 
9700
        /*
 
9701
         * Now fetch and print the OPERATOR entries (pg_amop rows).
 
9702
         *
 
9703
         * Print only those opfamily members that are tied to the opclass by
 
9704
         * pg_depend entries.
 
9705
         *
 
9706
         * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
 
9707
         * older server's opclass in which it is used.  This is to avoid
 
9708
         * hard-to-detect breakage if a newer pg_dump is used to dump from an
 
9709
         * older server and then reload into that old version.  This can go away
 
9710
         * once 8.3 is so old as to not be of interest to anyone.
 
9711
         */
 
9712
        resetPQExpBuffer(query);
 
9713
 
 
9714
        if (g_fout->remoteVersion >= 90100)
 
9715
        {
 
9716
                appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
 
9717
                                                  "amopopr::pg_catalog.regoperator, "
 
9718
                                                  "opfname AS sortfamily, "
 
9719
                                                  "nspname AS sortfamilynsp "
 
9720
                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
 
9721
                                                  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
 
9722
                          "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
 
9723
                           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
 
9724
                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
 
9725
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
9726
                                                  "AND amopfamily = '%s'::pg_catalog.oid "
 
9727
                                                  "ORDER BY amopstrategy",
 
9728
                                                  opcinfo->dobj.catId.oid,
 
9729
                                                  opcfamily);
 
9730
        }
 
9731
        else if (g_fout->remoteVersion >= 80400)
 
9732
        {
 
9733
                appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
 
9734
                                                  "amopopr::pg_catalog.regoperator, "
 
9735
                                                  "NULL AS sortfamily, "
 
9736
                                                  "NULL AS sortfamilynsp "
 
9737
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
 
9738
                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
 
9739
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
9740
                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
 
9741
                                                  "AND objid = ao.oid "
 
9742
                                                  "ORDER BY amopstrategy",
 
9743
                                                  opcinfo->dobj.catId.oid);
 
9744
        }
 
9745
        else if (g_fout->remoteVersion >= 80300)
 
9746
        {
 
9747
                appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
 
9748
                                                  "amopopr::pg_catalog.regoperator, "
 
9749
                                                  "NULL AS sortfamily, "
 
9750
                                                  "NULL AS sortfamilynsp "
 
9751
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
 
9752
                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
 
9753
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
9754
                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
 
9755
                                                  "AND objid = ao.oid "
 
9756
                                                  "ORDER BY amopstrategy",
 
9757
                                                  opcinfo->dobj.catId.oid);
 
9758
        }
 
9759
        else
 
9760
        {
 
9761
                /*
 
9762
                 * Here, we print all entries since there are no opfamilies and hence
 
9763
                 * no loose operators to worry about.
 
9764
                 */
 
9765
                appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
 
9766
                                                  "amopopr::pg_catalog.regoperator, "
 
9767
                                                  "NULL AS sortfamily, "
 
9768
                                                  "NULL AS sortfamilynsp "
 
9769
                                                  "FROM pg_catalog.pg_amop "
 
9770
                                                  "WHERE amopclaid = '%u'::pg_catalog.oid "
 
9771
                                                  "ORDER BY amopstrategy",
 
9772
                                                  opcinfo->dobj.catId.oid);
 
9773
        }
 
9774
 
 
9775
        res = PQexec(g_conn, query->data);
 
9776
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
9777
 
 
9778
        ntups = PQntuples(res);
 
9779
 
 
9780
        i_amopstrategy = PQfnumber(res, "amopstrategy");
 
9781
        i_amopreqcheck = PQfnumber(res, "amopreqcheck");
 
9782
        i_amopopr = PQfnumber(res, "amopopr");
 
9783
        i_sortfamily = PQfnumber(res, "sortfamily");
 
9784
        i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
 
9785
 
 
9786
        for (i = 0; i < ntups; i++)
 
9787
        {
 
9788
                amopstrategy = PQgetvalue(res, i, i_amopstrategy);
 
9789
                amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
 
9790
                amopopr = PQgetvalue(res, i, i_amopopr);
 
9791
                sortfamily = PQgetvalue(res, i, i_sortfamily);
 
9792
                sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
 
9793
 
 
9794
                if (needComma)
 
9795
                        appendPQExpBuffer(q, " ,\n    ");
 
9796
 
 
9797
                appendPQExpBuffer(q, "OPERATOR %s %s",
 
9798
                                                  amopstrategy, amopopr);
 
9799
 
 
9800
                if (strlen(sortfamily) > 0)
 
9801
                {
 
9802
                        appendPQExpBuffer(q, " FOR ORDER BY ");
 
9803
                        if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
 
9804
                                appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
 
9805
                        appendPQExpBuffer(q, "%s", fmtId(sortfamily));
 
9806
                }
 
9807
 
 
9808
                if (strcmp(amopreqcheck, "t") == 0)
 
9809
                        appendPQExpBuffer(q, " RECHECK");
 
9810
 
 
9811
                needComma = true;
 
9812
        }
 
9813
 
 
9814
        PQclear(res);
 
9815
 
 
9816
        /*
 
9817
         * Now fetch and print the FUNCTION entries (pg_amproc rows).
 
9818
         *
 
9819
         * Print only those opfamily members that are tied to the opclass by
 
9820
         * pg_depend entries.
 
9821
         */
 
9822
        resetPQExpBuffer(query);
 
9823
 
 
9824
        if (g_fout->remoteVersion >= 80300)
 
9825
        {
 
9826
                appendPQExpBuffer(query, "SELECT amprocnum, "
 
9827
                                                  "amproc::pg_catalog.regprocedure "
 
9828
                                                "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
 
9829
                   "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
 
9830
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
9831
                                 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
 
9832
                                                  "AND objid = ap.oid "
 
9833
                                                  "ORDER BY amprocnum",
 
9834
                                                  opcinfo->dobj.catId.oid);
 
9835
        }
 
9836
        else
 
9837
        {
 
9838
                appendPQExpBuffer(query, "SELECT amprocnum, "
 
9839
                                                  "amproc::pg_catalog.regprocedure "
 
9840
                                                  "FROM pg_catalog.pg_amproc "
 
9841
                                                  "WHERE amopclaid = '%u'::pg_catalog.oid "
 
9842
                                                  "ORDER BY amprocnum",
 
9843
                                                  opcinfo->dobj.catId.oid);
 
9844
        }
 
9845
 
 
9846
        res = PQexec(g_conn, query->data);
 
9847
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
9848
 
 
9849
        ntups = PQntuples(res);
 
9850
 
 
9851
        i_amprocnum = PQfnumber(res, "amprocnum");
 
9852
        i_amproc = PQfnumber(res, "amproc");
 
9853
 
 
9854
        for (i = 0; i < ntups; i++)
 
9855
        {
 
9856
                amprocnum = PQgetvalue(res, i, i_amprocnum);
 
9857
                amproc = PQgetvalue(res, i, i_amproc);
 
9858
 
 
9859
                if (needComma)
 
9860
                        appendPQExpBuffer(q, " ,\n    ");
 
9861
 
 
9862
                appendPQExpBuffer(q, "FUNCTION %s %s",
 
9863
                                                  amprocnum, amproc);
 
9864
 
 
9865
                needComma = true;
 
9866
        }
 
9867
 
 
9868
        PQclear(res);
 
9869
 
 
9870
        appendPQExpBuffer(q, ";\n");
 
9871
 
 
9872
        appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
 
9873
                                          fmtId(opcinfo->dobj.name));
 
9874
        appendPQExpBuffer(labelq, " USING %s",
 
9875
                                          fmtId(amname));
 
9876
 
 
9877
        if (binary_upgrade)
 
9878
                binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
 
9879
 
 
9880
        ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
 
9881
                                 opcinfo->dobj.name,
 
9882
                                 opcinfo->dobj.namespace->dobj.name,
 
9883
                                 NULL,
 
9884
                                 opcinfo->rolname,
 
9885
                                 false, "OPERATOR CLASS", SECTION_PRE_DATA,
 
9886
                                 q->data, delq->data, NULL,
 
9887
                                 opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
 
9888
                                 NULL, NULL);
 
9889
 
 
9890
        /* Dump Operator Class Comments */
 
9891
        dumpComment(fout, labelq->data,
 
9892
                                NULL, opcinfo->rolname,
 
9893
                                opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
 
9894
 
 
9895
        free(amname);
 
9896
        destroyPQExpBuffer(query);
 
9897
        destroyPQExpBuffer(q);
 
9898
        destroyPQExpBuffer(delq);
 
9899
        destroyPQExpBuffer(labelq);
 
9900
}
 
9901
 
 
9902
/*
 
9903
 * dumpOpfamily
 
9904
 *        write out a single operator family definition
 
9905
 *
 
9906
 * Note: this also dumps any "loose" operator members that aren't bound to a
 
9907
 * specific opclass within the opfamily.
 
9908
 */
 
9909
static void
 
9910
dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
 
9911
{
 
9912
        PQExpBuffer query;
 
9913
        PQExpBuffer q;
 
9914
        PQExpBuffer delq;
 
9915
        PQExpBuffer labelq;
 
9916
        PGresult   *res;
 
9917
        PGresult   *res_ops;
 
9918
        PGresult   *res_procs;
 
9919
        int                     ntups;
 
9920
        int                     i_amname;
 
9921
        int                     i_amopstrategy;
 
9922
        int                     i_amopreqcheck;
 
9923
        int                     i_amopopr;
 
9924
        int                     i_sortfamily;
 
9925
        int                     i_sortfamilynsp;
 
9926
        int                     i_amprocnum;
 
9927
        int                     i_amproc;
 
9928
        int                     i_amproclefttype;
 
9929
        int                     i_amprocrighttype;
 
9930
        char       *amname;
 
9931
        char       *amopstrategy;
 
9932
        char       *amopreqcheck;
 
9933
        char       *amopopr;
 
9934
        char       *sortfamily;
 
9935
        char       *sortfamilynsp;
 
9936
        char       *amprocnum;
 
9937
        char       *amproc;
 
9938
        char       *amproclefttype;
 
9939
        char       *amprocrighttype;
 
9940
        bool            needComma;
 
9941
        int                     i;
 
9942
 
 
9943
        /* Skip if not to be dumped */
 
9944
        if (!opfinfo->dobj.dump || dataOnly)
 
9945
                return;
 
9946
 
 
9947
        /*
 
9948
         * We want to dump the opfamily only if (1) it contains "loose" operators
 
9949
         * or functions, or (2) it contains an opclass with a different name or
 
9950
         * owner.  Otherwise it's sufficient to let it be created during creation
 
9951
         * of the contained opclass, and not dumping it improves portability of
 
9952
         * the dump.  Since we have to fetch the loose operators/funcs anyway, do
 
9953
         * that first.
 
9954
         */
 
9955
 
 
9956
        query = createPQExpBuffer();
 
9957
        q = createPQExpBuffer();
 
9958
        delq = createPQExpBuffer();
 
9959
        labelq = createPQExpBuffer();
 
9960
 
 
9961
        /* Make sure we are in proper schema so regoperator works correctly */
 
9962
        selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
 
9963
 
 
9964
        /*
 
9965
         * Fetch only those opfamily members that are tied directly to the
 
9966
         * opfamily by pg_depend entries.
 
9967
         *
 
9968
         * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
 
9969
         * older server's opclass in which it is used.  This is to avoid
 
9970
         * hard-to-detect breakage if a newer pg_dump is used to dump from an
 
9971
         * older server and then reload into that old version.  This can go away
 
9972
         * once 8.3 is so old as to not be of interest to anyone.
 
9973
         */
 
9974
        if (g_fout->remoteVersion >= 90100)
 
9975
        {
 
9976
                appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
 
9977
                                                  "amopopr::pg_catalog.regoperator, "
 
9978
                                                  "opfname AS sortfamily, "
 
9979
                                                  "nspname AS sortfamilynsp "
 
9980
                                   "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
 
9981
                                                  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
 
9982
                          "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
 
9983
                           "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
 
9984
                  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
 
9985
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
9986
                                                  "AND amopfamily = '%u'::pg_catalog.oid "
 
9987
                                                  "ORDER BY amopstrategy",
 
9988
                                                  opfinfo->dobj.catId.oid,
 
9989
                                                  opfinfo->dobj.catId.oid);
 
9990
        }
 
9991
        else if (g_fout->remoteVersion >= 80400)
 
9992
        {
 
9993
                appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
 
9994
                                                  "amopopr::pg_catalog.regoperator, "
 
9995
                                                  "NULL AS sortfamily, "
 
9996
                                                  "NULL AS sortfamilynsp "
 
9997
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
 
9998
                  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
 
9999
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
10000
                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
 
10001
                                                  "AND objid = ao.oid "
 
10002
                                                  "ORDER BY amopstrategy",
 
10003
                                                  opfinfo->dobj.catId.oid);
 
10004
        }
 
10005
        else
 
10006
        {
 
10007
                appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
 
10008
                                                  "amopopr::pg_catalog.regoperator, "
 
10009
                                                  "NULL AS sortfamily, "
 
10010
                                                  "NULL AS sortfamilynsp "
 
10011
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
 
10012
                  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
 
10013
                                                  "AND refobjid = '%u'::pg_catalog.oid "
 
10014
                                   "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
 
10015
                                                  "AND objid = ao.oid "
 
10016
                                                  "ORDER BY amopstrategy",
 
10017
                                                  opfinfo->dobj.catId.oid);
 
10018
        }
 
10019
 
 
10020
        res_ops = PQexec(g_conn, query->data);
 
10021
        check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
 
10022
 
 
10023
        resetPQExpBuffer(query);
 
10024
 
 
10025
        appendPQExpBuffer(query, "SELECT amprocnum, "
 
10026
                                          "amproc::pg_catalog.regprocedure, "
 
10027
                                          "amproclefttype::pg_catalog.regtype, "
 
10028
                                          "amprocrighttype::pg_catalog.regtype "
 
10029
                                          "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
 
10030
                  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
 
10031
                                          "AND refobjid = '%u'::pg_catalog.oid "
 
10032
                                 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
 
10033
                                          "AND objid = ap.oid "
 
10034
                                          "ORDER BY amprocnum",
 
10035
                                          opfinfo->dobj.catId.oid);
 
10036
 
 
10037
        res_procs = PQexec(g_conn, query->data);
 
10038
        check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
 
10039
 
 
10040
        if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
 
10041
        {
 
10042
                /* No loose members, so check contained opclasses */
 
10043
                resetPQExpBuffer(query);
 
10044
 
 
10045
                appendPQExpBuffer(query, "SELECT 1 "
 
10046
                                                  "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
 
10047
                                                  "WHERE f.oid = '%u'::pg_catalog.oid "
 
10048
                        "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
 
10049
                                                  "AND refobjid = f.oid "
 
10050
                                "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
 
10051
                                                  "AND objid = c.oid "
 
10052
                                                  "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
 
10053
                                                  "LIMIT 1",
 
10054
                                                  opfinfo->dobj.catId.oid);
 
10055
 
 
10056
                res = PQexec(g_conn, query->data);
 
10057
                check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10058
 
 
10059
                if (PQntuples(res) == 0)
 
10060
                {
 
10061
                        /* no need to dump it, so bail out */
 
10062
                        PQclear(res);
 
10063
                        PQclear(res_ops);
 
10064
                        PQclear(res_procs);
 
10065
                        destroyPQExpBuffer(query);
 
10066
                        destroyPQExpBuffer(q);
 
10067
                        destroyPQExpBuffer(delq);
 
10068
                        destroyPQExpBuffer(labelq);
 
10069
                        return;
 
10070
                }
 
10071
 
 
10072
                PQclear(res);
 
10073
        }
 
10074
 
 
10075
        /* Get additional fields from the pg_opfamily row */
 
10076
        resetPQExpBuffer(query);
 
10077
 
 
10078
        appendPQExpBuffer(query, "SELECT "
 
10079
         "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
 
10080
                                          "FROM pg_catalog.pg_opfamily "
 
10081
                                          "WHERE oid = '%u'::pg_catalog.oid",
 
10082
                                          opfinfo->dobj.catId.oid);
 
10083
 
 
10084
        res = PQexec(g_conn, query->data);
 
10085
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10086
 
 
10087
        /* Expecting a single result only */
 
10088
        ntups = PQntuples(res);
 
10089
        if (ntups != 1)
 
10090
        {
 
10091
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
10092
                                                           "query returned %d rows instead of one: %s\n",
 
10093
                                                                 ntups),
 
10094
                                  ntups, query->data);
 
10095
                exit_nicely();
 
10096
        }
 
10097
 
 
10098
        i_amname = PQfnumber(res, "amname");
 
10099
 
 
10100
        /* amname will still be needed after we PQclear res */
 
10101
        amname = strdup(PQgetvalue(res, 0, i_amname));
 
10102
 
 
10103
        /*
 
10104
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10105
         */
 
10106
        appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
 
10107
                                          fmtId(opfinfo->dobj.namespace->dobj.name));
 
10108
        appendPQExpBuffer(delq, ".%s",
 
10109
                                          fmtId(opfinfo->dobj.name));
 
10110
        appendPQExpBuffer(delq, " USING %s;\n",
 
10111
                                          fmtId(amname));
 
10112
 
 
10113
        /* Build the fixed portion of the CREATE command */
 
10114
        appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
 
10115
                                          fmtId(opfinfo->dobj.name));
 
10116
        appendPQExpBuffer(q, " USING %s;\n",
 
10117
                                          fmtId(amname));
 
10118
 
 
10119
        PQclear(res);
 
10120
 
 
10121
        /* Do we need an ALTER to add loose members? */
 
10122
        if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
 
10123
        {
 
10124
                appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
 
10125
                                                  fmtId(opfinfo->dobj.name));
 
10126
                appendPQExpBuffer(q, " USING %s ADD\n    ",
 
10127
                                                  fmtId(amname));
 
10128
 
 
10129
                needComma = false;
 
10130
 
 
10131
                /*
 
10132
                 * Now fetch and print the OPERATOR entries (pg_amop rows).
 
10133
                 */
 
10134
                ntups = PQntuples(res_ops);
 
10135
 
 
10136
                i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
 
10137
                i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
 
10138
                i_amopopr = PQfnumber(res_ops, "amopopr");
 
10139
                i_sortfamily = PQfnumber(res_ops, "sortfamily");
 
10140
                i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
 
10141
 
 
10142
                for (i = 0; i < ntups; i++)
 
10143
                {
 
10144
                        amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
 
10145
                        amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
 
10146
                        amopopr = PQgetvalue(res_ops, i, i_amopopr);
 
10147
                        sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
 
10148
                        sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
 
10149
 
 
10150
                        if (needComma)
 
10151
                                appendPQExpBuffer(q, " ,\n    ");
 
10152
 
 
10153
                        appendPQExpBuffer(q, "OPERATOR %s %s",
 
10154
                                                          amopstrategy, amopopr);
 
10155
 
 
10156
                        if (strlen(sortfamily) > 0)
 
10157
                        {
 
10158
                                appendPQExpBuffer(q, " FOR ORDER BY ");
 
10159
                                if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
 
10160
                                        appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
 
10161
                                appendPQExpBuffer(q, "%s", fmtId(sortfamily));
 
10162
                        }
 
10163
 
 
10164
                        if (strcmp(amopreqcheck, "t") == 0)
 
10165
                                appendPQExpBuffer(q, " RECHECK");
 
10166
 
 
10167
                        needComma = true;
 
10168
                }
 
10169
 
 
10170
                /*
 
10171
                 * Now fetch and print the FUNCTION entries (pg_amproc rows).
 
10172
                 */
 
10173
                ntups = PQntuples(res_procs);
 
10174
 
 
10175
                i_amprocnum = PQfnumber(res_procs, "amprocnum");
 
10176
                i_amproc = PQfnumber(res_procs, "amproc");
 
10177
                i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
 
10178
                i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
 
10179
 
 
10180
                for (i = 0; i < ntups; i++)
 
10181
                {
 
10182
                        amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
 
10183
                        amproc = PQgetvalue(res_procs, i, i_amproc);
 
10184
                        amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
 
10185
                        amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
 
10186
 
 
10187
                        if (needComma)
 
10188
                                appendPQExpBuffer(q, " ,\n    ");
 
10189
 
 
10190
                        appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
 
10191
                                                          amprocnum, amproclefttype, amprocrighttype,
 
10192
                                                          amproc);
 
10193
 
 
10194
                        needComma = true;
 
10195
                }
 
10196
 
 
10197
                appendPQExpBuffer(q, ";\n");
 
10198
        }
 
10199
 
 
10200
        appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
 
10201
                                          fmtId(opfinfo->dobj.name));
 
10202
        appendPQExpBuffer(labelq, " USING %s",
 
10203
                                          fmtId(amname));
 
10204
 
 
10205
        if (binary_upgrade)
 
10206
                binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
 
10207
 
 
10208
        ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
 
10209
                                 opfinfo->dobj.name,
 
10210
                                 opfinfo->dobj.namespace->dobj.name,
 
10211
                                 NULL,
 
10212
                                 opfinfo->rolname,
 
10213
                                 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
 
10214
                                 q->data, delq->data, NULL,
 
10215
                                 opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
 
10216
                                 NULL, NULL);
 
10217
 
 
10218
        /* Dump Operator Family Comments */
 
10219
        dumpComment(fout, labelq->data,
 
10220
                                NULL, opfinfo->rolname,
 
10221
                                opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
 
10222
 
 
10223
        free(amname);
 
10224
        PQclear(res_ops);
 
10225
        PQclear(res_procs);
 
10226
        destroyPQExpBuffer(query);
 
10227
        destroyPQExpBuffer(q);
 
10228
        destroyPQExpBuffer(delq);
 
10229
        destroyPQExpBuffer(labelq);
 
10230
}
 
10231
 
 
10232
/*
 
10233
 * dumpCollation
 
10234
 *        write out a single collation definition
 
10235
 */
 
10236
static void
 
10237
dumpCollation(Archive *fout, CollInfo *collinfo)
 
10238
{
 
10239
        PQExpBuffer query;
 
10240
        PQExpBuffer q;
 
10241
        PQExpBuffer delq;
 
10242
        PQExpBuffer labelq;
 
10243
        PGresult   *res;
 
10244
        int                     ntups;
 
10245
        int                     i_collcollate;
 
10246
        int                     i_collctype;
 
10247
        const char *collcollate;
 
10248
        const char *collctype;
 
10249
 
 
10250
        /* Skip if not to be dumped */
 
10251
        if (!collinfo->dobj.dump || dataOnly)
 
10252
                return;
 
10253
 
 
10254
        query = createPQExpBuffer();
 
10255
        q = createPQExpBuffer();
 
10256
        delq = createPQExpBuffer();
 
10257
        labelq = createPQExpBuffer();
 
10258
 
 
10259
        /* Make sure we are in proper schema */
 
10260
        selectSourceSchema(collinfo->dobj.namespace->dobj.name);
 
10261
 
 
10262
        /* Get conversion-specific details */
 
10263
        appendPQExpBuffer(query, "SELECT "
 
10264
                                          "collcollate, "
 
10265
                                          "collctype "
 
10266
                                          "FROM pg_catalog.pg_collation c "
 
10267
                                          "WHERE c.oid = '%u'::pg_catalog.oid",
 
10268
                                          collinfo->dobj.catId.oid);
 
10269
 
 
10270
        res = PQexec(g_conn, query->data);
 
10271
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10272
 
 
10273
        /* Expecting a single result only */
 
10274
        ntups = PQntuples(res);
 
10275
        if (ntups != 1)
 
10276
        {
 
10277
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
10278
                                                           "query returned %d rows instead of one: %s\n",
 
10279
                                                                 ntups),
 
10280
                                  ntups, query->data);
 
10281
                exit_nicely();
 
10282
        }
 
10283
 
 
10284
        i_collcollate = PQfnumber(res, "collcollate");
 
10285
        i_collctype = PQfnumber(res, "collctype");
 
10286
 
 
10287
        collcollate = PQgetvalue(res, 0, i_collcollate);
 
10288
        collctype = PQgetvalue(res, 0, i_collctype);
 
10289
 
 
10290
        /*
 
10291
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10292
         */
 
10293
        appendPQExpBuffer(delq, "DROP COLLATION %s",
 
10294
                                          fmtId(collinfo->dobj.namespace->dobj.name));
 
10295
        appendPQExpBuffer(delq, ".%s;\n",
 
10296
                                          fmtId(collinfo->dobj.name));
 
10297
 
 
10298
        appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
 
10299
                                          fmtId(collinfo->dobj.name));
 
10300
        appendStringLiteralAH(q, collcollate, fout);
 
10301
        appendPQExpBuffer(q, ", lc_ctype = ");
 
10302
        appendStringLiteralAH(q, collctype, fout);
 
10303
        appendPQExpBuffer(q, ");\n");
 
10304
 
 
10305
        appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
 
10306
 
 
10307
        if (binary_upgrade)
 
10308
                binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
 
10309
 
 
10310
        ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
 
10311
                                 collinfo->dobj.name,
 
10312
                                 collinfo->dobj.namespace->dobj.name,
 
10313
                                 NULL,
 
10314
                                 collinfo->rolname,
 
10315
                                 false, "COLLATION", SECTION_PRE_DATA,
 
10316
                                 q->data, delq->data, NULL,
 
10317
                                 collinfo->dobj.dependencies, collinfo->dobj.nDeps,
 
10318
                                 NULL, NULL);
 
10319
 
 
10320
        /* Dump Collation Comments */
 
10321
        dumpComment(fout, labelq->data,
 
10322
                                collinfo->dobj.namespace->dobj.name, collinfo->rolname,
 
10323
                                collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
 
10324
 
 
10325
        PQclear(res);
 
10326
 
 
10327
        destroyPQExpBuffer(query);
 
10328
        destroyPQExpBuffer(q);
 
10329
        destroyPQExpBuffer(delq);
 
10330
        destroyPQExpBuffer(labelq);
 
10331
}
 
10332
 
 
10333
/*
 
10334
 * dumpConversion
 
10335
 *        write out a single conversion definition
 
10336
 */
 
10337
static void
 
10338
dumpConversion(Archive *fout, ConvInfo *convinfo)
 
10339
{
 
10340
        PQExpBuffer query;
 
10341
        PQExpBuffer q;
 
10342
        PQExpBuffer delq;
 
10343
        PQExpBuffer labelq;
 
10344
        PGresult   *res;
 
10345
        int                     ntups;
 
10346
        int                     i_conforencoding;
 
10347
        int                     i_contoencoding;
 
10348
        int                     i_conproc;
 
10349
        int                     i_condefault;
 
10350
        const char *conforencoding;
 
10351
        const char *contoencoding;
 
10352
        const char *conproc;
 
10353
        bool            condefault;
 
10354
 
 
10355
        /* Skip if not to be dumped */
 
10356
        if (!convinfo->dobj.dump || dataOnly)
 
10357
                return;
 
10358
 
 
10359
        query = createPQExpBuffer();
 
10360
        q = createPQExpBuffer();
 
10361
        delq = createPQExpBuffer();
 
10362
        labelq = createPQExpBuffer();
 
10363
 
 
10364
        /* Make sure we are in proper schema */
 
10365
        selectSourceSchema(convinfo->dobj.namespace->dobj.name);
 
10366
 
 
10367
        /* Get conversion-specific details */
 
10368
        appendPQExpBuffer(query, "SELECT "
 
10369
                 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
 
10370
                   "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
 
10371
                                          "conproc, condefault "
 
10372
                                          "FROM pg_catalog.pg_conversion c "
 
10373
                                          "WHERE c.oid = '%u'::pg_catalog.oid",
 
10374
                                          convinfo->dobj.catId.oid);
 
10375
 
 
10376
        res = PQexec(g_conn, query->data);
 
10377
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10378
 
 
10379
        /* Expecting a single result only */
 
10380
        ntups = PQntuples(res);
 
10381
        if (ntups != 1)
 
10382
        {
 
10383
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
10384
                                                           "query returned %d rows instead of one: %s\n",
 
10385
                                                                 ntups),
 
10386
                                  ntups, query->data);
 
10387
                exit_nicely();
 
10388
        }
 
10389
 
 
10390
        i_conforencoding = PQfnumber(res, "conforencoding");
 
10391
        i_contoencoding = PQfnumber(res, "contoencoding");
 
10392
        i_conproc = PQfnumber(res, "conproc");
 
10393
        i_condefault = PQfnumber(res, "condefault");
 
10394
 
 
10395
        conforencoding = PQgetvalue(res, 0, i_conforencoding);
 
10396
        contoencoding = PQgetvalue(res, 0, i_contoencoding);
 
10397
        conproc = PQgetvalue(res, 0, i_conproc);
 
10398
        condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
 
10399
 
 
10400
        /*
 
10401
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10402
         */
 
10403
        appendPQExpBuffer(delq, "DROP CONVERSION %s",
 
10404
                                          fmtId(convinfo->dobj.namespace->dobj.name));
 
10405
        appendPQExpBuffer(delq, ".%s;\n",
 
10406
                                          fmtId(convinfo->dobj.name));
 
10407
 
 
10408
        appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
 
10409
                                          (condefault) ? "DEFAULT " : "",
 
10410
                                          fmtId(convinfo->dobj.name));
 
10411
        appendStringLiteralAH(q, conforencoding, fout);
 
10412
        appendPQExpBuffer(q, " TO ");
 
10413
        appendStringLiteralAH(q, contoencoding, fout);
 
10414
        /* regproc is automatically quoted in 7.3 and above */
 
10415
        appendPQExpBuffer(q, " FROM %s;\n", conproc);
 
10416
 
 
10417
        appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
 
10418
 
 
10419
        if (binary_upgrade)
 
10420
                binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
 
10421
 
 
10422
        ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
 
10423
                                 convinfo->dobj.name,
 
10424
                                 convinfo->dobj.namespace->dobj.name,
 
10425
                                 NULL,
 
10426
                                 convinfo->rolname,
 
10427
                                 false, "CONVERSION", SECTION_PRE_DATA,
 
10428
                                 q->data, delq->data, NULL,
 
10429
                                 convinfo->dobj.dependencies, convinfo->dobj.nDeps,
 
10430
                                 NULL, NULL);
 
10431
 
 
10432
        /* Dump Conversion Comments */
 
10433
        dumpComment(fout, labelq->data,
 
10434
                                convinfo->dobj.namespace->dobj.name, convinfo->rolname,
 
10435
                                convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
 
10436
 
 
10437
        PQclear(res);
 
10438
 
 
10439
        destroyPQExpBuffer(query);
 
10440
        destroyPQExpBuffer(q);
 
10441
        destroyPQExpBuffer(delq);
 
10442
        destroyPQExpBuffer(labelq);
 
10443
}
 
10444
 
 
10445
/*
 
10446
 * format_aggregate_signature: generate aggregate name and argument list
 
10447
 *
 
10448
 * The argument type names are qualified if needed.  The aggregate name
 
10449
 * is never qualified.
 
10450
 */
 
10451
static char *
 
10452
format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
 
10453
{
 
10454
        PQExpBufferData buf;
 
10455
        int                     j;
 
10456
 
 
10457
        initPQExpBuffer(&buf);
 
10458
        if (honor_quotes)
 
10459
                appendPQExpBuffer(&buf, "%s",
 
10460
                                                  fmtId(agginfo->aggfn.dobj.name));
 
10461
        else
 
10462
                appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
 
10463
 
 
10464
        if (agginfo->aggfn.nargs == 0)
 
10465
                appendPQExpBuffer(&buf, "(*)");
 
10466
        else
 
10467
        {
 
10468
                appendPQExpBuffer(&buf, "(");
 
10469
                for (j = 0; j < agginfo->aggfn.nargs; j++)
 
10470
                {
 
10471
                        char       *typname;
 
10472
 
 
10473
                        typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
 
10474
 
 
10475
                        appendPQExpBuffer(&buf, "%s%s",
 
10476
                                                          (j > 0) ? ", " : "",
 
10477
                                                          typname);
 
10478
                        free(typname);
 
10479
                }
 
10480
                appendPQExpBuffer(&buf, ")");
 
10481
        }
 
10482
        return buf.data;
 
10483
}
 
10484
 
 
10485
/*
 
10486
 * dumpAgg
 
10487
 *        write out a single aggregate definition
 
10488
 */
 
10489
static void
 
10490
dumpAgg(Archive *fout, AggInfo *agginfo)
 
10491
{
 
10492
        PQExpBuffer query;
 
10493
        PQExpBuffer q;
 
10494
        PQExpBuffer delq;
 
10495
        PQExpBuffer labelq;
 
10496
        PQExpBuffer details;
 
10497
        char       *aggsig;
 
10498
        char       *aggsig_tag;
 
10499
        PGresult   *res;
 
10500
        int                     ntups;
 
10501
        int                     i_aggtransfn;
 
10502
        int                     i_aggfinalfn;
 
10503
        int                     i_aggsortop;
 
10504
        int                     i_aggtranstype;
 
10505
        int                     i_agginitval;
 
10506
        int                     i_convertok;
 
10507
        const char *aggtransfn;
 
10508
        const char *aggfinalfn;
 
10509
        const char *aggsortop;
 
10510
        const char *aggtranstype;
 
10511
        const char *agginitval;
 
10512
        bool            convertok;
 
10513
 
 
10514
        /* Skip if not to be dumped */
 
10515
        if (!agginfo->aggfn.dobj.dump || dataOnly)
 
10516
                return;
 
10517
 
 
10518
        query = createPQExpBuffer();
 
10519
        q = createPQExpBuffer();
 
10520
        delq = createPQExpBuffer();
 
10521
        labelq = createPQExpBuffer();
 
10522
        details = createPQExpBuffer();
 
10523
 
 
10524
        /* Make sure we are in proper schema */
 
10525
        selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
 
10526
 
 
10527
        /* Get aggregate-specific details */
 
10528
        if (g_fout->remoteVersion >= 80100)
 
10529
        {
 
10530
                appendPQExpBuffer(query, "SELECT aggtransfn, "
 
10531
                                                  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
 
10532
                                                  "aggsortop::pg_catalog.regoperator, "
 
10533
                                                  "agginitval, "
 
10534
                                                  "'t'::boolean AS convertok "
 
10535
                                          "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
 
10536
                                                  "WHERE a.aggfnoid = p.oid "
 
10537
                                                  "AND p.oid = '%u'::pg_catalog.oid",
 
10538
                                                  agginfo->aggfn.dobj.catId.oid);
 
10539
        }
 
10540
        else if (g_fout->remoteVersion >= 70300)
 
10541
        {
 
10542
                appendPQExpBuffer(query, "SELECT aggtransfn, "
 
10543
                                                  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
 
10544
                                                  "0 AS aggsortop, "
 
10545
                                                  "agginitval, "
 
10546
                                                  "'t'::boolean AS convertok "
 
10547
                                          "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
 
10548
                                                  "WHERE a.aggfnoid = p.oid "
 
10549
                                                  "AND p.oid = '%u'::pg_catalog.oid",
 
10550
                                                  agginfo->aggfn.dobj.catId.oid);
 
10551
        }
 
10552
        else if (g_fout->remoteVersion >= 70100)
 
10553
        {
 
10554
                appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
 
10555
                                                  "format_type(aggtranstype, NULL) AS aggtranstype, "
 
10556
                                                  "0 AS aggsortop, "
 
10557
                                                  "agginitval, "
 
10558
                                                  "'t'::boolean AS convertok "
 
10559
                                                  "FROM pg_aggregate "
 
10560
                                                  "WHERE oid = '%u'::oid",
 
10561
                                                  agginfo->aggfn.dobj.catId.oid);
 
10562
        }
 
10563
        else
 
10564
        {
 
10565
                appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
 
10566
                                                  "aggfinalfn, "
 
10567
                                                  "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
 
10568
                                                  "0 AS aggsortop, "
 
10569
                                                  "agginitval1 AS agginitval, "
 
10570
                                                  "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
 
10571
                                                  "FROM pg_aggregate "
 
10572
                                                  "WHERE oid = '%u'::oid",
 
10573
                                                  agginfo->aggfn.dobj.catId.oid);
 
10574
        }
 
10575
 
 
10576
        res = PQexec(g_conn, query->data);
 
10577
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10578
 
 
10579
        /* Expecting a single result only */
 
10580
        ntups = PQntuples(res);
 
10581
        if (ntups != 1)
 
10582
        {
 
10583
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
10584
                                                           "query returned %d rows instead of one: %s\n",
 
10585
                                                                 ntups),
 
10586
                                  ntups, query->data);
 
10587
                exit_nicely();
 
10588
        }
 
10589
 
 
10590
        i_aggtransfn = PQfnumber(res, "aggtransfn");
 
10591
        i_aggfinalfn = PQfnumber(res, "aggfinalfn");
 
10592
        i_aggsortop = PQfnumber(res, "aggsortop");
 
10593
        i_aggtranstype = PQfnumber(res, "aggtranstype");
 
10594
        i_agginitval = PQfnumber(res, "agginitval");
 
10595
        i_convertok = PQfnumber(res, "convertok");
 
10596
 
 
10597
        aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
 
10598
        aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
 
10599
        aggsortop = PQgetvalue(res, 0, i_aggsortop);
 
10600
        aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
 
10601
        agginitval = PQgetvalue(res, 0, i_agginitval);
 
10602
        convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
 
10603
 
 
10604
        aggsig = format_aggregate_signature(agginfo, fout, true);
 
10605
        aggsig_tag = format_aggregate_signature(agginfo, fout, false);
 
10606
 
 
10607
        if (!convertok)
 
10608
        {
 
10609
                write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
 
10610
                                  aggsig);
 
10611
                return;
 
10612
        }
 
10613
 
 
10614
        if (g_fout->remoteVersion >= 70300)
 
10615
        {
 
10616
                /* If using 7.3's regproc or regtype, data is already quoted */
 
10617
                appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
 
10618
                                                  aggtransfn,
 
10619
                                                  aggtranstype);
 
10620
        }
 
10621
        else if (g_fout->remoteVersion >= 70100)
 
10622
        {
 
10623
                /* format_type quotes, regproc does not */
 
10624
                appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
 
10625
                                                  fmtId(aggtransfn),
 
10626
                                                  aggtranstype);
 
10627
        }
 
10628
        else
 
10629
        {
 
10630
                /* need quotes all around */
 
10631
                appendPQExpBuffer(details, "    SFUNC = %s,\n",
 
10632
                                                  fmtId(aggtransfn));
 
10633
                appendPQExpBuffer(details, "    STYPE = %s",
 
10634
                                                  fmtId(aggtranstype));
 
10635
        }
 
10636
 
 
10637
        if (!PQgetisnull(res, 0, i_agginitval))
 
10638
        {
 
10639
                appendPQExpBuffer(details, ",\n    INITCOND = ");
 
10640
                appendStringLiteralAH(details, agginitval, fout);
 
10641
        }
 
10642
 
 
10643
        if (strcmp(aggfinalfn, "-") != 0)
 
10644
        {
 
10645
                appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
 
10646
                                                  aggfinalfn);
 
10647
        }
 
10648
 
 
10649
        aggsortop = convertOperatorReference(aggsortop);
 
10650
        if (aggsortop)
 
10651
        {
 
10652
                appendPQExpBuffer(details, ",\n    SORTOP = %s",
 
10653
                                                  aggsortop);
 
10654
        }
 
10655
 
 
10656
        /*
 
10657
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10658
         */
 
10659
        appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
 
10660
                                          fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
 
10661
                                          aggsig);
 
10662
 
 
10663
        appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
 
10664
                                          aggsig, details->data);
 
10665
 
 
10666
        appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
 
10667
 
 
10668
        if (binary_upgrade)
 
10669
                binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
 
10670
 
 
10671
        ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
 
10672
                                 aggsig_tag,
 
10673
                                 agginfo->aggfn.dobj.namespace->dobj.name,
 
10674
                                 NULL,
 
10675
                                 agginfo->aggfn.rolname,
 
10676
                                 false, "AGGREGATE", SECTION_PRE_DATA,
 
10677
                                 q->data, delq->data, NULL,
 
10678
                                 agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
 
10679
                                 NULL, NULL);
 
10680
 
 
10681
        /* Dump Aggregate Comments */
 
10682
        dumpComment(fout, labelq->data,
 
10683
                        agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
 
10684
                                agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
10685
        dumpSecLabel(fout, labelq->data,
 
10686
                        agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
 
10687
                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
 
10688
 
 
10689
        /*
 
10690
         * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
 
10691
         * command look like a function's GRANT; in particular this affects the
 
10692
         * syntax for zero-argument aggregates.
 
10693
         */
 
10694
        free(aggsig);
 
10695
        free(aggsig_tag);
 
10696
 
 
10697
        aggsig = format_function_signature(&agginfo->aggfn, true);
 
10698
        aggsig_tag = format_function_signature(&agginfo->aggfn, false);
 
10699
 
 
10700
        dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
 
10701
                        "FUNCTION",
 
10702
                        aggsig, NULL, aggsig_tag,
 
10703
                        agginfo->aggfn.dobj.namespace->dobj.name,
 
10704
                        agginfo->aggfn.rolname, agginfo->aggfn.proacl);
 
10705
 
 
10706
        free(aggsig);
 
10707
        free(aggsig_tag);
 
10708
 
 
10709
        PQclear(res);
 
10710
 
 
10711
        destroyPQExpBuffer(query);
 
10712
        destroyPQExpBuffer(q);
 
10713
        destroyPQExpBuffer(delq);
 
10714
        destroyPQExpBuffer(labelq);
 
10715
        destroyPQExpBuffer(details);
 
10716
}
 
10717
 
 
10718
/*
 
10719
 * dumpTSParser
 
10720
 *        write out a single text search parser
 
10721
 */
 
10722
static void
 
10723
dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
 
10724
{
 
10725
        PQExpBuffer q;
 
10726
        PQExpBuffer delq;
 
10727
        PQExpBuffer labelq;
 
10728
 
 
10729
        /* Skip if not to be dumped */
 
10730
        if (!prsinfo->dobj.dump || dataOnly)
 
10731
                return;
 
10732
 
 
10733
        q = createPQExpBuffer();
 
10734
        delq = createPQExpBuffer();
 
10735
        labelq = createPQExpBuffer();
 
10736
 
 
10737
        /* Make sure we are in proper schema */
 
10738
        selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
 
10739
 
 
10740
        appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
 
10741
                                          fmtId(prsinfo->dobj.name));
 
10742
 
 
10743
        appendPQExpBuffer(q, "    START = %s,\n",
 
10744
                                          convertTSFunction(prsinfo->prsstart));
 
10745
        appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
 
10746
                                          convertTSFunction(prsinfo->prstoken));
 
10747
        appendPQExpBuffer(q, "    END = %s,\n",
 
10748
                                          convertTSFunction(prsinfo->prsend));
 
10749
        if (prsinfo->prsheadline != InvalidOid)
 
10750
                appendPQExpBuffer(q, "    HEADLINE = %s,\n",
 
10751
                                                  convertTSFunction(prsinfo->prsheadline));
 
10752
        appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
 
10753
                                          convertTSFunction(prsinfo->prslextype));
 
10754
 
 
10755
        /*
 
10756
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10757
         */
 
10758
        appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
 
10759
                                          fmtId(prsinfo->dobj.namespace->dobj.name));
 
10760
        appendPQExpBuffer(delq, ".%s;\n",
 
10761
                                          fmtId(prsinfo->dobj.name));
 
10762
 
 
10763
        appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
 
10764
                                          fmtId(prsinfo->dobj.name));
 
10765
 
 
10766
        if (binary_upgrade)
 
10767
                binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
 
10768
 
 
10769
        ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
 
10770
                                 prsinfo->dobj.name,
 
10771
                                 prsinfo->dobj.namespace->dobj.name,
 
10772
                                 NULL,
 
10773
                                 "",
 
10774
                                 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
 
10775
                                 q->data, delq->data, NULL,
 
10776
                                 prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
 
10777
                                 NULL, NULL);
 
10778
 
 
10779
        /* Dump Parser Comments */
 
10780
        dumpComment(fout, labelq->data,
 
10781
                                NULL, "",
 
10782
                                prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
 
10783
 
 
10784
        destroyPQExpBuffer(q);
 
10785
        destroyPQExpBuffer(delq);
 
10786
        destroyPQExpBuffer(labelq);
 
10787
}
 
10788
 
 
10789
/*
 
10790
 * dumpTSDictionary
 
10791
 *        write out a single text search dictionary
 
10792
 */
 
10793
static void
 
10794
dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
 
10795
{
 
10796
        PQExpBuffer q;
 
10797
        PQExpBuffer delq;
 
10798
        PQExpBuffer labelq;
 
10799
        PQExpBuffer query;
 
10800
        PGresult   *res;
 
10801
        int                     ntups;
 
10802
        char       *nspname;
 
10803
        char       *tmplname;
 
10804
 
 
10805
        /* Skip if not to be dumped */
 
10806
        if (!dictinfo->dobj.dump || dataOnly)
 
10807
                return;
 
10808
 
 
10809
        q = createPQExpBuffer();
 
10810
        delq = createPQExpBuffer();
 
10811
        labelq = createPQExpBuffer();
 
10812
        query = createPQExpBuffer();
 
10813
 
 
10814
        /* Fetch name and namespace of the dictionary's template */
 
10815
        selectSourceSchema("pg_catalog");
 
10816
        appendPQExpBuffer(query, "SELECT nspname, tmplname "
 
10817
                                          "FROM pg_ts_template p, pg_namespace n "
 
10818
                                          "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
 
10819
                                          dictinfo->dicttemplate);
 
10820
        res = PQexec(g_conn, query->data);
 
10821
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10822
        ntups = PQntuples(res);
 
10823
        if (ntups != 1)
 
10824
        {
 
10825
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
10826
                                                           "query returned %d rows instead of one: %s\n",
 
10827
                                                                 ntups),
 
10828
                                  ntups, query->data);
 
10829
                exit_nicely();
 
10830
        }
 
10831
        nspname = PQgetvalue(res, 0, 0);
 
10832
        tmplname = PQgetvalue(res, 0, 1);
 
10833
 
 
10834
        /* Make sure we are in proper schema */
 
10835
        selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
 
10836
 
 
10837
        appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
 
10838
                                          fmtId(dictinfo->dobj.name));
 
10839
 
 
10840
        appendPQExpBuffer(q, "    TEMPLATE = ");
 
10841
        if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
 
10842
                appendPQExpBuffer(q, "%s.", fmtId(nspname));
 
10843
        appendPQExpBuffer(q, "%s", fmtId(tmplname));
 
10844
 
 
10845
        PQclear(res);
 
10846
 
 
10847
        /* the dictinitoption can be dumped straight into the command */
 
10848
        if (dictinfo->dictinitoption)
 
10849
                appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
 
10850
 
 
10851
        appendPQExpBuffer(q, " );\n");
 
10852
 
 
10853
        /*
 
10854
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10855
         */
 
10856
        appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
 
10857
                                          fmtId(dictinfo->dobj.namespace->dobj.name));
 
10858
        appendPQExpBuffer(delq, ".%s;\n",
 
10859
                                          fmtId(dictinfo->dobj.name));
 
10860
 
 
10861
        appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
 
10862
                                          fmtId(dictinfo->dobj.name));
 
10863
 
 
10864
        if (binary_upgrade)
 
10865
                binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
 
10866
 
 
10867
        ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
 
10868
                                 dictinfo->dobj.name,
 
10869
                                 dictinfo->dobj.namespace->dobj.name,
 
10870
                                 NULL,
 
10871
                                 dictinfo->rolname,
 
10872
                                 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
 
10873
                                 q->data, delq->data, NULL,
 
10874
                                 dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
 
10875
                                 NULL, NULL);
 
10876
 
 
10877
        /* Dump Dictionary Comments */
 
10878
        dumpComment(fout, labelq->data,
 
10879
                                NULL, dictinfo->rolname,
 
10880
                                dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
 
10881
 
 
10882
        destroyPQExpBuffer(q);
 
10883
        destroyPQExpBuffer(delq);
 
10884
        destroyPQExpBuffer(labelq);
 
10885
        destroyPQExpBuffer(query);
 
10886
}
 
10887
 
 
10888
/*
 
10889
 * dumpTSTemplate
 
10890
 *        write out a single text search template
 
10891
 */
 
10892
static void
 
10893
dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
 
10894
{
 
10895
        PQExpBuffer q;
 
10896
        PQExpBuffer delq;
 
10897
        PQExpBuffer labelq;
 
10898
 
 
10899
        /* Skip if not to be dumped */
 
10900
        if (!tmplinfo->dobj.dump || dataOnly)
 
10901
                return;
 
10902
 
 
10903
        q = createPQExpBuffer();
 
10904
        delq = createPQExpBuffer();
 
10905
        labelq = createPQExpBuffer();
 
10906
 
 
10907
        /* Make sure we are in proper schema */
 
10908
        selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
 
10909
 
 
10910
        appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
 
10911
                                          fmtId(tmplinfo->dobj.name));
 
10912
 
 
10913
        if (tmplinfo->tmplinit != InvalidOid)
 
10914
                appendPQExpBuffer(q, "    INIT = %s,\n",
 
10915
                                                  convertTSFunction(tmplinfo->tmplinit));
 
10916
        appendPQExpBuffer(q, "    LEXIZE = %s );\n",
 
10917
                                          convertTSFunction(tmplinfo->tmpllexize));
 
10918
 
 
10919
        /*
 
10920
         * DROP must be fully qualified in case same name appears in pg_catalog
 
10921
         */
 
10922
        appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
 
10923
                                          fmtId(tmplinfo->dobj.namespace->dobj.name));
 
10924
        appendPQExpBuffer(delq, ".%s;\n",
 
10925
                                          fmtId(tmplinfo->dobj.name));
 
10926
 
 
10927
        appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
 
10928
                                          fmtId(tmplinfo->dobj.name));
 
10929
 
 
10930
        if (binary_upgrade)
 
10931
                binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
 
10932
 
 
10933
        ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
 
10934
                                 tmplinfo->dobj.name,
 
10935
                                 tmplinfo->dobj.namespace->dobj.name,
 
10936
                                 NULL,
 
10937
                                 "",
 
10938
                                 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
 
10939
                                 q->data, delq->data, NULL,
 
10940
                                 tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
 
10941
                                 NULL, NULL);
 
10942
 
 
10943
        /* Dump Template Comments */
 
10944
        dumpComment(fout, labelq->data,
 
10945
                                NULL, "",
 
10946
                                tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
 
10947
 
 
10948
        destroyPQExpBuffer(q);
 
10949
        destroyPQExpBuffer(delq);
 
10950
        destroyPQExpBuffer(labelq);
 
10951
}
 
10952
 
 
10953
/*
 
10954
 * dumpTSConfig
 
10955
 *        write out a single text search configuration
 
10956
 */
 
10957
static void
 
10958
dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
 
10959
{
 
10960
        PQExpBuffer q;
 
10961
        PQExpBuffer delq;
 
10962
        PQExpBuffer labelq;
 
10963
        PQExpBuffer query;
 
10964
        PGresult   *res;
 
10965
        char       *nspname;
 
10966
        char       *prsname;
 
10967
        int                     ntups,
 
10968
                                i;
 
10969
        int                     i_tokenname;
 
10970
        int                     i_dictname;
 
10971
 
 
10972
        /* Skip if not to be dumped */
 
10973
        if (!cfginfo->dobj.dump || dataOnly)
 
10974
                return;
 
10975
 
 
10976
        q = createPQExpBuffer();
 
10977
        delq = createPQExpBuffer();
 
10978
        labelq = createPQExpBuffer();
 
10979
        query = createPQExpBuffer();
 
10980
 
 
10981
        /* Fetch name and namespace of the config's parser */
 
10982
        selectSourceSchema("pg_catalog");
 
10983
        appendPQExpBuffer(query, "SELECT nspname, prsname "
 
10984
                                          "FROM pg_ts_parser p, pg_namespace n "
 
10985
                                          "WHERE p.oid = '%u' AND n.oid = prsnamespace",
 
10986
                                          cfginfo->cfgparser);
 
10987
        res = PQexec(g_conn, query->data);
 
10988
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
10989
        ntups = PQntuples(res);
 
10990
        if (ntups != 1)
 
10991
        {
 
10992
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
10993
                                                           "query returned %d rows instead of one: %s\n",
 
10994
                                                                 ntups),
 
10995
                                  ntups, query->data);
 
10996
                exit_nicely();
 
10997
        }
 
10998
        nspname = PQgetvalue(res, 0, 0);
 
10999
        prsname = PQgetvalue(res, 0, 1);
 
11000
 
 
11001
        /* Make sure we are in proper schema */
 
11002
        selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
 
11003
 
 
11004
        appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
 
11005
                                          fmtId(cfginfo->dobj.name));
 
11006
 
 
11007
        appendPQExpBuffer(q, "    PARSER = ");
 
11008
        if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
 
11009
                appendPQExpBuffer(q, "%s.", fmtId(nspname));
 
11010
        appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
 
11011
 
 
11012
        PQclear(res);
 
11013
 
 
11014
        resetPQExpBuffer(query);
 
11015
        appendPQExpBuffer(query,
 
11016
                                          "SELECT \n"
 
11017
                                          "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
 
11018
                                          "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
 
11019
                                          "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
 
11020
                                          "FROM pg_catalog.pg_ts_config_map AS m \n"
 
11021
                                          "WHERE m.mapcfg = '%u' \n"
 
11022
                                          "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
 
11023
                                          cfginfo->cfgparser, cfginfo->dobj.catId.oid);
 
11024
 
 
11025
        res = PQexec(g_conn, query->data);
 
11026
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11027
        ntups = PQntuples(res);
 
11028
 
 
11029
        i_tokenname = PQfnumber(res, "tokenname");
 
11030
        i_dictname = PQfnumber(res, "dictname");
 
11031
 
 
11032
        for (i = 0; i < ntups; i++)
 
11033
        {
 
11034
                char       *tokenname = PQgetvalue(res, i, i_tokenname);
 
11035
                char       *dictname = PQgetvalue(res, i, i_dictname);
 
11036
 
 
11037
                if (i == 0 ||
 
11038
                        strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
 
11039
                {
 
11040
                        /* starting a new token type, so start a new command */
 
11041
                        if (i > 0)
 
11042
                                appendPQExpBuffer(q, ";\n");
 
11043
                        appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
 
11044
                                                          fmtId(cfginfo->dobj.name));
 
11045
                        /* tokenname needs quoting, dictname does NOT */
 
11046
                        appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
 
11047
                                                          fmtId(tokenname), dictname);
 
11048
                }
 
11049
                else
 
11050
                        appendPQExpBuffer(q, ", %s", dictname);
 
11051
        }
 
11052
 
 
11053
        if (ntups > 0)
 
11054
                appendPQExpBuffer(q, ";\n");
 
11055
 
 
11056
        PQclear(res);
 
11057
 
 
11058
        /*
 
11059
         * DROP must be fully qualified in case same name appears in pg_catalog
 
11060
         */
 
11061
        appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
 
11062
                                          fmtId(cfginfo->dobj.namespace->dobj.name));
 
11063
        appendPQExpBuffer(delq, ".%s;\n",
 
11064
                                          fmtId(cfginfo->dobj.name));
 
11065
 
 
11066
        appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
 
11067
                                          fmtId(cfginfo->dobj.name));
 
11068
 
 
11069
        if (binary_upgrade)
 
11070
                binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
 
11071
 
 
11072
        ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
 
11073
                                 cfginfo->dobj.name,
 
11074
                                 cfginfo->dobj.namespace->dobj.name,
 
11075
                                 NULL,
 
11076
                                 cfginfo->rolname,
 
11077
                                 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
 
11078
                                 q->data, delq->data, NULL,
 
11079
                                 cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
 
11080
                                 NULL, NULL);
 
11081
 
 
11082
        /* Dump Configuration Comments */
 
11083
        dumpComment(fout, labelq->data,
 
11084
                                NULL, cfginfo->rolname,
 
11085
                                cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
 
11086
 
 
11087
        destroyPQExpBuffer(q);
 
11088
        destroyPQExpBuffer(delq);
 
11089
        destroyPQExpBuffer(labelq);
 
11090
        destroyPQExpBuffer(query);
 
11091
}
 
11092
 
 
11093
/*
 
11094
 * dumpForeignDataWrapper
 
11095
 *        write out a single foreign-data wrapper definition
 
11096
 */
 
11097
static void
 
11098
dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
 
11099
{
 
11100
        PQExpBuffer q;
 
11101
        PQExpBuffer delq;
 
11102
        PQExpBuffer labelq;
 
11103
        char       *qfdwname;
 
11104
 
 
11105
        /* Skip if not to be dumped */
 
11106
        if (!fdwinfo->dobj.dump || dataOnly)
 
11107
                return;
 
11108
 
 
11109
        q = createPQExpBuffer();
 
11110
        delq = createPQExpBuffer();
 
11111
        labelq = createPQExpBuffer();
 
11112
 
 
11113
        qfdwname = strdup(fmtId(fdwinfo->dobj.name));
 
11114
 
 
11115
        appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
 
11116
                                          qfdwname);
 
11117
 
 
11118
        if (strcmp(fdwinfo->fdwhandler, "-") != 0)
 
11119
                appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
 
11120
 
 
11121
        if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
 
11122
                appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
 
11123
 
 
11124
        if (strlen(fdwinfo->fdwoptions) > 0)
 
11125
                appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
 
11126
 
 
11127
        appendPQExpBuffer(q, ";\n");
 
11128
 
 
11129
        appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
 
11130
                                          qfdwname);
 
11131
 
 
11132
        appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
 
11133
                                          qfdwname);
 
11134
 
 
11135
        if (binary_upgrade)
 
11136
                binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
 
11137
 
 
11138
        ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
 
11139
                                 fdwinfo->dobj.name,
 
11140
                                 NULL,
 
11141
                                 NULL,
 
11142
                                 fdwinfo->rolname,
 
11143
                                 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
 
11144
                                 q->data, delq->data, NULL,
 
11145
                                 fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
 
11146
                                 NULL, NULL);
 
11147
 
 
11148
        /* Handle the ACL */
 
11149
        dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
 
11150
                        "FOREIGN DATA WRAPPER",
 
11151
                        qfdwname, NULL, fdwinfo->dobj.name,
 
11152
                        NULL, fdwinfo->rolname,
 
11153
                        fdwinfo->fdwacl);
 
11154
 
 
11155
        /* Dump Foreign Data Wrapper Comments */
 
11156
        dumpComment(fout, labelq->data,
 
11157
                                NULL, fdwinfo->rolname,
 
11158
                                fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
 
11159
 
 
11160
        free(qfdwname);
 
11161
 
 
11162
        destroyPQExpBuffer(q);
 
11163
        destroyPQExpBuffer(delq);
 
11164
        destroyPQExpBuffer(labelq);
 
11165
}
 
11166
 
 
11167
/*
 
11168
 * dumpForeignServer
 
11169
 *        write out a foreign server definition
 
11170
 */
 
11171
static void
 
11172
dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
 
11173
{
 
11174
        PQExpBuffer q;
 
11175
        PQExpBuffer delq;
 
11176
        PQExpBuffer labelq;
 
11177
        PQExpBuffer query;
 
11178
        PGresult   *res;
 
11179
        int                     ntups;
 
11180
        char       *qsrvname;
 
11181
        char       *fdwname;
 
11182
 
 
11183
        /* Skip if not to be dumped */
 
11184
        if (!srvinfo->dobj.dump || dataOnly)
 
11185
                return;
 
11186
 
 
11187
        q = createPQExpBuffer();
 
11188
        delq = createPQExpBuffer();
 
11189
        labelq = createPQExpBuffer();
 
11190
        query = createPQExpBuffer();
 
11191
 
 
11192
        qsrvname = strdup(fmtId(srvinfo->dobj.name));
 
11193
 
 
11194
        /* look up the foreign-data wrapper */
 
11195
        selectSourceSchema("pg_catalog");
 
11196
        appendPQExpBuffer(query, "SELECT fdwname "
 
11197
                                          "FROM pg_foreign_data_wrapper w "
 
11198
                                          "WHERE w.oid = '%u'",
 
11199
                                          srvinfo->srvfdw);
 
11200
        res = PQexec(g_conn, query->data);
 
11201
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11202
        ntups = PQntuples(res);
 
11203
        if (ntups != 1)
 
11204
        {
 
11205
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
11206
                                                           "query returned %d rows instead of one: %s\n",
 
11207
                                                                 ntups),
 
11208
                                  ntups, query->data);
 
11209
                exit_nicely();
 
11210
        }
 
11211
        fdwname = PQgetvalue(res, 0, 0);
 
11212
 
 
11213
        appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
 
11214
        if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
 
11215
        {
 
11216
                appendPQExpBuffer(q, " TYPE ");
 
11217
                appendStringLiteralAH(q, srvinfo->srvtype, fout);
 
11218
        }
 
11219
        if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
 
11220
        {
 
11221
                appendPQExpBuffer(q, " VERSION ");
 
11222
                appendStringLiteralAH(q, srvinfo->srvversion, fout);
 
11223
        }
 
11224
 
 
11225
        appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
 
11226
        appendPQExpBuffer(q, "%s", fmtId(fdwname));
 
11227
 
 
11228
        if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
 
11229
                appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
 
11230
 
 
11231
        appendPQExpBuffer(q, ";\n");
 
11232
 
 
11233
        appendPQExpBuffer(delq, "DROP SERVER %s;\n",
 
11234
                                          qsrvname);
 
11235
 
 
11236
        appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
 
11237
 
 
11238
        if (binary_upgrade)
 
11239
                binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
 
11240
 
 
11241
        ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
 
11242
                                 srvinfo->dobj.name,
 
11243
                                 NULL,
 
11244
                                 NULL,
 
11245
                                 srvinfo->rolname,
 
11246
                                 false, "SERVER", SECTION_PRE_DATA,
 
11247
                                 q->data, delq->data, NULL,
 
11248
                                 srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
 
11249
                                 NULL, NULL);
 
11250
 
 
11251
        /* Handle the ACL */
 
11252
        dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
 
11253
                        "FOREIGN SERVER",
 
11254
                        qsrvname, NULL, srvinfo->dobj.name,
 
11255
                        NULL, srvinfo->rolname,
 
11256
                        srvinfo->srvacl);
 
11257
 
 
11258
        /* Dump user mappings */
 
11259
        dumpUserMappings(fout,
 
11260
                                         srvinfo->dobj.name, NULL,
 
11261
                                         srvinfo->rolname,
 
11262
                                         srvinfo->dobj.catId, srvinfo->dobj.dumpId);
 
11263
 
 
11264
        /* Dump Foreign Server Comments */
 
11265
        dumpComment(fout, labelq->data,
 
11266
                                NULL, srvinfo->rolname,
 
11267
                                srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
 
11268
 
 
11269
        free(qsrvname);
 
11270
 
 
11271
        destroyPQExpBuffer(q);
 
11272
        destroyPQExpBuffer(delq);
 
11273
        destroyPQExpBuffer(labelq);
 
11274
}
 
11275
 
 
11276
/*
 
11277
 * dumpUserMappings
 
11278
 *
 
11279
 * This routine is used to dump any user mappings associated with the
 
11280
 * server handed to this routine. Should be called after ArchiveEntry()
 
11281
 * for the server.
 
11282
 */
 
11283
static void
 
11284
dumpUserMappings(Archive *fout,
 
11285
                                 const char *servername, const char *namespace,
 
11286
                                 const char *owner,
 
11287
                                 CatalogId catalogId, DumpId dumpId)
 
11288
{
 
11289
        PQExpBuffer q;
 
11290
        PQExpBuffer delq;
 
11291
        PQExpBuffer query;
 
11292
        PQExpBuffer tag;
 
11293
        PGresult   *res;
 
11294
        int                     ntups;
 
11295
        int                     i_usename;
 
11296
        int                     i_umoptions;
 
11297
        int                     i;
 
11298
 
 
11299
        q = createPQExpBuffer();
 
11300
        tag = createPQExpBuffer();
 
11301
        delq = createPQExpBuffer();
 
11302
        query = createPQExpBuffer();
 
11303
 
 
11304
        /*
 
11305
         * We read from the publicly accessible view pg_user_mappings, so as not
 
11306
         * to fail if run by a non-superuser.  Note that the view will show
 
11307
         * umoptions as null if the user hasn't got privileges for the associated
 
11308
         * server; this means that pg_dump will dump such a mapping, but with no
 
11309
         * OPTIONS clause.      A possible alternative is to skip such mappings
 
11310
         * altogether, but it's not clear that that's an improvement.
 
11311
         */
 
11312
        selectSourceSchema("pg_catalog");
 
11313
 
 
11314
        appendPQExpBuffer(query,
 
11315
                                          "SELECT usename, "
 
11316
                                          "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
 
11317
                                          "FROM pg_user_mappings "
 
11318
                                          "WHERE srvid = %u",
 
11319
                                          catalogId.oid);
 
11320
 
 
11321
        res = PQexec(g_conn, query->data);
 
11322
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11323
 
 
11324
        ntups = PQntuples(res);
 
11325
        i_usename = PQfnumber(res, "usename");
 
11326
        i_umoptions = PQfnumber(res, "umoptions");
 
11327
 
 
11328
        for (i = 0; i < ntups; i++)
 
11329
        {
 
11330
                char       *usename;
 
11331
                char       *umoptions;
 
11332
 
 
11333
                usename = PQgetvalue(res, i, i_usename);
 
11334
                umoptions = PQgetvalue(res, i, i_umoptions);
 
11335
 
 
11336
                resetPQExpBuffer(q);
 
11337
                appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
 
11338
                appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
 
11339
 
 
11340
                if (umoptions && strlen(umoptions) > 0)
 
11341
                        appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
 
11342
 
 
11343
                appendPQExpBuffer(q, ";\n");
 
11344
 
 
11345
                resetPQExpBuffer(delq);
 
11346
                appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
 
11347
                appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
 
11348
 
 
11349
                resetPQExpBuffer(tag);
 
11350
                appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
 
11351
                                                  usename, servername);
 
11352
 
 
11353
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
11354
                                         tag->data,
 
11355
                                         namespace,
 
11356
                                         NULL,
 
11357
                                         owner, false,
 
11358
                                         "USER MAPPING", SECTION_PRE_DATA,
 
11359
                                         q->data, delq->data, NULL,
 
11360
                                         &dumpId, 1,
 
11361
                                         NULL, NULL);
 
11362
        }
 
11363
 
 
11364
        PQclear(res);
 
11365
 
 
11366
        destroyPQExpBuffer(query);
 
11367
        destroyPQExpBuffer(delq);
 
11368
        destroyPQExpBuffer(q);
 
11369
}
 
11370
 
 
11371
/*
 
11372
 * Write out default privileges information
 
11373
 */
 
11374
static void
 
11375
dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
 
11376
{
 
11377
        PQExpBuffer q;
 
11378
        PQExpBuffer tag;
 
11379
        const char *type;
 
11380
 
 
11381
        /* Skip if not to be dumped */
 
11382
        if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
 
11383
                return;
 
11384
 
 
11385
        q = createPQExpBuffer();
 
11386
        tag = createPQExpBuffer();
 
11387
 
 
11388
        switch (daclinfo->defaclobjtype)
 
11389
        {
 
11390
                case DEFACLOBJ_RELATION:
 
11391
                        type = "TABLES";
 
11392
                        break;
 
11393
                case DEFACLOBJ_SEQUENCE:
 
11394
                        type = "SEQUENCES";
 
11395
                        break;
 
11396
                case DEFACLOBJ_FUNCTION:
 
11397
                        type = "FUNCTIONS";
 
11398
                        break;
 
11399
                default:
 
11400
                        /* shouldn't get here */
 
11401
                        write_msg(NULL, "unknown object type (%d) in default privileges\n",
 
11402
                                          (int) daclinfo->defaclobjtype);
 
11403
                        exit_nicely();
 
11404
                        type = "";                      /* keep compiler quiet */
 
11405
        }
 
11406
 
 
11407
        appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
 
11408
 
 
11409
        /* build the actual command(s) for this tuple */
 
11410
        if (!buildDefaultACLCommands(type,
 
11411
                                                                 daclinfo->dobj.namespace != NULL ?
 
11412
                                                                 daclinfo->dobj.namespace->dobj.name : NULL,
 
11413
                                                                 daclinfo->defaclacl,
 
11414
                                                                 daclinfo->defaclrole,
 
11415
                                                                 fout->remoteVersion,
 
11416
                                                                 q))
 
11417
        {
 
11418
                write_msg(NULL, "could not parse default ACL list (%s)\n",
 
11419
                                  daclinfo->defaclacl);
 
11420
                exit_nicely();
 
11421
        }
 
11422
 
 
11423
        ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
 
11424
                                 tag->data,
 
11425
           daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
 
11426
                                 NULL,
 
11427
                                 daclinfo->defaclrole,
 
11428
                                 false, "DEFAULT ACL", SECTION_NONE,
 
11429
                                 q->data, "", NULL,
 
11430
                                 daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
 
11431
                                 NULL, NULL);
 
11432
 
 
11433
        destroyPQExpBuffer(tag);
 
11434
        destroyPQExpBuffer(q);
 
11435
}
 
11436
 
 
11437
/*----------
 
11438
 * Write out grant/revoke information
 
11439
 *
 
11440
 * 'objCatId' is the catalog ID of the underlying object.
 
11441
 * 'objDumpId' is the dump ID of the underlying object.
 
11442
 * 'type' must be one of
 
11443
 *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
 
11444
 *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
 
11445
 * 'name' is the formatted name of the object.  Must be quoted etc. already.
 
11446
 * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
 
11447
 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
 
11448
 * 'nspname' is the namespace the object is in (NULL if none).
 
11449
 * 'owner' is the owner, NULL if there is no owner (for languages).
 
11450
 * 'acls' is the string read out of the fooacl system catalog field;
 
11451
 *              it will be parsed here.
 
11452
 *----------
 
11453
 */
 
11454
static void
 
11455
dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
 
11456
                const char *type, const char *name, const char *subname,
 
11457
                const char *tag, const char *nspname, const char *owner,
 
11458
                const char *acls)
 
11459
{
 
11460
        PQExpBuffer sql;
 
11461
 
 
11462
        /* Do nothing if ACL dump is not enabled */
 
11463
        if (aclsSkip)
 
11464
                return;
 
11465
 
 
11466
        /* --data-only skips ACLs *except* BLOB ACLs */
 
11467
        if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
 
11468
                return;
 
11469
 
 
11470
        sql = createPQExpBuffer();
 
11471
 
 
11472
        if (!buildACLCommands(name, subname, type, acls, owner,
 
11473
                                                  "", fout->remoteVersion, sql))
 
11474
        {
 
11475
                write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
 
11476
                                  acls, name, type);
 
11477
                exit_nicely();
 
11478
        }
 
11479
 
 
11480
        if (sql->len > 0)
 
11481
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
11482
                                         tag, nspname,
 
11483
                                         NULL,
 
11484
                                         owner ? owner : "",
 
11485
                                         false, "ACL", SECTION_NONE,
 
11486
                                         sql->data, "", NULL,
 
11487
                                         &(objDumpId), 1,
 
11488
                                         NULL, NULL);
 
11489
 
 
11490
        destroyPQExpBuffer(sql);
 
11491
}
 
11492
 
 
11493
/*
 
11494
 * dumpSecLabel
 
11495
 *
 
11496
 * This routine is used to dump any security labels associated with the
 
11497
 * object handed to this routine. The routine takes a constant character
 
11498
 * string for the target part of the security-label command, plus
 
11499
 * the namespace and owner of the object (for labeling the ArchiveEntry),
 
11500
 * plus catalog ID and subid which are the lookup key for pg_seclabel,
 
11501
 * plus the dump ID for the object (for setting a dependency).
 
11502
 * If a matching pg_seclabel entry is found, it is dumped.
 
11503
 *
 
11504
 * Note: although this routine takes a dumpId for dependency purposes,
 
11505
 * that purpose is just to mark the dependency in the emitted dump file
 
11506
 * for possible future use by pg_restore.  We do NOT use it for determining
 
11507
 * ordering of the label in the dump file, because this routine is called
 
11508
 * after dependency sorting occurs.  This routine should be called just after
 
11509
 * calling ArchiveEntry() for the specified object.
 
11510
 */
 
11511
static void
 
11512
dumpSecLabel(Archive *fout, const char *target,
 
11513
                         const char *namespace, const char *owner,
 
11514
                         CatalogId catalogId, int subid, DumpId dumpId)
 
11515
{
 
11516
        SecLabelItem *labels;
 
11517
        int                     nlabels;
 
11518
        int                     i;
 
11519
        PQExpBuffer query;
 
11520
 
 
11521
        /* do nothing, if --no-security-label is supplied */
 
11522
        if (no_security_label)
 
11523
                return;
 
11524
 
 
11525
        /* Comments are schema not data ... except blob comments are data */
 
11526
        if (strncmp(target, "LARGE OBJECT ", 13) != 0)
 
11527
        {
 
11528
                if (dataOnly)
 
11529
                        return;
 
11530
        }
 
11531
        else
 
11532
        {
 
11533
                if (schemaOnly)
 
11534
                        return;
 
11535
        }
 
11536
 
 
11537
        /* Search for security labels associated with catalogId, using table */
 
11538
        nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
 
11539
 
 
11540
        query = createPQExpBuffer();
 
11541
 
 
11542
        for (i = 0; i < nlabels; i++)
 
11543
        {
 
11544
                /*
 
11545
                 * Ignore label entries for which the subid doesn't match.
 
11546
                 */
 
11547
                if (labels[i].objsubid != subid)
 
11548
                        continue;
 
11549
 
 
11550
                appendPQExpBuffer(query,
 
11551
                                                  "SECURITY LABEL FOR %s ON %s IS ",
 
11552
                                                  fmtId(labels[i].provider), target);
 
11553
                appendStringLiteralAH(query, labels[i].label, fout);
 
11554
                appendPQExpBuffer(query, ";\n");
 
11555
        }
 
11556
 
 
11557
        if (query->len > 0)
 
11558
        {
 
11559
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
11560
                                         target, namespace, NULL, owner,
 
11561
                                         false, "SECURITY LABEL", SECTION_NONE,
 
11562
                                         query->data, "", NULL,
 
11563
                                         &(dumpId), 1,
 
11564
                                         NULL, NULL);
 
11565
        }
 
11566
        destroyPQExpBuffer(query);
 
11567
}
 
11568
 
 
11569
/*
 
11570
 * dumpTableSecLabel
 
11571
 *
 
11572
 * As above, but dump security label for both the specified table (or view)
 
11573
 * and its columns.
 
11574
 */
 
11575
static void
 
11576
dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
 
11577
{
 
11578
        SecLabelItem *labels;
 
11579
        int                     nlabels;
 
11580
        int                     i;
 
11581
        PQExpBuffer query;
 
11582
        PQExpBuffer target;
 
11583
 
 
11584
        /* do nothing, if --no-security-label is supplied */
 
11585
        if (no_security_label)
 
11586
                return;
 
11587
 
 
11588
        /* SecLabel are SCHEMA not data */
 
11589
        if (dataOnly)
 
11590
                return;
 
11591
 
 
11592
        /* Search for comments associated with relation, using table */
 
11593
        nlabels = findSecLabels(fout,
 
11594
                                                        tbinfo->dobj.catId.tableoid,
 
11595
                                                        tbinfo->dobj.catId.oid,
 
11596
                                                        &labels);
 
11597
 
 
11598
        /* If security labels exist, build SECURITY LABEL statements */
 
11599
        if (nlabels <= 0)
 
11600
                return;
 
11601
 
 
11602
        query = createPQExpBuffer();
 
11603
        target = createPQExpBuffer();
 
11604
 
 
11605
        for (i = 0; i < nlabels; i++)
 
11606
        {
 
11607
                const char *colname;
 
11608
                const char *provider = labels[i].provider;
 
11609
                const char *label = labels[i].label;
 
11610
                int                     objsubid = labels[i].objsubid;
 
11611
 
 
11612
                resetPQExpBuffer(target);
 
11613
                if (objsubid == 0)
 
11614
                {
 
11615
                        appendPQExpBuffer(target, "%s %s", reltypename,
 
11616
                                                          fmtId(tbinfo->dobj.name));
 
11617
                }
 
11618
                else
 
11619
                {
 
11620
                        colname = getAttrName(objsubid, tbinfo);
 
11621
                        /* first fmtId result must be consumed before calling it again */
 
11622
                        appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
 
11623
                        appendPQExpBuffer(target, ".%s", fmtId(colname));
 
11624
                }
 
11625
                appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
 
11626
                                                  fmtId(provider), target->data);
 
11627
                appendStringLiteralAH(query, label, fout);
 
11628
                appendPQExpBuffer(query, ";\n");
 
11629
        }
 
11630
        if (query->len > 0)
 
11631
        {
 
11632
                resetPQExpBuffer(target);
 
11633
                appendPQExpBuffer(target, "%s %s", reltypename,
 
11634
                                                  fmtId(tbinfo->dobj.name));
 
11635
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
11636
                                         target->data,
 
11637
                                         tbinfo->dobj.namespace->dobj.name,
 
11638
                                         NULL, tbinfo->rolname,
 
11639
                                         false, "SECURITY LABEL", SECTION_NONE,
 
11640
                                         query->data, "", NULL,
 
11641
                                         &(tbinfo->dobj.dumpId), 1,
 
11642
                                         NULL, NULL);
 
11643
        }
 
11644
        destroyPQExpBuffer(query);
 
11645
        destroyPQExpBuffer(target);
 
11646
}
 
11647
 
 
11648
/*
 
11649
 * findSecLabels
 
11650
 *
 
11651
 * Find the security label(s), if any, associated with the given object.
 
11652
 * All the objsubid values associated with the given classoid/objoid are
 
11653
 * found with one search.
 
11654
 */
 
11655
static int
 
11656
findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
 
11657
{
 
11658
        /* static storage for table of security labels */
 
11659
        static SecLabelItem *labels = NULL;
 
11660
        static int      nlabels = -1;
 
11661
 
 
11662
        SecLabelItem *middle = NULL;
 
11663
        SecLabelItem *low;
 
11664
        SecLabelItem *high;
 
11665
        int                     nmatch;
 
11666
 
 
11667
        /* Get security labels if we didn't already */
 
11668
        if (nlabels < 0)
 
11669
                nlabels = collectSecLabels(fout, &labels);
 
11670
 
 
11671
        /*
 
11672
         * Do binary search to find some item matching the object.
 
11673
         */
 
11674
        low = &labels[0];
 
11675
        high = &labels[nlabels - 1];
 
11676
        while (low <= high)
 
11677
        {
 
11678
                middle = low + (high - low) / 2;
 
11679
 
 
11680
                if (classoid < middle->classoid)
 
11681
                        high = middle - 1;
 
11682
                else if (classoid > middle->classoid)
 
11683
                        low = middle + 1;
 
11684
                else if (objoid < middle->objoid)
 
11685
                        high = middle - 1;
 
11686
                else if (objoid > middle->objoid)
 
11687
                        low = middle + 1;
 
11688
                else
 
11689
                        break;                          /* found a match */
 
11690
        }
 
11691
 
 
11692
        if (low > high)                         /* no matches */
 
11693
        {
 
11694
                *items = NULL;
 
11695
                return 0;
 
11696
        }
 
11697
 
 
11698
        /*
 
11699
         * Now determine how many items match the object.  The search loop
 
11700
         * invariant still holds: only items between low and high inclusive could
 
11701
         * match.
 
11702
         */
 
11703
        nmatch = 1;
 
11704
        while (middle > low)
 
11705
        {
 
11706
                if (classoid != middle[-1].classoid ||
 
11707
                        objoid != middle[-1].objoid)
 
11708
                        break;
 
11709
                middle--;
 
11710
                nmatch++;
 
11711
        }
 
11712
 
 
11713
        *items = middle;
 
11714
 
 
11715
        middle += nmatch;
 
11716
        while (middle <= high)
 
11717
        {
 
11718
                if (classoid != middle->classoid ||
 
11719
                        objoid != middle->objoid)
 
11720
                        break;
 
11721
                middle++;
 
11722
                nmatch++;
 
11723
        }
 
11724
 
 
11725
        return nmatch;
 
11726
}
 
11727
 
 
11728
/*
 
11729
 * collectSecLabels
 
11730
 *
 
11731
 * Construct a table of all security labels available for database objects.
 
11732
 * It's much faster to pull them all at once.
 
11733
 *
 
11734
 * The table is sorted by classoid/objid/objsubid for speed in lookup.
 
11735
 */
 
11736
static int
 
11737
collectSecLabels(Archive *fout, SecLabelItem **items)
 
11738
{
 
11739
        PGresult   *res;
 
11740
        PQExpBuffer query;
 
11741
        int                     i_label;
 
11742
        int                     i_provider;
 
11743
        int                     i_classoid;
 
11744
        int                     i_objoid;
 
11745
        int                     i_objsubid;
 
11746
        int                     ntups;
 
11747
        int                     i;
 
11748
        SecLabelItem *labels;
 
11749
 
 
11750
        query = createPQExpBuffer();
 
11751
 
 
11752
        appendPQExpBuffer(query,
 
11753
                                          "SELECT label, provider, classoid, objoid, objsubid "
 
11754
                                          "FROM pg_catalog.pg_seclabel "
 
11755
                                          "ORDER BY classoid, objoid, objsubid");
 
11756
 
 
11757
        res = PQexec(g_conn, query->data);
 
11758
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11759
 
 
11760
        /* Construct lookup table containing OIDs in numeric form */
 
11761
        i_label = PQfnumber(res, "label");
 
11762
        i_provider = PQfnumber(res, "provider");
 
11763
        i_classoid = PQfnumber(res, "classoid");
 
11764
        i_objoid = PQfnumber(res, "objoid");
 
11765
        i_objsubid = PQfnumber(res, "objsubid");
 
11766
 
 
11767
        ntups = PQntuples(res);
 
11768
 
 
11769
        labels = (SecLabelItem *) malloc(ntups * sizeof(SecLabelItem));
 
11770
 
 
11771
        for (i = 0; i < ntups; i++)
 
11772
        {
 
11773
                labels[i].label = PQgetvalue(res, i, i_label);
 
11774
                labels[i].provider = PQgetvalue(res, i, i_provider);
 
11775
                labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
 
11776
                labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
 
11777
                labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
 
11778
        }
 
11779
 
 
11780
        /* Do NOT free the PGresult since we are keeping pointers into it */
 
11781
        destroyPQExpBuffer(query);
 
11782
 
 
11783
        *items = labels;
 
11784
        return ntups;
 
11785
}
 
11786
 
 
11787
/*
 
11788
 * dumpTable
 
11789
 *        write out to fout the declarations (not data) of a user-defined table
 
11790
 */
 
11791
static void
 
11792
dumpTable(Archive *fout, TableInfo *tbinfo)
 
11793
{
 
11794
        if (tbinfo->dobj.dump)
 
11795
        {
 
11796
                char       *namecopy;
 
11797
 
 
11798
                if (tbinfo->relkind == RELKIND_SEQUENCE)
 
11799
                        dumpSequence(fout, tbinfo);
 
11800
                else if (!dataOnly)
 
11801
                        dumpTableSchema(fout, tbinfo);
 
11802
 
 
11803
                /* Handle the ACL here */
 
11804
                namecopy = strdup(fmtId(tbinfo->dobj.name));
 
11805
                dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 
11806
                                (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
 
11807
                                (tbinfo->relkind == RELKIND_FOREIGN_TABLE) ? "FOREIGN TABLE" :
 
11808
                                "TABLE",
 
11809
                                namecopy, NULL, tbinfo->dobj.name,
 
11810
                                tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 
11811
                                tbinfo->relacl);
 
11812
 
 
11813
                /*
 
11814
                 * Handle column ACLs, if any.  Note: we pull these with a separate
 
11815
                 * query rather than trying to fetch them during getTableAttrs, so
 
11816
                 * that we won't miss ACLs on system columns.
 
11817
                 */
 
11818
                if (g_fout->remoteVersion >= 80400)
 
11819
                {
 
11820
                        PQExpBuffer query = createPQExpBuffer();
 
11821
                        PGresult   *res;
 
11822
                        int                     i;
 
11823
 
 
11824
                        appendPQExpBuffer(query,
 
11825
                                           "SELECT attname, attacl FROM pg_catalog.pg_attribute "
 
11826
                                                          "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
 
11827
                                                          "ORDER BY attnum",
 
11828
                                                          tbinfo->dobj.catId.oid);
 
11829
                        res = PQexec(g_conn, query->data);
 
11830
                        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11831
 
 
11832
                        for (i = 0; i < PQntuples(res); i++)
 
11833
                        {
 
11834
                                char       *attname = PQgetvalue(res, i, 0);
 
11835
                                char       *attacl = PQgetvalue(res, i, 1);
 
11836
                                char       *attnamecopy;
 
11837
                                char       *acltag;
 
11838
 
 
11839
                                attnamecopy = strdup(fmtId(attname));
 
11840
                                acltag = malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
 
11841
                                sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
 
11842
                                /* Column's GRANT type is always TABLE */
 
11843
                                dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
 
11844
                                                namecopy, attnamecopy, acltag,
 
11845
                                                tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 
11846
                                                attacl);
 
11847
                                free(attnamecopy);
 
11848
                                free(acltag);
 
11849
                        }
 
11850
                        PQclear(res);
 
11851
                        destroyPQExpBuffer(query);
 
11852
                }
 
11853
 
 
11854
                free(namecopy);
 
11855
        }
 
11856
}
 
11857
 
 
11858
/*
 
11859
 * dumpTableSchema
 
11860
 *        write the declaration (not data) of one user-defined table or view
 
11861
 */
 
11862
static void
 
11863
dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 
11864
{
 
11865
        PQExpBuffer query = createPQExpBuffer();
 
11866
        PQExpBuffer q = createPQExpBuffer();
 
11867
        PQExpBuffer delq = createPQExpBuffer();
 
11868
        PQExpBuffer labelq = createPQExpBuffer();
 
11869
        PGresult   *res;
 
11870
        int                     numParents;
 
11871
        TableInfo **parents;
 
11872
        int                     actual_atts;    /* number of attrs in this CREATE statment */
 
11873
        char       *reltypename;
 
11874
        char       *storage;
 
11875
        int                     j,
 
11876
                                k;
 
11877
        char       *srvname;
 
11878
        char       *ftoptions = NULL;
 
11879
 
 
11880
        /* Make sure we are in proper schema */
 
11881
        selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
11882
 
 
11883
        if (binary_upgrade)
 
11884
                binary_upgrade_set_type_oids_by_rel_oid(q,
 
11885
                                                                                                         tbinfo->dobj.catId.oid);
 
11886
 
 
11887
        /* Is it a table or a view? */
 
11888
        if (tbinfo->relkind == RELKIND_VIEW)
 
11889
        {
 
11890
                char       *viewdef;
 
11891
 
 
11892
                reltypename = "VIEW";
 
11893
 
 
11894
                /* Fetch the view definition */
 
11895
                if (g_fout->remoteVersion >= 70300)
 
11896
                {
 
11897
                        /* Beginning in 7.3, viewname is not unique; rely on OID */
 
11898
                        appendPQExpBuffer(query,
 
11899
                                                          "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
 
11900
                                                          tbinfo->dobj.catId.oid);
 
11901
                }
 
11902
                else
 
11903
                {
 
11904
                        appendPQExpBuffer(query, "SELECT definition AS viewdef "
 
11905
                                                          "FROM pg_views WHERE viewname = ");
 
11906
                        appendStringLiteralAH(query, tbinfo->dobj.name, fout);
 
11907
                        appendPQExpBuffer(query, ";");
 
11908
                }
 
11909
 
 
11910
                res = PQexec(g_conn, query->data);
 
11911
                check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11912
 
 
11913
                if (PQntuples(res) != 1)
 
11914
                {
 
11915
                        if (PQntuples(res) < 1)
 
11916
                                write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
 
11917
                                                  tbinfo->dobj.name);
 
11918
                        else
 
11919
                                write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
 
11920
                                                  tbinfo->dobj.name);
 
11921
                        exit_nicely();
 
11922
                }
 
11923
 
 
11924
                viewdef = PQgetvalue(res, 0, 0);
 
11925
 
 
11926
                if (strlen(viewdef) == 0)
 
11927
                {
 
11928
                        write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
 
11929
                                          tbinfo->dobj.name);
 
11930
                        exit_nicely();
 
11931
                }
 
11932
 
 
11933
                /*
 
11934
                 * DROP must be fully qualified in case same name appears in
 
11935
                 * pg_catalog
 
11936
                 */
 
11937
                appendPQExpBuffer(delq, "DROP VIEW %s.",
 
11938
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
11939
                appendPQExpBuffer(delq, "%s;\n",
 
11940
                                                  fmtId(tbinfo->dobj.name));
 
11941
 
 
11942
                if (binary_upgrade)
 
11943
                        binary_upgrade_set_pg_class_oids(q, tbinfo->dobj.catId.oid, false);
 
11944
 
 
11945
                appendPQExpBuffer(q, "CREATE VIEW %s AS\n    %s\n",
 
11946
                                                  fmtId(tbinfo->dobj.name), viewdef);
 
11947
 
 
11948
                appendPQExpBuffer(labelq, "VIEW %s",
 
11949
                                                  fmtId(tbinfo->dobj.name));
 
11950
 
 
11951
                PQclear(res);
 
11952
        }
 
11953
        else
 
11954
        {
 
11955
                if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
 
11956
                {
 
11957
                        int                     i_srvname;
 
11958
                        int                     i_ftoptions;
 
11959
 
 
11960
                        reltypename = "FOREIGN TABLE";
 
11961
 
 
11962
                        /* retrieve name of foreign server and generic options */
 
11963
                        appendPQExpBuffer(query,
 
11964
                                                          "SELECT fs.srvname, array_to_string(ARRAY("
 
11965
                                "   SELECT option_name || ' ' || quote_literal(option_value)"
 
11966
                           "   FROM pg_options_to_table(ftoptions)), ', ') AS ftoptions "
 
11967
                                                "FROM pg_foreign_table ft JOIN pg_foreign_server fs "
 
11968
                                                          "     ON (fs.oid = ft.ftserver) "
 
11969
                                                        "WHERE ft.ftrelid = %u", tbinfo->dobj.catId.oid);
 
11970
                        res = PQexec(g_conn, query->data);
 
11971
                        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
11972
                        i_srvname = PQfnumber(res, "srvname");
 
11973
                        i_ftoptions = PQfnumber(res, "ftoptions");
 
11974
                        srvname = strdup(PQgetvalue(res, 0, i_srvname));
 
11975
                        ftoptions = strdup(PQgetvalue(res, 0, i_ftoptions));
 
11976
                        PQclear(res);
 
11977
                }
 
11978
                else
 
11979
                {
 
11980
                        reltypename = "TABLE";
 
11981
                        srvname = NULL;
 
11982
                        ftoptions = NULL;
 
11983
                }
 
11984
                numParents = tbinfo->numParents;
 
11985
                parents = tbinfo->parents;
 
11986
 
 
11987
                /*
 
11988
                 * DROP must be fully qualified in case same name appears in
 
11989
                 * pg_catalog
 
11990
                 */
 
11991
                appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
 
11992
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
11993
                appendPQExpBuffer(delq, "%s;\n",
 
11994
                                                  fmtId(tbinfo->dobj.name));
 
11995
 
 
11996
                appendPQExpBuffer(labelq, "%s %s", reltypename,
 
11997
                                                  fmtId(tbinfo->dobj.name));
 
11998
 
 
11999
                if (binary_upgrade)
 
12000
                        binary_upgrade_set_pg_class_oids(q, tbinfo->dobj.catId.oid, false);
 
12001
 
 
12002
                appendPQExpBuffer(q, "CREATE %s%s %s",
 
12003
                                                  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
 
12004
                                                  "UNLOGGED " : "",
 
12005
                                                  reltypename,
 
12006
                                                  fmtId(tbinfo->dobj.name));
 
12007
                /*
 
12008
                 * In case of a binary upgrade, we dump the table normally and attach
 
12009
                 * it to the type afterward.
 
12010
                 */
 
12011
                if (tbinfo->reloftype && !binary_upgrade)
 
12012
                        appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
 
12013
                actual_atts = 0;
 
12014
                for (j = 0; j < tbinfo->numatts; j++)
 
12015
                {
 
12016
                        /*
 
12017
                         * Normally, dump if it's one of the table's own attrs, and not
 
12018
                         * dropped.  But for binary upgrade, dump all the columns.
 
12019
                         */
 
12020
                        if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
 
12021
                                binary_upgrade)
 
12022
                        {
 
12023
                                /*
 
12024
                                 * Default value --- suppress if inherited (except in
 
12025
                                 * binary-upgrade case, where we're not doing normal
 
12026
                                 * inheritance) or if it's to be printed separately.
 
12027
                                 */
 
12028
                                bool            has_default = (tbinfo->attrdefs[j] != NULL
 
12029
                                                                && (!tbinfo->inhAttrDef[j] || binary_upgrade)
 
12030
                                                                                   && !tbinfo->attrdefs[j]->separate);
 
12031
 
 
12032
                                /*
 
12033
                                 * Not Null constraint --- suppress if inherited, except in
 
12034
                                 * binary-upgrade case.
 
12035
                                 */
 
12036
                                bool            has_notnull = (tbinfo->notnull[j]
 
12037
                                                          && (!tbinfo->inhNotNull[j] || binary_upgrade));
 
12038
 
 
12039
                                if (tbinfo->reloftype && !has_default && !has_notnull && !binary_upgrade)
 
12040
                                        continue;
 
12041
 
 
12042
                                /* Format properly if not first attr */
 
12043
                                if (actual_atts == 0)
 
12044
                                        appendPQExpBuffer(q, " (");
 
12045
                                else
 
12046
                                        appendPQExpBuffer(q, ",");
 
12047
                                appendPQExpBuffer(q, "\n    ");
 
12048
                                actual_atts++;
 
12049
 
 
12050
                                /* Attribute name */
 
12051
                                appendPQExpBuffer(q, "%s ",
 
12052
                                                                  fmtId(tbinfo->attnames[j]));
 
12053
 
 
12054
                                if (tbinfo->attisdropped[j])
 
12055
                                {
 
12056
                                        /*
 
12057
                                         * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
 
12058
                                         * so we will not have gotten a valid type name; insert
 
12059
                                         * INTEGER as a stopgap.  We'll clean things up later.
 
12060
                                         */
 
12061
                                        appendPQExpBuffer(q, "INTEGER /* dummy */");
 
12062
                                        /* Skip all the rest, too */
 
12063
                                        continue;
 
12064
                                }
 
12065
 
 
12066
                                /* Attribute type */
 
12067
                                if (tbinfo->reloftype && !binary_upgrade)
 
12068
                                {
 
12069
                                        appendPQExpBuffer(q, "WITH OPTIONS");
 
12070
                                }
 
12071
                                else if (g_fout->remoteVersion >= 70100)
 
12072
                                {
 
12073
                                        appendPQExpBuffer(q, "%s",
 
12074
                                                                          tbinfo->atttypnames[j]);
 
12075
                                }
 
12076
                                else
 
12077
                                {
 
12078
                                        /* If no format_type, fake it */
 
12079
                                        appendPQExpBuffer(q, "%s",
 
12080
                                                                          myFormatType(tbinfo->atttypnames[j],
 
12081
                                                                                                   tbinfo->atttypmod[j]));
 
12082
                                }
 
12083
 
 
12084
                                /* Add collation if not default for the type */
 
12085
                                if (OidIsValid(tbinfo->attcollation[j]))
 
12086
                                {
 
12087
                                        CollInfo   *coll;
 
12088
 
 
12089
                                        coll = findCollationByOid(tbinfo->attcollation[j]);
 
12090
                                        if (coll)
 
12091
                                        {
 
12092
                                                /* always schema-qualify, don't try to be smart */
 
12093
                                                appendPQExpBuffer(q, " COLLATE %s.",
 
12094
                                                                         fmtId(coll->dobj.namespace->dobj.name));
 
12095
                                                appendPQExpBuffer(q, "%s",
 
12096
                                                                                  fmtId(coll->dobj.name));
 
12097
                                        }
 
12098
                                }
 
12099
 
 
12100
                                if (has_default)
 
12101
                                        appendPQExpBuffer(q, " DEFAULT %s",
 
12102
                                                                          tbinfo->attrdefs[j]->adef_expr);
 
12103
 
 
12104
                                if (has_notnull)
 
12105
                                        appendPQExpBuffer(q, " NOT NULL");
 
12106
                        }
 
12107
                }
 
12108
 
 
12109
                /*
 
12110
                 * Add non-inherited CHECK constraints, if any.
 
12111
                 */
 
12112
                for (j = 0; j < tbinfo->ncheck; j++)
 
12113
                {
 
12114
                        ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
 
12115
 
 
12116
                        if (constr->separate || !constr->conislocal)
 
12117
                                continue;
 
12118
 
 
12119
                        if (actual_atts == 0)
 
12120
                                appendPQExpBuffer(q, " (\n    ");
 
12121
                        else
 
12122
                                appendPQExpBuffer(q, ",\n    ");
 
12123
 
 
12124
                        appendPQExpBuffer(q, "CONSTRAINT %s ",
 
12125
                                                          fmtId(constr->dobj.name));
 
12126
                        appendPQExpBuffer(q, "%s", constr->condef);
 
12127
 
 
12128
                        actual_atts++;
 
12129
                }
 
12130
 
 
12131
                if (actual_atts)
 
12132
                        appendPQExpBuffer(q, "\n)");
 
12133
                else if (!(tbinfo->reloftype && !binary_upgrade))
 
12134
                {
 
12135
                        /*
 
12136
                         * We must have a parenthesized attribute list, even though empty,
 
12137
                         * when not using the OF TYPE syntax.
 
12138
                         */
 
12139
                        appendPQExpBuffer(q, " (\n)");
 
12140
                }
 
12141
 
 
12142
                if (numParents > 0 && !binary_upgrade)
 
12143
                {
 
12144
                        appendPQExpBuffer(q, "\nINHERITS (");
 
12145
                        for (k = 0; k < numParents; k++)
 
12146
                        {
 
12147
                                TableInfo  *parentRel = parents[k];
 
12148
 
 
12149
                                if (k > 0)
 
12150
                                        appendPQExpBuffer(q, ", ");
 
12151
                                if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
 
12152
                                        appendPQExpBuffer(q, "%s.",
 
12153
                                                                fmtId(parentRel->dobj.namespace->dobj.name));
 
12154
                                appendPQExpBuffer(q, "%s",
 
12155
                                                                  fmtId(parentRel->dobj.name));
 
12156
                        }
 
12157
                        appendPQExpBuffer(q, ")");
 
12158
                }
 
12159
 
 
12160
                if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
 
12161
                        appendPQExpBuffer(q, "\nSERVER %s", srvname);
 
12162
 
 
12163
                if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
 
12164
                  (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
 
12165
                {
 
12166
                        bool            addcomma = false;
 
12167
 
 
12168
                        appendPQExpBuffer(q, "\nWITH (");
 
12169
                        if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
 
12170
                        {
 
12171
                                addcomma = true;
 
12172
                                appendPQExpBuffer(q, "%s", tbinfo->reloptions);
 
12173
                        }
 
12174
                        if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
 
12175
                        {
 
12176
                                appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
 
12177
                                                                  tbinfo->toast_reloptions);
 
12178
                        }
 
12179
                        appendPQExpBuffer(q, ")");
 
12180
                }
 
12181
 
 
12182
                /* Dump generic options if any */
 
12183
                if (ftoptions && ftoptions[0])
 
12184
                        appendPQExpBuffer(q, "\nOPTIONS (%s)", ftoptions);
 
12185
 
 
12186
                appendPQExpBuffer(q, ";\n");
 
12187
 
 
12188
                /*
 
12189
                 * To create binary-compatible heap files, we have to ensure the same
 
12190
                 * physical column order, including dropped columns, as in the
 
12191
                 * original.  Therefore, we create dropped columns above and drop them
 
12192
                 * here, also updating their attlen/attalign values so that the
 
12193
                 * dropped column can be skipped properly.      (We do not bother with
 
12194
                 * restoring the original attbyval setting.)  Also, inheritance
 
12195
                 * relationships are set up by doing ALTER INHERIT rather than using
 
12196
                 * an INHERITS clause --- the latter would possibly mess up the column
 
12197
                 * order.  That also means we have to take care about setting
 
12198
                 * attislocal correctly, plus fix up any inherited CHECK constraints.
 
12199
                 * Analogously, we set up typed tables using ALTER TABLE / OF here.
 
12200
                 */
 
12201
                if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
 
12202
                {
 
12203
                        for (j = 0; j < tbinfo->numatts; j++)
 
12204
                        {
 
12205
                                if (tbinfo->attisdropped[j])
 
12206
                                {
 
12207
                                        appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
 
12208
                                        appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
 
12209
                                                                          "SET attlen = %d, "
 
12210
                                                                          "attalign = '%c', attbyval = false\n"
 
12211
                                                                          "WHERE attname = ",
 
12212
                                                                          tbinfo->attlen[j],
 
12213
                                                                          tbinfo->attalign[j]);
 
12214
                                        appendStringLiteralAH(q, tbinfo->attnames[j], fout);
 
12215
                                        appendPQExpBuffer(q, "\n  AND attrelid = ");
 
12216
                                        appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
 
12217
                                        appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
 
12218
 
 
12219
                                        appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
 
12220
                                                                          fmtId(tbinfo->dobj.name));
 
12221
                                        appendPQExpBuffer(q, "DROP COLUMN %s;\n",
 
12222
                                                                          fmtId(tbinfo->attnames[j]));
 
12223
                                }
 
12224
                                else if (!tbinfo->attislocal[j])
 
12225
                                {
 
12226
                                        appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
 
12227
                                        appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
 
12228
                                                                          "SET attislocal = false\n"
 
12229
                                                                          "WHERE attname = ");
 
12230
                                        appendStringLiteralAH(q, tbinfo->attnames[j], fout);
 
12231
                                        appendPQExpBuffer(q, "\n  AND attrelid = ");
 
12232
                                        appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
 
12233
                                        appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
 
12234
                                }
 
12235
                        }
 
12236
 
 
12237
                        for (k = 0; k < tbinfo->ncheck; k++)
 
12238
                        {
 
12239
                                ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
 
12240
 
 
12241
                                if (constr->separate || constr->conislocal)
 
12242
                                        continue;
 
12243
 
 
12244
                                appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
 
12245
                                appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
 
12246
                                                                  fmtId(tbinfo->dobj.name));
 
12247
                                appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
 
12248
                                                                  fmtId(constr->dobj.name));
 
12249
                                appendPQExpBuffer(q, "%s;\n", constr->condef);
 
12250
                                appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
 
12251
                                                                  "SET conislocal = false\n"
 
12252
                                                                  "WHERE contype = 'c' AND conname = ");
 
12253
                                appendStringLiteralAH(q, constr->dobj.name, fout);
 
12254
                                appendPQExpBuffer(q, "\n  AND conrelid = ");
 
12255
                                appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
 
12256
                                appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
 
12257
                        }
 
12258
 
 
12259
                        if (numParents > 0)
 
12260
                        {
 
12261
                                appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
 
12262
                                for (k = 0; k < numParents; k++)
 
12263
                                {
 
12264
                                        TableInfo  *parentRel = parents[k];
 
12265
 
 
12266
                                        appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
 
12267
                                                                          fmtId(tbinfo->dobj.name));
 
12268
                                        if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
 
12269
                                                appendPQExpBuffer(q, "%s.",
 
12270
                                                                fmtId(parentRel->dobj.namespace->dobj.name));
 
12271
                                        appendPQExpBuffer(q, "%s;\n",
 
12272
                                                                          fmtId(parentRel->dobj.name));
 
12273
                                }
 
12274
                        }
 
12275
 
 
12276
                        if (tbinfo->reloftype)
 
12277
                        {
 
12278
                                appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
 
12279
                                appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
 
12280
                                                                  fmtId(tbinfo->dobj.name),
 
12281
                                                                  tbinfo->reloftype);
 
12282
                        }
 
12283
 
 
12284
                        appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
 
12285
                        appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
 
12286
                                                          "SET relfrozenxid = '%u'\n"
 
12287
                                                          "WHERE oid = ",
 
12288
                                                          tbinfo->frozenxid);
 
12289
                        appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
 
12290
                        appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
 
12291
 
 
12292
                        if (tbinfo->toast_oid)
 
12293
                        {
 
12294
                                /* We preserve the toast oids, so we can use it during restore */
 
12295
                                appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
 
12296
                                appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
 
12297
                                                                  "SET relfrozenxid = '%u'\n"
 
12298
                                                                  "WHERE oid = '%u';\n",
 
12299
                                                                  tbinfo->toast_frozenxid, tbinfo->toast_oid);
 
12300
                        }
 
12301
                }
 
12302
 
 
12303
                /* Loop dumping statistics and storage statements */
 
12304
                for (j = 0; j < tbinfo->numatts; j++)
 
12305
                {
 
12306
                        /*
 
12307
                         * Dump per-column statistics information. We only issue an ALTER
 
12308
                         * TABLE statement if the attstattarget entry for this column is
 
12309
                         * non-negative (i.e. it's not the default value)
 
12310
                         */
 
12311
                        if (tbinfo->attstattarget[j] >= 0 &&
 
12312
                                !tbinfo->attisdropped[j])
 
12313
                        {
 
12314
                                appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
 
12315
                                                                  fmtId(tbinfo->dobj.name));
 
12316
                                appendPQExpBuffer(q, "ALTER COLUMN %s ",
 
12317
                                                                  fmtId(tbinfo->attnames[j]));
 
12318
                                appendPQExpBuffer(q, "SET STATISTICS %d;\n",
 
12319
                                                                  tbinfo->attstattarget[j]);
 
12320
                        }
 
12321
 
 
12322
                        /*
 
12323
                         * Dump per-column storage information.  The statement is only
 
12324
                         * dumped if the storage has been changed from the type's default.
 
12325
                         */
 
12326
                        if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
 
12327
                        {
 
12328
                                switch (tbinfo->attstorage[j])
 
12329
                                {
 
12330
                                        case 'p':
 
12331
                                                storage = "PLAIN";
 
12332
                                                break;
 
12333
                                        case 'e':
 
12334
                                                storage = "EXTERNAL";
 
12335
                                                break;
 
12336
                                        case 'm':
 
12337
                                                storage = "MAIN";
 
12338
                                                break;
 
12339
                                        case 'x':
 
12340
                                                storage = "EXTENDED";
 
12341
                                                break;
 
12342
                                        default:
 
12343
                                                storage = NULL;
 
12344
                                }
 
12345
 
 
12346
                                /*
 
12347
                                 * Only dump the statement if it's a storage type we recognize
 
12348
                                 */
 
12349
                                if (storage != NULL)
 
12350
                                {
 
12351
                                        appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
 
12352
                                                                          fmtId(tbinfo->dobj.name));
 
12353
                                        appendPQExpBuffer(q, "ALTER COLUMN %s ",
 
12354
                                                                          fmtId(tbinfo->attnames[j]));
 
12355
                                        appendPQExpBuffer(q, "SET STORAGE %s;\n",
 
12356
                                                                          storage);
 
12357
                                }
 
12358
                        }
 
12359
 
 
12360
                        /*
 
12361
                         * Dump per-column attributes.
 
12362
                         */
 
12363
                        if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
 
12364
                        {
 
12365
                                appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
 
12366
                                                                  fmtId(tbinfo->dobj.name));
 
12367
                                appendPQExpBuffer(q, "ALTER COLUMN %s ",
 
12368
                                                                  fmtId(tbinfo->attnames[j]));
 
12369
                                appendPQExpBuffer(q, "SET (%s);\n",
 
12370
                                                                  tbinfo->attoptions[j]);
 
12371
                        }
 
12372
                }
 
12373
        }
 
12374
 
 
12375
        if (binary_upgrade)
 
12376
                binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
 
12377
 
 
12378
        ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 
12379
                                 tbinfo->dobj.name,
 
12380
                                 tbinfo->dobj.namespace->dobj.name,
 
12381
                        (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
 
12382
                                 tbinfo->rolname,
 
12383
                           (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
 
12384
                                 reltypename, SECTION_PRE_DATA,
 
12385
                                 q->data, delq->data, NULL,
 
12386
                                 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
 
12387
                                 NULL, NULL);
 
12388
 
 
12389
 
 
12390
        /* Dump Table Comments */
 
12391
        dumpTableComment(fout, tbinfo, reltypename);
 
12392
 
 
12393
        /* Dump Table Security Labels */
 
12394
        dumpTableSecLabel(fout, tbinfo, reltypename);
 
12395
 
 
12396
        /* Dump comments on inlined table constraints */
 
12397
        for (j = 0; j < tbinfo->ncheck; j++)
 
12398
        {
 
12399
                ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
 
12400
 
 
12401
                if (constr->separate || !constr->conislocal)
 
12402
                        continue;
 
12403
 
 
12404
                dumpTableConstraintComment(fout, constr);
 
12405
        }
 
12406
 
 
12407
        destroyPQExpBuffer(query);
 
12408
        destroyPQExpBuffer(q);
 
12409
        destroyPQExpBuffer(delq);
 
12410
        destroyPQExpBuffer(labelq);
 
12411
}
 
12412
 
 
12413
/*
 
12414
 * dumpAttrDef --- dump an attribute's default-value declaration
 
12415
 */
 
12416
static void
 
12417
dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
 
12418
{
 
12419
        TableInfo  *tbinfo = adinfo->adtable;
 
12420
        int                     adnum = adinfo->adnum;
 
12421
        PQExpBuffer q;
 
12422
        PQExpBuffer delq;
 
12423
 
 
12424
        /* Only print it if "separate" mode is selected */
 
12425
        if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
 
12426
                return;
 
12427
 
 
12428
        /* Don't print inherited defaults, either, except for binary upgrade */
 
12429
        if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
 
12430
                return;
 
12431
 
 
12432
        q = createPQExpBuffer();
 
12433
        delq = createPQExpBuffer();
 
12434
 
 
12435
        appendPQExpBuffer(q, "ALTER TABLE %s ",
 
12436
                                          fmtId(tbinfo->dobj.name));
 
12437
        appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
 
12438
                                          fmtId(tbinfo->attnames[adnum - 1]),
 
12439
                                          adinfo->adef_expr);
 
12440
 
 
12441
        /*
 
12442
         * DROP must be fully qualified in case same name appears in pg_catalog
 
12443
         */
 
12444
        appendPQExpBuffer(delq, "ALTER TABLE %s.",
 
12445
                                          fmtId(tbinfo->dobj.namespace->dobj.name));
 
12446
        appendPQExpBuffer(delq, "%s ",
 
12447
                                          fmtId(tbinfo->dobj.name));
 
12448
        appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
 
12449
                                          fmtId(tbinfo->attnames[adnum - 1]));
 
12450
 
 
12451
        ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
 
12452
                                 tbinfo->attnames[adnum - 1],
 
12453
                                 tbinfo->dobj.namespace->dobj.name,
 
12454
                                 NULL,
 
12455
                                 tbinfo->rolname,
 
12456
                                 false, "DEFAULT", SECTION_PRE_DATA,
 
12457
                                 q->data, delq->data, NULL,
 
12458
                                 adinfo->dobj.dependencies, adinfo->dobj.nDeps,
 
12459
                                 NULL, NULL);
 
12460
 
 
12461
        destroyPQExpBuffer(q);
 
12462
        destroyPQExpBuffer(delq);
 
12463
}
 
12464
 
 
12465
/*
 
12466
 * getAttrName: extract the correct name for an attribute
 
12467
 *
 
12468
 * The array tblInfo->attnames[] only provides names of user attributes;
 
12469
 * if a system attribute number is supplied, we have to fake it.
 
12470
 * We also do a little bit of bounds checking for safety's sake.
 
12471
 */
 
12472
static const char *
 
12473
getAttrName(int attrnum, TableInfo *tblInfo)
 
12474
{
 
12475
        if (attrnum > 0 && attrnum <= tblInfo->numatts)
 
12476
                return tblInfo->attnames[attrnum - 1];
 
12477
        switch (attrnum)
 
12478
        {
 
12479
                case SelfItemPointerAttributeNumber:
 
12480
                        return "ctid";
 
12481
                case ObjectIdAttributeNumber:
 
12482
                        return "oid";
 
12483
                case MinTransactionIdAttributeNumber:
 
12484
                        return "xmin";
 
12485
                case MinCommandIdAttributeNumber:
 
12486
                        return "cmin";
 
12487
                case MaxTransactionIdAttributeNumber:
 
12488
                        return "xmax";
 
12489
                case MaxCommandIdAttributeNumber:
 
12490
                        return "cmax";
 
12491
                case TableOidAttributeNumber:
 
12492
                        return "tableoid";
 
12493
        }
 
12494
        write_msg(NULL, "invalid column number %d for table \"%s\"\n",
 
12495
                          attrnum, tblInfo->dobj.name);
 
12496
        exit_nicely();
 
12497
        return NULL;                            /* keep compiler quiet */
 
12498
}
 
12499
 
 
12500
/*
 
12501
 * dumpIndex
 
12502
 *        write out to fout a user-defined index
 
12503
 */
 
12504
static void
 
12505
dumpIndex(Archive *fout, IndxInfo *indxinfo)
 
12506
{
 
12507
        TableInfo  *tbinfo = indxinfo->indextable;
 
12508
        PQExpBuffer q;
 
12509
        PQExpBuffer delq;
 
12510
        PQExpBuffer labelq;
 
12511
 
 
12512
        if (dataOnly)
 
12513
                return;
 
12514
 
 
12515
        q = createPQExpBuffer();
 
12516
        delq = createPQExpBuffer();
 
12517
        labelq = createPQExpBuffer();
 
12518
 
 
12519
        appendPQExpBuffer(labelq, "INDEX %s",
 
12520
                                          fmtId(indxinfo->dobj.name));
 
12521
 
 
12522
        /*
 
12523
         * If there's an associated constraint, don't dump the index per se, but
 
12524
         * do dump any comment for it.  (This is safe because dependency ordering
 
12525
         * will have ensured the constraint is emitted first.)
 
12526
         */
 
12527
        if (indxinfo->indexconstraint == 0)
 
12528
        {
 
12529
                if (binary_upgrade)
 
12530
                        binary_upgrade_set_pg_class_oids(q, indxinfo->dobj.catId.oid, true);
 
12531
 
 
12532
                /* Plain secondary index */
 
12533
                appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
 
12534
 
 
12535
                /* If the index is clustered, we need to record that. */
 
12536
                if (indxinfo->indisclustered)
 
12537
                {
 
12538
                        appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
 
12539
                                                          fmtId(tbinfo->dobj.name));
 
12540
                        appendPQExpBuffer(q, " ON %s;\n",
 
12541
                                                          fmtId(indxinfo->dobj.name));
 
12542
                }
 
12543
 
 
12544
                /*
 
12545
                 * DROP must be fully qualified in case same name appears in
 
12546
                 * pg_catalog
 
12547
                 */
 
12548
                appendPQExpBuffer(delq, "DROP INDEX %s.",
 
12549
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
12550
                appendPQExpBuffer(delq, "%s;\n",
 
12551
                                                  fmtId(indxinfo->dobj.name));
 
12552
 
 
12553
                ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
 
12554
                                         indxinfo->dobj.name,
 
12555
                                         tbinfo->dobj.namespace->dobj.name,
 
12556
                                         indxinfo->tablespace,
 
12557
                                         tbinfo->rolname, false,
 
12558
                                         "INDEX", SECTION_POST_DATA,
 
12559
                                         q->data, delq->data, NULL,
 
12560
                                         indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
 
12561
                                         NULL, NULL);
 
12562
        }
 
12563
 
 
12564
        /* Dump Index Comments */
 
12565
        dumpComment(fout, labelq->data,
 
12566
                                tbinfo->dobj.namespace->dobj.name,
 
12567
                                tbinfo->rolname,
 
12568
                                indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
 
12569
 
 
12570
        destroyPQExpBuffer(q);
 
12571
        destroyPQExpBuffer(delq);
 
12572
        destroyPQExpBuffer(labelq);
 
12573
}
 
12574
 
 
12575
/*
 
12576
 * dumpConstraint
 
12577
 *        write out to fout a user-defined constraint
 
12578
 */
 
12579
static void
 
12580
dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
 
12581
{
 
12582
        TableInfo  *tbinfo = coninfo->contable;
 
12583
        PQExpBuffer q;
 
12584
        PQExpBuffer delq;
 
12585
 
 
12586
        /* Skip if not to be dumped */
 
12587
        if (!coninfo->dobj.dump || dataOnly)
 
12588
                return;
 
12589
 
 
12590
        q = createPQExpBuffer();
 
12591
        delq = createPQExpBuffer();
 
12592
 
 
12593
        if (coninfo->contype == 'p' ||
 
12594
                coninfo->contype == 'u' ||
 
12595
                coninfo->contype == 'x')
 
12596
        {
 
12597
                /* Index-related constraint */
 
12598
                IndxInfo   *indxinfo;
 
12599
                int                     k;
 
12600
 
 
12601
                indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
 
12602
 
 
12603
                if (indxinfo == NULL)
 
12604
                {
 
12605
                        write_msg(NULL, "missing index for constraint \"%s\"\n",
 
12606
                                          coninfo->dobj.name);
 
12607
                        exit_nicely();
 
12608
                }
 
12609
 
 
12610
                if (binary_upgrade && !coninfo->condef)
 
12611
                        binary_upgrade_set_pg_class_oids(q, indxinfo->dobj.catId.oid, true);
 
12612
 
 
12613
                appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
 
12614
                                                  fmtId(tbinfo->dobj.name));
 
12615
                appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
 
12616
                                                  fmtId(coninfo->dobj.name));
 
12617
 
 
12618
                if (coninfo->condef)
 
12619
                {
 
12620
                        /* pg_get_constraintdef should have provided everything */
 
12621
                        appendPQExpBuffer(q, "%s;\n", coninfo->condef);
 
12622
                }
 
12623
                else
 
12624
                {
 
12625
                        appendPQExpBuffer(q, "%s (",
 
12626
                                                 coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
 
12627
                        for (k = 0; k < indxinfo->indnkeys; k++)
 
12628
                        {
 
12629
                                int                     indkey = (int) indxinfo->indkeys[k];
 
12630
                                const char *attname;
 
12631
 
 
12632
                                if (indkey == InvalidAttrNumber)
 
12633
                                        break;
 
12634
                                attname = getAttrName(indkey, tbinfo);
 
12635
 
 
12636
                                appendPQExpBuffer(q, "%s%s",
 
12637
                                                                  (k == 0) ? "" : ", ",
 
12638
                                                                  fmtId(attname));
 
12639
                        }
 
12640
 
 
12641
                        appendPQExpBuffer(q, ")");
 
12642
 
 
12643
                        if (indxinfo->options && strlen(indxinfo->options) > 0)
 
12644
                                appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
 
12645
 
 
12646
                        if (coninfo->condeferrable)
 
12647
                        {
 
12648
                                appendPQExpBuffer(q, " DEFERRABLE");
 
12649
                                if (coninfo->condeferred)
 
12650
                                        appendPQExpBuffer(q, " INITIALLY DEFERRED");
 
12651
                        }
 
12652
 
 
12653
                        appendPQExpBuffer(q, ";\n");
 
12654
                }
 
12655
 
 
12656
                /* If the index is clustered, we need to record that. */
 
12657
                if (indxinfo->indisclustered)
 
12658
                {
 
12659
                        appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
 
12660
                                                          fmtId(tbinfo->dobj.name));
 
12661
                        appendPQExpBuffer(q, " ON %s;\n",
 
12662
                                                          fmtId(indxinfo->dobj.name));
 
12663
                }
 
12664
 
 
12665
                /*
 
12666
                 * DROP must be fully qualified in case same name appears in
 
12667
                 * pg_catalog
 
12668
                 */
 
12669
                appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
 
12670
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
12671
                appendPQExpBuffer(delq, "%s ",
 
12672
                                                  fmtId(tbinfo->dobj.name));
 
12673
                appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 
12674
                                                  fmtId(coninfo->dobj.name));
 
12675
 
 
12676
                ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 
12677
                                         coninfo->dobj.name,
 
12678
                                         tbinfo->dobj.namespace->dobj.name,
 
12679
                                         indxinfo->tablespace,
 
12680
                                         tbinfo->rolname, false,
 
12681
                                         "CONSTRAINT", SECTION_POST_DATA,
 
12682
                                         q->data, delq->data, NULL,
 
12683
                                         coninfo->dobj.dependencies, coninfo->dobj.nDeps,
 
12684
                                         NULL, NULL);
 
12685
        }
 
12686
        else if (coninfo->contype == 'f')
 
12687
        {
 
12688
                /*
 
12689
                 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
 
12690
                 * current table data is not processed
 
12691
                 */
 
12692
                appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
 
12693
                                                  fmtId(tbinfo->dobj.name));
 
12694
                appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
 
12695
                                                  fmtId(coninfo->dobj.name),
 
12696
                                                  coninfo->condef);
 
12697
 
 
12698
                /*
 
12699
                 * DROP must be fully qualified in case same name appears in
 
12700
                 * pg_catalog
 
12701
                 */
 
12702
                appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
 
12703
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
12704
                appendPQExpBuffer(delq, "%s ",
 
12705
                                                  fmtId(tbinfo->dobj.name));
 
12706
                appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 
12707
                                                  fmtId(coninfo->dobj.name));
 
12708
 
 
12709
                ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 
12710
                                         coninfo->dobj.name,
 
12711
                                         tbinfo->dobj.namespace->dobj.name,
 
12712
                                         NULL,
 
12713
                                         tbinfo->rolname, false,
 
12714
                                         "FK CONSTRAINT", SECTION_POST_DATA,
 
12715
                                         q->data, delq->data, NULL,
 
12716
                                         coninfo->dobj.dependencies, coninfo->dobj.nDeps,
 
12717
                                         NULL, NULL);
 
12718
        }
 
12719
        else if (coninfo->contype == 'c' && tbinfo)
 
12720
        {
 
12721
                /* CHECK constraint on a table */
 
12722
 
 
12723
                /* Ignore if not to be dumped separately */
 
12724
                if (coninfo->separate)
 
12725
                {
 
12726
                        /* not ONLY since we want it to propagate to children */
 
12727
                        appendPQExpBuffer(q, "ALTER TABLE %s\n",
 
12728
                                                          fmtId(tbinfo->dobj.name));
 
12729
                        appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
 
12730
                                                          fmtId(coninfo->dobj.name),
 
12731
                                                          coninfo->condef);
 
12732
 
 
12733
                        /*
 
12734
                         * DROP must be fully qualified in case same name appears in
 
12735
                         * pg_catalog
 
12736
                         */
 
12737
                        appendPQExpBuffer(delq, "ALTER TABLE %s.",
 
12738
                                                          fmtId(tbinfo->dobj.namespace->dobj.name));
 
12739
                        appendPQExpBuffer(delq, "%s ",
 
12740
                                                          fmtId(tbinfo->dobj.name));
 
12741
                        appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 
12742
                                                          fmtId(coninfo->dobj.name));
 
12743
 
 
12744
                        ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 
12745
                                                 coninfo->dobj.name,
 
12746
                                                 tbinfo->dobj.namespace->dobj.name,
 
12747
                                                 NULL,
 
12748
                                                 tbinfo->rolname, false,
 
12749
                                                 "CHECK CONSTRAINT", SECTION_POST_DATA,
 
12750
                                                 q->data, delq->data, NULL,
 
12751
                                                 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
 
12752
                                                 NULL, NULL);
 
12753
                }
 
12754
        }
 
12755
        else if (coninfo->contype == 'c' && tbinfo == NULL)
 
12756
        {
 
12757
                /* CHECK constraint on a domain */
 
12758
                TypeInfo   *tyinfo = coninfo->condomain;
 
12759
 
 
12760
                /* Ignore if not to be dumped separately */
 
12761
                if (coninfo->separate)
 
12762
                {
 
12763
                        appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
 
12764
                                                          fmtId(tyinfo->dobj.name));
 
12765
                        appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
 
12766
                                                          fmtId(coninfo->dobj.name),
 
12767
                                                          coninfo->condef);
 
12768
 
 
12769
                        /*
 
12770
                         * DROP must be fully qualified in case same name appears in
 
12771
                         * pg_catalog
 
12772
                         */
 
12773
                        appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
 
12774
                                                          fmtId(tyinfo->dobj.namespace->dobj.name));
 
12775
                        appendPQExpBuffer(delq, "%s ",
 
12776
                                                          fmtId(tyinfo->dobj.name));
 
12777
                        appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
 
12778
                                                          fmtId(coninfo->dobj.name));
 
12779
 
 
12780
                        ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
 
12781
                                                 coninfo->dobj.name,
 
12782
                                                 tyinfo->dobj.namespace->dobj.name,
 
12783
                                                 NULL,
 
12784
                                                 tyinfo->rolname, false,
 
12785
                                                 "CHECK CONSTRAINT", SECTION_POST_DATA,
 
12786
                                                 q->data, delq->data, NULL,
 
12787
                                                 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
 
12788
                                                 NULL, NULL);
 
12789
                }
 
12790
        }
 
12791
        else
 
12792
        {
 
12793
                write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
 
12794
                exit_nicely();
 
12795
        }
 
12796
 
 
12797
        /* Dump Constraint Comments --- only works for table constraints */
 
12798
        if (tbinfo && coninfo->separate)
 
12799
                dumpTableConstraintComment(fout, coninfo);
 
12800
 
 
12801
        destroyPQExpBuffer(q);
 
12802
        destroyPQExpBuffer(delq);
 
12803
}
 
12804
 
 
12805
/*
 
12806
 * dumpTableConstraintComment --- dump a constraint's comment if any
 
12807
 *
 
12808
 * This is split out because we need the function in two different places
 
12809
 * depending on whether the constraint is dumped as part of CREATE TABLE
 
12810
 * or as a separate ALTER command.
 
12811
 */
 
12812
static void
 
12813
dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
 
12814
{
 
12815
        TableInfo  *tbinfo = coninfo->contable;
 
12816
        PQExpBuffer labelq = createPQExpBuffer();
 
12817
 
 
12818
        appendPQExpBuffer(labelq, "CONSTRAINT %s ",
 
12819
                                          fmtId(coninfo->dobj.name));
 
12820
        appendPQExpBuffer(labelq, "ON %s",
 
12821
                                          fmtId(tbinfo->dobj.name));
 
12822
        dumpComment(fout, labelq->data,
 
12823
                                tbinfo->dobj.namespace->dobj.name,
 
12824
                                tbinfo->rolname,
 
12825
                                coninfo->dobj.catId, 0,
 
12826
                         coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
 
12827
 
 
12828
        destroyPQExpBuffer(labelq);
 
12829
}
 
12830
 
 
12831
/*
 
12832
 * findLastBuiltInOid -
 
12833
 * find the last built in oid
 
12834
 *
 
12835
 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
 
12836
 * pg_database entry for the current database
 
12837
 */
 
12838
static Oid
 
12839
findLastBuiltinOid_V71(const char *dbname)
 
12840
{
 
12841
        PGresult   *res;
 
12842
        int                     ntups;
 
12843
        Oid                     last_oid;
 
12844
        PQExpBuffer query = createPQExpBuffer();
 
12845
 
 
12846
        resetPQExpBuffer(query);
 
12847
        appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
 
12848
        appendStringLiteralAH(query, dbname, g_fout);
 
12849
 
 
12850
        res = PQexec(g_conn, query->data);
 
12851
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
12852
 
 
12853
        ntups = PQntuples(res);
 
12854
        if (ntups < 1)
 
12855
        {
 
12856
                write_msg(NULL, "missing pg_database entry for this database\n");
 
12857
                exit_nicely();
 
12858
        }
 
12859
        if (ntups > 1)
 
12860
        {
 
12861
                write_msg(NULL, "found more than one pg_database entry for this database\n");
 
12862
                exit_nicely();
 
12863
        }
 
12864
        last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
 
12865
        PQclear(res);
 
12866
        destroyPQExpBuffer(query);
 
12867
        return last_oid;
 
12868
}
 
12869
 
 
12870
/*
 
12871
 * findLastBuiltInOid -
 
12872
 * find the last built in oid
 
12873
 *
 
12874
 * For 7.0, we do this by assuming that the last thing that initdb does is to
 
12875
 * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
 
12876
 * initdb won't be changing anymore, it'll do.
 
12877
 */
 
12878
static Oid
 
12879
findLastBuiltinOid_V70(void)
 
12880
{
 
12881
        PGresult   *res;
 
12882
        int                     ntups;
 
12883
        int                     last_oid;
 
12884
 
 
12885
        res = PQexec(g_conn,
 
12886
                                 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
 
12887
        check_sql_result(res, g_conn,
 
12888
                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
 
12889
                                         PGRES_TUPLES_OK);
 
12890
        ntups = PQntuples(res);
 
12891
        if (ntups < 1)
 
12892
        {
 
12893
                write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
 
12894
                exit_nicely();
 
12895
        }
 
12896
        if (ntups > 1)
 
12897
        {
 
12898
                write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
 
12899
                exit_nicely();
 
12900
        }
 
12901
        last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
 
12902
        PQclear(res);
 
12903
        return last_oid;
 
12904
}
 
12905
 
 
12906
static void
 
12907
dumpSequence(Archive *fout, TableInfo *tbinfo)
 
12908
{
 
12909
        PGresult   *res;
 
12910
        char       *startv,
 
12911
                           *last,
 
12912
                           *incby,
 
12913
                           *maxv = NULL,
 
12914
                           *minv = NULL,
 
12915
                           *cache;
 
12916
        char            bufm[100],
 
12917
                                bufx[100];
 
12918
        bool            cycled,
 
12919
                                called;
 
12920
        PQExpBuffer query = createPQExpBuffer();
 
12921
        PQExpBuffer delqry = createPQExpBuffer();
 
12922
        PQExpBuffer labelq = createPQExpBuffer();
 
12923
 
 
12924
        /* Make sure we are in proper schema */
 
12925
        selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
12926
 
 
12927
        snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
 
12928
        snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
 
12929
 
 
12930
        if (g_fout->remoteVersion >= 80400)
 
12931
        {
 
12932
                appendPQExpBuffer(query,
 
12933
                                                  "SELECT sequence_name, "
 
12934
                                                  "start_value, last_value, increment_by, "
 
12935
                                   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
 
12936
                                   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
 
12937
                                                  "     ELSE max_value "
 
12938
                                                  "END AS max_value, "
 
12939
                                        "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
 
12940
                                   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
 
12941
                                                  "     ELSE min_value "
 
12942
                                                  "END AS min_value, "
 
12943
                                                  "cache_value, is_cycled, is_called from %s",
 
12944
                                                  bufx, bufm,
 
12945
                                                  fmtId(tbinfo->dobj.name));
 
12946
        }
 
12947
        else
 
12948
        {
 
12949
                appendPQExpBuffer(query,
 
12950
                                                  "SELECT sequence_name, "
 
12951
                                                  "0 AS start_value, last_value, increment_by, "
 
12952
                                   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
 
12953
                                   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
 
12954
                                                  "     ELSE max_value "
 
12955
                                                  "END AS max_value, "
 
12956
                                        "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
 
12957
                                   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
 
12958
                                                  "     ELSE min_value "
 
12959
                                                  "END AS min_value, "
 
12960
                                                  "cache_value, is_cycled, is_called from %s",
 
12961
                                                  bufx, bufm,
 
12962
                                                  fmtId(tbinfo->dobj.name));
 
12963
        }
 
12964
 
 
12965
        res = PQexec(g_conn, query->data);
 
12966
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
12967
 
 
12968
        if (PQntuples(res) != 1)
 
12969
        {
 
12970
                write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
 
12971
                                                                 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
 
12972
                                                                 PQntuples(res)),
 
12973
                                  tbinfo->dobj.name, PQntuples(res));
 
12974
                exit_nicely();
 
12975
        }
 
12976
 
 
12977
        /* Disable this check: it fails if sequence has been renamed */
 
12978
#ifdef NOT_USED
 
12979
        if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
 
12980
        {
 
12981
                write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
 
12982
                                  tbinfo->dobj.name, PQgetvalue(res, 0, 0));
 
12983
                exit_nicely();
 
12984
        }
 
12985
#endif
 
12986
 
 
12987
        startv = PQgetvalue(res, 0, 1);
 
12988
        last = PQgetvalue(res, 0, 2);
 
12989
        incby = PQgetvalue(res, 0, 3);
 
12990
        if (!PQgetisnull(res, 0, 4))
 
12991
                maxv = PQgetvalue(res, 0, 4);
 
12992
        if (!PQgetisnull(res, 0, 5))
 
12993
                minv = PQgetvalue(res, 0, 5);
 
12994
        cache = PQgetvalue(res, 0, 6);
 
12995
        cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
 
12996
        called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
 
12997
 
 
12998
        /*
 
12999
         * The logic we use for restoring sequences is as follows:
 
13000
         *
 
13001
         * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
 
13002
         * last_val for start if called is false, else use min_val for start_val).
 
13003
         * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
 
13004
         * BY command for it.
 
13005
         *
 
13006
         * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
 
13007
         */
 
13008
        if (!dataOnly)
 
13009
        {
 
13010
                /*
 
13011
                 * DROP must be fully qualified in case same name appears in
 
13012
                 * pg_catalog
 
13013
                 */
 
13014
                appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
 
13015
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
13016
                appendPQExpBuffer(delqry, "%s;\n",
 
13017
                                                  fmtId(tbinfo->dobj.name));
 
13018
 
 
13019
                resetPQExpBuffer(query);
 
13020
 
 
13021
                if (binary_upgrade)
 
13022
                {
 
13023
                        binary_upgrade_set_pg_class_oids(query, tbinfo->dobj.catId.oid, false);
 
13024
                        binary_upgrade_set_type_oids_by_rel_oid(query, tbinfo->dobj.catId.oid);
 
13025
                }
 
13026
 
 
13027
                appendPQExpBuffer(query,
 
13028
                                                  "CREATE SEQUENCE %s\n",
 
13029
                                                  fmtId(tbinfo->dobj.name));
 
13030
 
 
13031
                if (g_fout->remoteVersion >= 80400)
 
13032
                        appendPQExpBuffer(query, "    START WITH %s\n", startv);
 
13033
                else
 
13034
                {
 
13035
                        /*
 
13036
                         * Versions before 8.4 did not remember the true start value.  If
 
13037
                         * is_called is false then the sequence has never been incremented
 
13038
                         * so we can use last_val.      Otherwise punt and let it default.
 
13039
                         */
 
13040
                        if (!called)
 
13041
                                appendPQExpBuffer(query, "    START WITH %s\n", last);
 
13042
                }
 
13043
 
 
13044
                appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
 
13045
 
 
13046
                if (minv)
 
13047
                        appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
 
13048
                else
 
13049
                        appendPQExpBuffer(query, "    NO MINVALUE\n");
 
13050
 
 
13051
                if (maxv)
 
13052
                        appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
 
13053
                else
 
13054
                        appendPQExpBuffer(query, "    NO MAXVALUE\n");
 
13055
 
 
13056
                appendPQExpBuffer(query,
 
13057
                                                  "    CACHE %s%s",
 
13058
                                                  cache, (cycled ? "\n    CYCLE" : ""));
 
13059
 
 
13060
                appendPQExpBuffer(query, ";\n");
 
13061
 
 
13062
                appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
 
13063
 
 
13064
                /* binary_upgrade:      no need to clear TOAST table oid */
 
13065
 
 
13066
                if (binary_upgrade)
 
13067
                        binary_upgrade_extension_member(query, &tbinfo->dobj,
 
13068
                                                                                        labelq->data);
 
13069
 
 
13070
                ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
 
13071
                                         tbinfo->dobj.name,
 
13072
                                         tbinfo->dobj.namespace->dobj.name,
 
13073
                                         NULL,
 
13074
                                         tbinfo->rolname,
 
13075
                                         false, "SEQUENCE", SECTION_PRE_DATA,
 
13076
                                         query->data, delqry->data, NULL,
 
13077
                                         tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
 
13078
                                         NULL, NULL);
 
13079
 
 
13080
                /*
 
13081
                 * If the sequence is owned by a table column, emit the ALTER for it
 
13082
                 * as a separate TOC entry immediately following the sequence's own
 
13083
                 * entry.  It's OK to do this rather than using full sorting logic,
 
13084
                 * because the dependency that tells us it's owned will have forced
 
13085
                 * the table to be created first.  We can't just include the ALTER in
 
13086
                 * the TOC entry because it will fail if we haven't reassigned the
 
13087
                 * sequence owner to match the table's owner.
 
13088
                 *
 
13089
                 * We need not schema-qualify the table reference because both
 
13090
                 * sequence and table must be in the same schema.
 
13091
                 */
 
13092
                if (OidIsValid(tbinfo->owning_tab))
 
13093
                {
 
13094
                        TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
 
13095
 
 
13096
                        if (owning_tab && owning_tab->dobj.dump)
 
13097
                        {
 
13098
                                resetPQExpBuffer(query);
 
13099
                                appendPQExpBuffer(query, "ALTER SEQUENCE %s",
 
13100
                                                                  fmtId(tbinfo->dobj.name));
 
13101
                                appendPQExpBuffer(query, " OWNED BY %s",
 
13102
                                                                  fmtId(owning_tab->dobj.name));
 
13103
                                appendPQExpBuffer(query, ".%s;\n",
 
13104
                                                fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
 
13105
 
 
13106
                                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
13107
                                                         tbinfo->dobj.name,
 
13108
                                                         tbinfo->dobj.namespace->dobj.name,
 
13109
                                                         NULL,
 
13110
                                                         tbinfo->rolname,
 
13111
                                                         false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
 
13112
                                                         query->data, "", NULL,
 
13113
                                                         &(tbinfo->dobj.dumpId), 1,
 
13114
                                                         NULL, NULL);
 
13115
                        }
 
13116
                }
 
13117
 
 
13118
                /* Dump Sequence Comments and Security Labels */
 
13119
                dumpComment(fout, labelq->data,
 
13120
                                        tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 
13121
                                        tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
13122
                dumpSecLabel(fout, labelq->data,
 
13123
                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 
13124
                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
13125
        }
 
13126
 
 
13127
        if (!schemaOnly)
 
13128
        {
 
13129
                resetPQExpBuffer(query);
 
13130
                appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
 
13131
                appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
 
13132
                appendPQExpBuffer(query, ", %s, %s);\n",
 
13133
                                                  last, (called ? "true" : "false"));
 
13134
 
 
13135
                ArchiveEntry(fout, nilCatalogId, createDumpId(),
 
13136
                                         tbinfo->dobj.name,
 
13137
                                         tbinfo->dobj.namespace->dobj.name,
 
13138
                                         NULL,
 
13139
                                         tbinfo->rolname,
 
13140
                                         false, "SEQUENCE SET", SECTION_PRE_DATA,
 
13141
                                         query->data, "", NULL,
 
13142
                                         &(tbinfo->dobj.dumpId), 1,
 
13143
                                         NULL, NULL);
 
13144
        }
 
13145
 
 
13146
        PQclear(res);
 
13147
 
 
13148
        destroyPQExpBuffer(query);
 
13149
        destroyPQExpBuffer(delqry);
 
13150
        destroyPQExpBuffer(labelq);
 
13151
}
 
13152
 
 
13153
static void
 
13154
dumpTrigger(Archive *fout, TriggerInfo *tginfo)
 
13155
{
 
13156
        TableInfo  *tbinfo = tginfo->tgtable;
 
13157
        PQExpBuffer query;
 
13158
        PQExpBuffer delqry;
 
13159
        PQExpBuffer labelq;
 
13160
        char       *tgargs;
 
13161
        size_t          lentgargs;
 
13162
        const char *p;
 
13163
        int                     findx;
 
13164
 
 
13165
        if (dataOnly)
 
13166
                return;
 
13167
 
 
13168
        query = createPQExpBuffer();
 
13169
        delqry = createPQExpBuffer();
 
13170
        labelq = createPQExpBuffer();
 
13171
 
 
13172
        /*
 
13173
         * DROP must be fully qualified in case same name appears in pg_catalog
 
13174
         */
 
13175
        appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
 
13176
                                          fmtId(tginfo->dobj.name));
 
13177
        appendPQExpBuffer(delqry, "ON %s.",
 
13178
                                          fmtId(tbinfo->dobj.namespace->dobj.name));
 
13179
        appendPQExpBuffer(delqry, "%s;\n",
 
13180
                                          fmtId(tbinfo->dobj.name));
 
13181
 
 
13182
        if (tginfo->tgdef)
 
13183
        {
 
13184
                appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
 
13185
        }
 
13186
        else
 
13187
        {
 
13188
                if (tginfo->tgisconstraint)
 
13189
                {
 
13190
                        appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
 
13191
                        appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
 
13192
                }
 
13193
                else
 
13194
                {
 
13195
                        appendPQExpBuffer(query, "CREATE TRIGGER ");
 
13196
                        appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
 
13197
                }
 
13198
                appendPQExpBuffer(query, "\n    ");
 
13199
 
 
13200
                /* Trigger type */
 
13201
                if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
 
13202
                        appendPQExpBuffer(query, "BEFORE");
 
13203
                else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
 
13204
                        appendPQExpBuffer(query, "AFTER");
 
13205
                else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
 
13206
                        appendPQExpBuffer(query, "INSTEAD OF");
 
13207
                else
 
13208
                {
 
13209
                        write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
 
13210
                        exit_nicely();
 
13211
                }
 
13212
 
 
13213
                findx = 0;
 
13214
                if (TRIGGER_FOR_INSERT(tginfo->tgtype))
 
13215
                {
 
13216
                        appendPQExpBuffer(query, " INSERT");
 
13217
                        findx++;
 
13218
                }
 
13219
                if (TRIGGER_FOR_DELETE(tginfo->tgtype))
 
13220
                {
 
13221
                        if (findx > 0)
 
13222
                                appendPQExpBuffer(query, " OR DELETE");
 
13223
                        else
 
13224
                                appendPQExpBuffer(query, " DELETE");
 
13225
                        findx++;
 
13226
                }
 
13227
                if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
 
13228
                {
 
13229
                        if (findx > 0)
 
13230
                                appendPQExpBuffer(query, " OR UPDATE");
 
13231
                        else
 
13232
                                appendPQExpBuffer(query, " UPDATE");
 
13233
                        findx++;
 
13234
                }
 
13235
                if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
 
13236
                {
 
13237
                        if (findx > 0)
 
13238
                                appendPQExpBuffer(query, " OR TRUNCATE");
 
13239
                        else
 
13240
                                appendPQExpBuffer(query, " TRUNCATE");
 
13241
                        findx++;
 
13242
                }
 
13243
                appendPQExpBuffer(query, " ON %s\n",
 
13244
                                                  fmtId(tbinfo->dobj.name));
 
13245
 
 
13246
                if (tginfo->tgisconstraint)
 
13247
                {
 
13248
                        if (OidIsValid(tginfo->tgconstrrelid))
 
13249
                        {
 
13250
                                /* If we are using regclass, name is already quoted */
 
13251
                                if (g_fout->remoteVersion >= 70300)
 
13252
                                        appendPQExpBuffer(query, "    FROM %s\n    ",
 
13253
                                                                          tginfo->tgconstrrelname);
 
13254
                                else
 
13255
                                        appendPQExpBuffer(query, "    FROM %s\n    ",
 
13256
                                                                          fmtId(tginfo->tgconstrrelname));
 
13257
                        }
 
13258
                        if (!tginfo->tgdeferrable)
 
13259
                                appendPQExpBuffer(query, "NOT ");
 
13260
                        appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
 
13261
                        if (tginfo->tginitdeferred)
 
13262
                                appendPQExpBuffer(query, "DEFERRED\n");
 
13263
                        else
 
13264
                                appendPQExpBuffer(query, "IMMEDIATE\n");
 
13265
                }
 
13266
 
 
13267
                if (TRIGGER_FOR_ROW(tginfo->tgtype))
 
13268
                        appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
 
13269
                else
 
13270
                        appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
 
13271
 
 
13272
                /* In 7.3, result of regproc is already quoted */
 
13273
                if (g_fout->remoteVersion >= 70300)
 
13274
                        appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
 
13275
                                                          tginfo->tgfname);
 
13276
                else
 
13277
                        appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
 
13278
                                                          fmtId(tginfo->tgfname));
 
13279
 
 
13280
                tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
 
13281
                                                                                  &lentgargs);
 
13282
                p = tgargs;
 
13283
                for (findx = 0; findx < tginfo->tgnargs; findx++)
 
13284
                {
 
13285
                        /* find the embedded null that terminates this trigger argument */
 
13286
                        size_t          tlen = strlen(p);
 
13287
 
 
13288
                        if (p + tlen >= tgargs + lentgargs)
 
13289
                        {
 
13290
                                /* hm, not found before end of bytea value... */
 
13291
                                write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
 
13292
                                                  tginfo->tgargs,
 
13293
                                                  tginfo->dobj.name,
 
13294
                                                  tbinfo->dobj.name);
 
13295
                                exit_nicely();
 
13296
                        }
 
13297
 
 
13298
                        if (findx > 0)
 
13299
                                appendPQExpBuffer(query, ", ");
 
13300
                        appendStringLiteralAH(query, p, fout);
 
13301
                        p += tlen + 1;
 
13302
                }
 
13303
                free(tgargs);
 
13304
                appendPQExpBuffer(query, ");\n");
 
13305
        }
 
13306
 
 
13307
        if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
 
13308
        {
 
13309
                appendPQExpBuffer(query, "\nALTER TABLE %s ",
 
13310
                                                  fmtId(tbinfo->dobj.name));
 
13311
                switch (tginfo->tgenabled)
 
13312
                {
 
13313
                        case 'D':
 
13314
                        case 'f':
 
13315
                                appendPQExpBuffer(query, "DISABLE");
 
13316
                                break;
 
13317
                        case 'A':
 
13318
                                appendPQExpBuffer(query, "ENABLE ALWAYS");
 
13319
                                break;
 
13320
                        case 'R':
 
13321
                                appendPQExpBuffer(query, "ENABLE REPLICA");
 
13322
                                break;
 
13323
                        default:
 
13324
                                appendPQExpBuffer(query, "ENABLE");
 
13325
                                break;
 
13326
                }
 
13327
                appendPQExpBuffer(query, " TRIGGER %s;\n",
 
13328
                                                  fmtId(tginfo->dobj.name));
 
13329
        }
 
13330
 
 
13331
        appendPQExpBuffer(labelq, "TRIGGER %s ",
 
13332
                                          fmtId(tginfo->dobj.name));
 
13333
        appendPQExpBuffer(labelq, "ON %s",
 
13334
                                          fmtId(tbinfo->dobj.name));
 
13335
 
 
13336
        ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
 
13337
                                 tginfo->dobj.name,
 
13338
                                 tbinfo->dobj.namespace->dobj.name,
 
13339
                                 NULL,
 
13340
                                 tbinfo->rolname, false,
 
13341
                                 "TRIGGER", SECTION_POST_DATA,
 
13342
                                 query->data, delqry->data, NULL,
 
13343
                                 tginfo->dobj.dependencies, tginfo->dobj.nDeps,
 
13344
                                 NULL, NULL);
 
13345
 
 
13346
        dumpComment(fout, labelq->data,
 
13347
                                tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 
13348
                                tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
 
13349
 
 
13350
        destroyPQExpBuffer(query);
 
13351
        destroyPQExpBuffer(delqry);
 
13352
        destroyPQExpBuffer(labelq);
 
13353
}
 
13354
 
 
13355
/*
 
13356
 * dumpRule
 
13357
 *              Dump a rule
 
13358
 */
 
13359
static void
 
13360
dumpRule(Archive *fout, RuleInfo *rinfo)
 
13361
{
 
13362
        TableInfo  *tbinfo = rinfo->ruletable;
 
13363
        PQExpBuffer query;
 
13364
        PQExpBuffer cmd;
 
13365
        PQExpBuffer delcmd;
 
13366
        PQExpBuffer labelq;
 
13367
        PGresult   *res;
 
13368
 
 
13369
        /* Skip if not to be dumped */
 
13370
        if (!rinfo->dobj.dump || dataOnly)
 
13371
                return;
 
13372
 
 
13373
        /*
 
13374
         * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
 
13375
         * we do not want to dump it as a separate object.
 
13376
         */
 
13377
        if (!rinfo->separate)
 
13378
                return;
 
13379
 
 
13380
        /*
 
13381
         * Make sure we are in proper schema.
 
13382
         */
 
13383
        selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
 
13384
 
 
13385
        query = createPQExpBuffer();
 
13386
        cmd = createPQExpBuffer();
 
13387
        delcmd = createPQExpBuffer();
 
13388
        labelq = createPQExpBuffer();
 
13389
 
 
13390
        if (g_fout->remoteVersion >= 70300)
 
13391
        {
 
13392
                appendPQExpBuffer(query,
 
13393
                                                  "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
 
13394
                                                  rinfo->dobj.catId.oid);
 
13395
        }
 
13396
        else
 
13397
        {
 
13398
                /* Rule name was unique before 7.3 ... */
 
13399
                appendPQExpBuffer(query,
 
13400
                                                  "SELECT pg_get_ruledef('%s') AS definition",
 
13401
                                                  rinfo->dobj.name);
 
13402
        }
 
13403
 
 
13404
        res = PQexec(g_conn, query->data);
 
13405
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
13406
 
 
13407
        if (PQntuples(res) != 1)
 
13408
        {
 
13409
                write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
 
13410
                                  rinfo->dobj.name, tbinfo->dobj.name);
 
13411
                exit_nicely();
 
13412
        }
 
13413
 
 
13414
        printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
 
13415
 
 
13416
        /*
 
13417
         * Add the command to alter the rules replication firing semantics if it
 
13418
         * differs from the default.
 
13419
         */
 
13420
        if (rinfo->ev_enabled != 'O')
 
13421
        {
 
13422
                appendPQExpBuffer(cmd, "ALTER TABLE %s.",
 
13423
                                                  fmtId(tbinfo->dobj.namespace->dobj.name));
 
13424
                appendPQExpBuffer(cmd, "%s ",
 
13425
                                                  fmtId(tbinfo->dobj.name));
 
13426
                switch (rinfo->ev_enabled)
 
13427
                {
 
13428
                        case 'A':
 
13429
                                appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
 
13430
                                                                  fmtId(rinfo->dobj.name));
 
13431
                                break;
 
13432
                        case 'R':
 
13433
                                appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
 
13434
                                                                  fmtId(rinfo->dobj.name));
 
13435
                                break;
 
13436
                        case 'D':
 
13437
                                appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
 
13438
                                                                  fmtId(rinfo->dobj.name));
 
13439
                                break;
 
13440
                }
 
13441
        }
 
13442
 
 
13443
        /*
 
13444
         * DROP must be fully qualified in case same name appears in pg_catalog
 
13445
         */
 
13446
        appendPQExpBuffer(delcmd, "DROP RULE %s ",
 
13447
                                          fmtId(rinfo->dobj.name));
 
13448
        appendPQExpBuffer(delcmd, "ON %s.",
 
13449
                                          fmtId(tbinfo->dobj.namespace->dobj.name));
 
13450
        appendPQExpBuffer(delcmd, "%s;\n",
 
13451
                                          fmtId(tbinfo->dobj.name));
 
13452
 
 
13453
        appendPQExpBuffer(labelq, "RULE %s",
 
13454
                                          fmtId(rinfo->dobj.name));
 
13455
        appendPQExpBuffer(labelq, " ON %s",
 
13456
                                          fmtId(tbinfo->dobj.name));
 
13457
 
 
13458
        ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
 
13459
                                 rinfo->dobj.name,
 
13460
                                 tbinfo->dobj.namespace->dobj.name,
 
13461
                                 NULL,
 
13462
                                 tbinfo->rolname, false,
 
13463
                                 "RULE", SECTION_POST_DATA,
 
13464
                                 cmd->data, delcmd->data, NULL,
 
13465
                                 rinfo->dobj.dependencies, rinfo->dobj.nDeps,
 
13466
                                 NULL, NULL);
 
13467
 
 
13468
        /* Dump rule comments */
 
13469
        dumpComment(fout, labelq->data,
 
13470
                                tbinfo->dobj.namespace->dobj.name,
 
13471
                                tbinfo->rolname,
 
13472
                                rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
 
13473
 
 
13474
        PQclear(res);
 
13475
 
 
13476
        destroyPQExpBuffer(query);
 
13477
        destroyPQExpBuffer(cmd);
 
13478
        destroyPQExpBuffer(delcmd);
 
13479
        destroyPQExpBuffer(labelq);
 
13480
}
 
13481
 
 
13482
/*
 
13483
 * getExtensionMembership --- obtain extension membership data
 
13484
 */
 
13485
void
 
13486
getExtensionMembership(ExtensionInfo extinfo[], int numExtensions)
 
13487
{
 
13488
        PQExpBuffer query;
 
13489
        PGresult   *res;
 
13490
        int                     ntups,
 
13491
                                i;
 
13492
        int                     i_classid,
 
13493
                                i_objid,
 
13494
                                i_refclassid,
 
13495
                                i_refobjid;
 
13496
        DumpableObject *dobj,
 
13497
                           *refdobj;
 
13498
 
 
13499
        /* Nothing to do if no extensions */
 
13500
        if (numExtensions == 0)
 
13501
                return;
 
13502
 
 
13503
        /* Make sure we are in proper schema */
 
13504
        selectSourceSchema("pg_catalog");
 
13505
 
 
13506
        query = createPQExpBuffer();
 
13507
 
 
13508
        /* refclassid constraint is redundant but may speed the search */
 
13509
        appendPQExpBuffer(query, "SELECT "
 
13510
                                          "classid, objid, refclassid, refobjid "
 
13511
                                          "FROM pg_depend "
 
13512
                                          "WHERE refclassid = 'pg_extension'::regclass "
 
13513
                                          "AND deptype = 'e' "
 
13514
                                          "ORDER BY 3,4");
 
13515
 
 
13516
        res = PQexec(g_conn, query->data);
 
13517
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
13518
 
 
13519
        ntups = PQntuples(res);
 
13520
 
 
13521
        i_classid = PQfnumber(res, "classid");
 
13522
        i_objid = PQfnumber(res, "objid");
 
13523
        i_refclassid = PQfnumber(res, "refclassid");
 
13524
        i_refobjid = PQfnumber(res, "refobjid");
 
13525
 
 
13526
        /*
 
13527
         * Since we ordered the SELECT by referenced ID, we can expect that
 
13528
         * multiple entries for the same extension will appear together; this
 
13529
         * saves on searches.
 
13530
         */
 
13531
        refdobj = NULL;
 
13532
 
 
13533
        for (i = 0; i < ntups; i++)
 
13534
        {
 
13535
                CatalogId       objId;
 
13536
                CatalogId       refobjId;
 
13537
 
 
13538
                objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
 
13539
                objId.oid = atooid(PQgetvalue(res, i, i_objid));
 
13540
                refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
 
13541
                refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
 
13542
 
 
13543
                if (refdobj == NULL ||
 
13544
                        refdobj->catId.tableoid != refobjId.tableoid ||
 
13545
                        refdobj->catId.oid != refobjId.oid)
 
13546
                        refdobj = findObjectByCatalogId(refobjId);
 
13547
 
 
13548
                /*
 
13549
                 * Failure to find objects mentioned in pg_depend is not unexpected,
 
13550
                 * since for example we don't collect info about TOAST tables.
 
13551
                 */
 
13552
                if (refdobj == NULL)
 
13553
                {
 
13554
#ifdef NOT_USED
 
13555
                        fprintf(stderr, "no referenced object %u %u\n",
 
13556
                                        refobjId.tableoid, refobjId.oid);
 
13557
#endif
 
13558
                        continue;
 
13559
                }
 
13560
 
 
13561
                dobj = findObjectByCatalogId(objId);
 
13562
 
 
13563
                if (dobj == NULL)
 
13564
                {
 
13565
#ifdef NOT_USED
 
13566
                        fprintf(stderr, "no referencing object %u %u\n",
 
13567
                                        objId.tableoid, objId.oid);
 
13568
#endif
 
13569
                        continue;
 
13570
                }
 
13571
 
 
13572
                /* Record dependency so that getDependencies needn't repeat this */
 
13573
                addObjectDependency(dobj, refdobj->dumpId);
 
13574
 
 
13575
                dobj->ext_member = true;
 
13576
 
 
13577
                /*
 
13578
                 * Normally, mark the member object as not to be dumped.  But in
 
13579
                 * binary upgrades, we still dump the members individually, since the
 
13580
                 * idea is to exactly reproduce the database contents rather than
 
13581
                 * replace the extension contents with something different.
 
13582
                 */
 
13583
                if (!binary_upgrade)
 
13584
                        dobj->dump = false;
 
13585
                else
 
13586
                        dobj->dump = refdobj->dump;
 
13587
        }
 
13588
 
 
13589
        PQclear(res);
 
13590
 
 
13591
        /*
 
13592
         * Now identify extension configuration tables and create TableDataInfo
 
13593
         * objects for them, ensuring their data will be dumped even though the
 
13594
         * tables themselves won't be.
 
13595
         *
 
13596
         * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
 
13597
         * user data in a configuration table is treated like schema data. This
 
13598
         * seems appropriate since system data in a config table would get
 
13599
         * reloaded by CREATE EXTENSION.
 
13600
         */
 
13601
        for (i = 0; i < numExtensions; i++)
 
13602
        {
 
13603
                char       *extconfig = extinfo[i].extconfig;
 
13604
                char       *extcondition = extinfo[i].extcondition;
 
13605
                char      **extconfigarray = NULL;
 
13606
                char      **extconditionarray = NULL;
 
13607
                int                     nconfigitems;
 
13608
                int                     nconditionitems;
 
13609
 
 
13610
                if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
 
13611
                  parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
 
13612
                        nconfigitems == nconditionitems)
 
13613
                {
 
13614
                        int                     j;
 
13615
 
 
13616
                        for (j = 0; j < nconfigitems; j++)
 
13617
                        {
 
13618
                                TableInfo  *configtbl;
 
13619
 
 
13620
                                configtbl = findTableByOid(atooid(extconfigarray[j]));
 
13621
                                if (configtbl && configtbl->dataObj == NULL)
 
13622
                                {
 
13623
                                        /*
 
13624
                                         * Note: config tables are dumped without OIDs regardless
 
13625
                                         * of the --oids setting.  This is because row filtering
 
13626
                                         * conditions aren't compatible with dumping OIDs.
 
13627
                                         */
 
13628
                                        makeTableDataInfo(configtbl, false);
 
13629
                                        if (strlen(extconditionarray[j]) > 0)
 
13630
                                                configtbl->dataObj->filtercond = strdup(extconditionarray[j]);
 
13631
                                }
 
13632
                        }
 
13633
                }
 
13634
                if (extconfigarray)
 
13635
                        free(extconfigarray);
 
13636
                if (extconditionarray)
 
13637
                        free(extconditionarray);
 
13638
        }
 
13639
 
 
13640
        destroyPQExpBuffer(query);
 
13641
}
 
13642
 
 
13643
/*
 
13644
 * getDependencies --- obtain available dependency data
 
13645
 */
 
13646
static void
 
13647
getDependencies(void)
 
13648
{
 
13649
        PQExpBuffer query;
 
13650
        PGresult   *res;
 
13651
        int                     ntups,
 
13652
                                i;
 
13653
        int                     i_classid,
 
13654
                                i_objid,
 
13655
                                i_refclassid,
 
13656
                                i_refobjid,
 
13657
                                i_deptype;
 
13658
        DumpableObject *dobj,
 
13659
                           *refdobj;
 
13660
 
 
13661
        /* No dependency info available before 7.3 */
 
13662
        if (g_fout->remoteVersion < 70300)
 
13663
                return;
 
13664
 
 
13665
        if (g_verbose)
 
13666
                write_msg(NULL, "reading dependency data\n");
 
13667
 
 
13668
        /* Make sure we are in proper schema */
 
13669
        selectSourceSchema("pg_catalog");
 
13670
 
 
13671
        query = createPQExpBuffer();
 
13672
 
 
13673
        /*
 
13674
         * PIN dependencies aren't interesting, and EXTENSION dependencies were
 
13675
         * already processed by getExtensionMembership.
 
13676
         */
 
13677
        appendPQExpBuffer(query, "SELECT "
 
13678
                                          "classid, objid, refclassid, refobjid, deptype "
 
13679
                                          "FROM pg_depend "
 
13680
                                          "WHERE deptype != 'p' AND deptype != 'e' "
 
13681
                                          "ORDER BY 1,2");
 
13682
 
 
13683
        res = PQexec(g_conn, query->data);
 
13684
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
13685
 
 
13686
        ntups = PQntuples(res);
 
13687
 
 
13688
        i_classid = PQfnumber(res, "classid");
 
13689
        i_objid = PQfnumber(res, "objid");
 
13690
        i_refclassid = PQfnumber(res, "refclassid");
 
13691
        i_refobjid = PQfnumber(res, "refobjid");
 
13692
        i_deptype = PQfnumber(res, "deptype");
 
13693
 
 
13694
        /*
 
13695
         * Since we ordered the SELECT by referencing ID, we can expect that
 
13696
         * multiple entries for the same object will appear together; this saves
 
13697
         * on searches.
 
13698
         */
 
13699
        dobj = NULL;
 
13700
 
 
13701
        for (i = 0; i < ntups; i++)
 
13702
        {
 
13703
                CatalogId       objId;
 
13704
                CatalogId       refobjId;
 
13705
                char            deptype;
 
13706
 
 
13707
                objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
 
13708
                objId.oid = atooid(PQgetvalue(res, i, i_objid));
 
13709
                refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
 
13710
                refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
 
13711
                deptype = *(PQgetvalue(res, i, i_deptype));
 
13712
 
 
13713
                if (dobj == NULL ||
 
13714
                        dobj->catId.tableoid != objId.tableoid ||
 
13715
                        dobj->catId.oid != objId.oid)
 
13716
                        dobj = findObjectByCatalogId(objId);
 
13717
 
 
13718
                /*
 
13719
                 * Failure to find objects mentioned in pg_depend is not unexpected,
 
13720
                 * since for example we don't collect info about TOAST tables.
 
13721
                 */
 
13722
                if (dobj == NULL)
 
13723
                {
 
13724
#ifdef NOT_USED
 
13725
                        fprintf(stderr, "no referencing object %u %u\n",
 
13726
                                        objId.tableoid, objId.oid);
 
13727
#endif
 
13728
                        continue;
 
13729
                }
 
13730
 
 
13731
                refdobj = findObjectByCatalogId(refobjId);
 
13732
 
 
13733
                if (refdobj == NULL)
 
13734
                {
 
13735
#ifdef NOT_USED
 
13736
                        fprintf(stderr, "no referenced object %u %u\n",
 
13737
                                        refobjId.tableoid, refobjId.oid);
 
13738
#endif
 
13739
                        continue;
 
13740
                }
 
13741
 
 
13742
                /*
 
13743
                 * Ordinarily, table rowtypes have implicit dependencies on their
 
13744
                 * tables.      However, for a composite type the implicit dependency goes
 
13745
                 * the other way in pg_depend; which is the right thing for DROP but
 
13746
                 * it doesn't produce the dependency ordering we need. So in that one
 
13747
                 * case, we reverse the direction of the dependency.
 
13748
                 */
 
13749
                if (deptype == 'i' &&
 
13750
                        dobj->objType == DO_TABLE &&
 
13751
                        refdobj->objType == DO_TYPE)
 
13752
                        addObjectDependency(refdobj, dobj->dumpId);
 
13753
                else
 
13754
                        /* normal case */
 
13755
                        addObjectDependency(dobj, refdobj->dumpId);
 
13756
        }
 
13757
 
 
13758
        PQclear(res);
 
13759
 
 
13760
        destroyPQExpBuffer(query);
 
13761
}
 
13762
 
 
13763
 
 
13764
/*
 
13765
 * selectSourceSchema - make the specified schema the active search path
 
13766
 * in the source database.
 
13767
 *
 
13768
 * NB: pg_catalog is explicitly searched after the specified schema;
 
13769
 * so user names are only qualified if they are cross-schema references,
 
13770
 * and system names are only qualified if they conflict with a user name
 
13771
 * in the current schema.
 
13772
 *
 
13773
 * Whenever the selected schema is not pg_catalog, be careful to qualify
 
13774
 * references to system catalogs and types in our emitted commands!
 
13775
 */
 
13776
static void
 
13777
selectSourceSchema(const char *schemaName)
 
13778
{
 
13779
        static char *curSchemaName = NULL;
 
13780
        PQExpBuffer query;
 
13781
 
 
13782
        /* Not relevant if fetching from pre-7.3 DB */
 
13783
        if (g_fout->remoteVersion < 70300)
 
13784
                return;
 
13785
        /* Ignore null schema names */
 
13786
        if (schemaName == NULL || *schemaName == '\0')
 
13787
                return;
 
13788
        /* Optimize away repeated selection of same schema */
 
13789
        if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
 
13790
                return;
 
13791
 
 
13792
        query = createPQExpBuffer();
 
13793
        appendPQExpBuffer(query, "SET search_path = %s",
 
13794
                                          fmtId(schemaName));
 
13795
        if (strcmp(schemaName, "pg_catalog") != 0)
 
13796
                appendPQExpBuffer(query, ", pg_catalog");
 
13797
 
 
13798
        do_sql_command(g_conn, query->data);
 
13799
 
 
13800
        destroyPQExpBuffer(query);
 
13801
        if (curSchemaName)
 
13802
                free(curSchemaName);
 
13803
        curSchemaName = strdup(schemaName);
 
13804
}
 
13805
 
 
13806
/*
 
13807
 * getFormattedTypeName - retrieve a nicely-formatted type name for the
 
13808
 * given type name.
 
13809
 *
 
13810
 * NB: in 7.3 and up the result may depend on the currently-selected
 
13811
 * schema; this is why we don't try to cache the names.
 
13812
 */
 
13813
static char *
 
13814
getFormattedTypeName(Oid oid, OidOptions opts)
 
13815
{
 
13816
        char       *result;
 
13817
        PQExpBuffer query;
 
13818
        PGresult   *res;
 
13819
        int                     ntups;
 
13820
 
 
13821
        if (oid == 0)
 
13822
        {
 
13823
                if ((opts & zeroAsOpaque) != 0)
 
13824
                        return strdup(g_opaque_type);
 
13825
                else if ((opts & zeroAsAny) != 0)
 
13826
                        return strdup("'any'");
 
13827
                else if ((opts & zeroAsStar) != 0)
 
13828
                        return strdup("*");
 
13829
                else if ((opts & zeroAsNone) != 0)
 
13830
                        return strdup("NONE");
 
13831
        }
 
13832
 
 
13833
        query = createPQExpBuffer();
 
13834
        if (g_fout->remoteVersion >= 70300)
 
13835
        {
 
13836
                appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
 
13837
                                                  oid);
 
13838
        }
 
13839
        else if (g_fout->remoteVersion >= 70100)
 
13840
        {
 
13841
                appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
 
13842
                                                  oid);
 
13843
        }
 
13844
        else
 
13845
        {
 
13846
                appendPQExpBuffer(query, "SELECT typname "
 
13847
                                                  "FROM pg_type "
 
13848
                                                  "WHERE oid = '%u'::oid",
 
13849
                                                  oid);
 
13850
        }
 
13851
 
 
13852
        res = PQexec(g_conn, query->data);
 
13853
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
 
13854
 
 
13855
        /* Expecting a single result only */
 
13856
        ntups = PQntuples(res);
 
13857
        if (ntups != 1)
 
13858
        {
 
13859
                write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
 
13860
                                                           "query returned %d rows instead of one: %s\n",
 
13861
                                                                 ntups),
 
13862
                                  ntups, query->data);
 
13863
                exit_nicely();
 
13864
        }
 
13865
 
 
13866
        if (g_fout->remoteVersion >= 70100)
 
13867
        {
 
13868
                /* already quoted */
 
13869
                result = strdup(PQgetvalue(res, 0, 0));
 
13870
        }
 
13871
        else
 
13872
        {
 
13873
                /* may need to quote it */
 
13874
                result = strdup(fmtId(PQgetvalue(res, 0, 0)));
 
13875
        }
 
13876
 
 
13877
        PQclear(res);
 
13878
        destroyPQExpBuffer(query);
 
13879
 
 
13880
        return result;
 
13881
}
 
13882
 
 
13883
/*
 
13884
 * myFormatType --- local implementation of format_type for use with 7.0.
 
13885
 */
 
13886
static char *
 
13887
myFormatType(const char *typname, int32 typmod)
 
13888
{
 
13889
        char       *result;
 
13890
        bool            isarray = false;
 
13891
        PQExpBuffer buf = createPQExpBuffer();
 
13892
 
 
13893
        /* Handle array types */
 
13894
        if (typname[0] == '_')
 
13895
        {
 
13896
                isarray = true;
 
13897
                typname++;
 
13898
        }
 
13899
 
 
13900
        /* Show lengths on bpchar and varchar */
 
13901
        if (!strcmp(typname, "bpchar"))
 
13902
        {
 
13903
                int                     len = (typmod - VARHDRSZ);
 
13904
 
 
13905
                appendPQExpBuffer(buf, "character");
 
13906
                if (len > 1)
 
13907
                        appendPQExpBuffer(buf, "(%d)",
 
13908
                                                          typmod - VARHDRSZ);
 
13909
        }
 
13910
        else if (!strcmp(typname, "varchar"))
 
13911
        {
 
13912
                appendPQExpBuffer(buf, "character varying");
 
13913
                if (typmod != -1)
 
13914
                        appendPQExpBuffer(buf, "(%d)",
 
13915
                                                          typmod - VARHDRSZ);
 
13916
        }
 
13917
        else if (!strcmp(typname, "numeric"))
 
13918
        {
 
13919
                appendPQExpBuffer(buf, "numeric");
 
13920
                if (typmod != -1)
 
13921
                {
 
13922
                        int32           tmp_typmod;
 
13923
                        int                     precision;
 
13924
                        int                     scale;
 
13925
 
 
13926
                        tmp_typmod = typmod - VARHDRSZ;
 
13927
                        precision = (tmp_typmod >> 16) & 0xffff;
 
13928
                        scale = tmp_typmod & 0xffff;
 
13929
                        appendPQExpBuffer(buf, "(%d,%d)",
 
13930
                                                          precision, scale);
 
13931
                }
 
13932
        }
 
13933
 
 
13934
        /*
 
13935
         * char is an internal single-byte data type; Let's make sure we force it
 
13936
         * through with quotes. - thomas 1998-12-13
 
13937
         */
 
13938
        else if (strcmp(typname, "char") == 0)
 
13939
                appendPQExpBuffer(buf, "\"char\"");
 
13940
        else
 
13941
                appendPQExpBuffer(buf, "%s", fmtId(typname));
 
13942
 
 
13943
        /* Append array qualifier for array types */
 
13944
        if (isarray)
 
13945
                appendPQExpBuffer(buf, "[]");
 
13946
 
 
13947
        result = strdup(buf->data);
 
13948
        destroyPQExpBuffer(buf);
 
13949
 
 
13950
        return result;
 
13951
}
 
13952
 
 
13953
/*
 
13954
 * fmtQualifiedId - convert a qualified name to the proper format for
 
13955
 * the source database.
 
13956
 *
 
13957
 * Like fmtId, use the result before calling again.
 
13958
 */
 
13959
static const char *
 
13960
fmtQualifiedId(const char *schema, const char *id)
 
13961
{
 
13962
        static PQExpBuffer id_return = NULL;
 
13963
 
 
13964
        if (id_return)                          /* first time through? */
 
13965
                resetPQExpBuffer(id_return);
 
13966
        else
 
13967
                id_return = createPQExpBuffer();
 
13968
 
 
13969
        /* Suppress schema name if fetching from pre-7.3 DB */
 
13970
        if (g_fout->remoteVersion >= 70300 && schema && *schema)
 
13971
        {
 
13972
                appendPQExpBuffer(id_return, "%s.",
 
13973
                                                  fmtId(schema));
 
13974
        }
 
13975
        appendPQExpBuffer(id_return, "%s",
 
13976
                                          fmtId(id));
 
13977
 
 
13978
        return id_return->data;
 
13979
}
 
13980
 
 
13981
/*
 
13982
 * Return a column list clause for the given relation.
 
13983
 *
 
13984
 * Special case: if there are no undropped columns in the relation, return
 
13985
 * "", not an invalid "()" column list.
 
13986
 */
 
13987
static const char *
 
13988
fmtCopyColumnList(const TableInfo *ti)
 
13989
{
 
13990
        static PQExpBuffer q = NULL;
 
13991
        int                     numatts = ti->numatts;
 
13992
        char      **attnames = ti->attnames;
 
13993
        bool       *attisdropped = ti->attisdropped;
 
13994
        bool            needComma;
 
13995
        int                     i;
 
13996
 
 
13997
        if (q)                                          /* first time through? */
 
13998
                resetPQExpBuffer(q);
 
13999
        else
 
14000
                q = createPQExpBuffer();
 
14001
 
 
14002
        appendPQExpBuffer(q, "(");
 
14003
        needComma = false;
 
14004
        for (i = 0; i < numatts; i++)
 
14005
        {
 
14006
                if (attisdropped[i])
 
14007
                        continue;
 
14008
                if (needComma)
 
14009
                        appendPQExpBuffer(q, ", ");
 
14010
                appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
 
14011
                needComma = true;
 
14012
        }
 
14013
 
 
14014
        if (!needComma)
 
14015
                return "";                              /* no undropped columns */
 
14016
 
 
14017
        appendPQExpBuffer(q, ")");
 
14018
        return q->data;
 
14019
}
 
14020
 
 
14021
/*
 
14022
 * Convenience subroutine to execute a SQL command and check for
 
14023
 * COMMAND_OK status.
 
14024
 */
 
14025
static void
 
14026
do_sql_command(PGconn *conn, const char *query)
 
14027
{
 
14028
        PGresult   *res;
 
14029
 
 
14030
        res = PQexec(conn, query);
 
14031
        check_sql_result(res, conn, query, PGRES_COMMAND_OK);
 
14032
        PQclear(res);
 
14033
}
 
14034
 
 
14035
/*
 
14036
 * Convenience subroutine to verify a SQL command succeeded,
 
14037
 * and exit with a useful error message if not.
 
14038
 */
 
14039
static void
 
14040
check_sql_result(PGresult *res, PGconn *conn, const char *query,
 
14041
                                 ExecStatusType expected)
 
14042
{
 
14043
        const char *err;
 
14044
 
 
14045
        if (res && PQresultStatus(res) == expected)
 
14046
                return;                                 /* A-OK */
 
14047
 
 
14048
        write_msg(NULL, "SQL command failed\n");
 
14049
        if (res)
 
14050
                err = PQresultErrorMessage(res);
 
14051
        else
 
14052
                err = PQerrorMessage(conn);
 
14053
        write_msg(NULL, "Error message from server: %s", err);
 
14054
        write_msg(NULL, "The command was: %s\n", query);
 
14055
        exit_nicely();
 
14056
}