1 /*-------------------------------------------------------------------------
4 * pg_dump is a utility for dumping out a postgres database
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
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
17 *-------------------------------------------------------------------------
20 #include "postgres_fe.h"
31 #include "getopt_long.h"
33 #include "access/attnum.h"
34 #include "access/sysattr.h"
35 #include "catalog/pg_cast.h"
36 #include "catalog/pg_class.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_trigger.h"
39 #include "catalog/pg_type.h"
40 #include "libpq/libpq-fs.h"
42 #include "pg_backup_archiver.h"
43 #include "dumputils.h"
52 const char *descr
; /* comment for an object */
53 Oid classoid
; /* object class (catalog OID) */
54 Oid objoid
; /* object OID */
55 int objsubid
; /* subobject (table column #) */
60 bool g_verbose
; /* User wants verbose narration of our
62 Archive
*g_fout
; /* the script file */
63 PGconn
*g_conn
; /* the database connection */
65 /* various user-settable parameters */
69 const char *lockWaitTimeout
;
71 /* subquery used to convert user ID (eg, datdba) to user name */
72 static const char *username_subquery
;
74 /* obsolete as of 7.3: */
75 static Oid g_last_builtin_oid
; /* value of the last builtin oid */
78 * Object inclusion/exclusion lists
80 * The string lists record the patterns given by command-line switches,
81 * which we then convert to lists of OIDs of matching objects.
83 static SimpleStringList schema_include_patterns
= {NULL
, NULL
};
84 static SimpleOidList schema_include_oids
= {NULL
, NULL
};
85 static SimpleStringList schema_exclude_patterns
= {NULL
, NULL
};
86 static SimpleOidList schema_exclude_oids
= {NULL
, NULL
};
88 static SimpleStringList table_include_patterns
= {NULL
, NULL
};
89 static SimpleOidList table_include_oids
= {NULL
, NULL
};
90 static SimpleStringList table_exclude_patterns
= {NULL
, NULL
};
91 static SimpleOidList table_exclude_oids
= {NULL
, NULL
};
93 /* default, if no "inclusion" switches appear, is to dump everything */
94 static bool include_everything
= true;
96 char g_opaque_type
[10]; /* name for the opaque type */
98 /* placeholders for the delimiters for comments */
99 char g_comment_start
[10];
100 char g_comment_end
[10];
102 static const CatalogId nilCatalogId
= {0, 0};
104 /* these are to avoid passing around info for findNamespace() */
105 static NamespaceInfo
*g_namespaces
;
106 static int g_numNamespaces
;
108 /* flags for various command-line long options */
109 static int binary_upgrade
= 0;
110 static int disable_dollar_quoting
= 0;
111 static int dump_inserts
= 0;
112 static int column_inserts
= 0;
115 static void help(const char *progname
);
116 static void expand_schema_name_patterns(SimpleStringList
*patterns
,
117 SimpleOidList
*oids
);
118 static void expand_table_name_patterns(SimpleStringList
*patterns
,
119 SimpleOidList
*oids
);
120 static NamespaceInfo
*findNamespace(Oid nsoid
, Oid objoid
);
121 static void dumpTableData(Archive
*fout
, TableDataInfo
*tdinfo
);
122 static void guessConstraintInheritance(TableInfo
*tblinfo
, int numTables
);
123 static void dumpComment(Archive
*fout
, const char *target
,
124 const char *namespace, const char *owner
,
125 CatalogId catalogId
, int subid
, DumpId dumpId
);
126 static int findComments(Archive
*fout
, Oid classoid
, Oid objoid
,
127 CommentItem
**items
);
128 static int collectComments(Archive
*fout
, CommentItem
**items
);
129 static void dumpDumpableObject(Archive
*fout
, DumpableObject
*dobj
);
130 static void dumpNamespace(Archive
*fout
, NamespaceInfo
*nspinfo
);
131 static void dumpType(Archive
*fout
, TypeInfo
*tinfo
);
132 static void dumpBaseType(Archive
*fout
, TypeInfo
*tinfo
);
133 static void dumpEnumType(Archive
*fout
, TypeInfo
*tinfo
);
134 static void dumpDomain(Archive
*fout
, TypeInfo
*tinfo
);
135 static void dumpCompositeType(Archive
*fout
, TypeInfo
*tinfo
);
136 static void dumpShellType(Archive
*fout
, ShellTypeInfo
*stinfo
);
137 static void dumpProcLang(Archive
*fout
, ProcLangInfo
*plang
);
138 static void dumpFunc(Archive
*fout
, FuncInfo
*finfo
);
139 static void dumpCast(Archive
*fout
, CastInfo
*cast
);
140 static void dumpOpr(Archive
*fout
, OprInfo
*oprinfo
);
141 static void dumpOpclass(Archive
*fout
, OpclassInfo
*opcinfo
);
142 static void dumpOpfamily(Archive
*fout
, OpfamilyInfo
*opfinfo
);
143 static void dumpConversion(Archive
*fout
, ConvInfo
*convinfo
);
144 static void dumpRule(Archive
*fout
, RuleInfo
*rinfo
);
145 static void dumpAgg(Archive
*fout
, AggInfo
*agginfo
);
146 static void dumpTrigger(Archive
*fout
, TriggerInfo
*tginfo
);
147 static void dumpTable(Archive
*fout
, TableInfo
*tbinfo
);
148 static void dumpTableSchema(Archive
*fout
, TableInfo
*tbinfo
);
149 static void dumpAttrDef(Archive
*fout
, AttrDefInfo
*adinfo
);
150 static void dumpSequence(Archive
*fout
, TableInfo
*tbinfo
);
151 static void dumpIndex(Archive
*fout
, IndxInfo
*indxinfo
);
152 static void dumpConstraint(Archive
*fout
, ConstraintInfo
*coninfo
);
153 static void dumpTableConstraintComment(Archive
*fout
, ConstraintInfo
*coninfo
);
154 static void dumpTSParser(Archive
*fout
, TSParserInfo
*prsinfo
);
155 static void dumpTSDictionary(Archive
*fout
, TSDictInfo
*dictinfo
);
156 static void dumpTSTemplate(Archive
*fout
, TSTemplateInfo
*tmplinfo
);
157 static void dumpTSConfig(Archive
*fout
, TSConfigInfo
*cfginfo
);
158 static void dumpForeignDataWrapper(Archive
*fout
, FdwInfo
*fdwinfo
);
159 static void dumpForeignServer(Archive
*fout
, ForeignServerInfo
*srvinfo
);
160 static void dumpUserMappings(Archive
*fout
, const char *target
,
161 const char *servername
, const char *namespace,
162 const char *owner
, CatalogId catalogId
, DumpId dumpId
);
164 static void dumpACL(Archive
*fout
, CatalogId objCatId
, DumpId objDumpId
,
165 const char *type
, const char *name
, const char *subname
,
166 const char *tag
, const char *nspname
, const char *owner
,
169 static void getDependencies(void);
170 static void getDomainConstraints(TypeInfo
*tinfo
);
171 static void getTableData(TableInfo
*tblinfo
, int numTables
, bool oids
);
172 static void getTableDataFKConstraints(void);
173 static char *format_function_arguments(FuncInfo
*finfo
, char *funcargs
);
174 static char *format_function_arguments_old(FuncInfo
*finfo
, int nallargs
,
178 static char *format_function_signature(FuncInfo
*finfo
, bool honor_quotes
);
179 static const char *convertRegProcReference(const char *proc
);
180 static const char *convertOperatorReference(const char *opr
);
181 static const char *convertTSFunction(Oid funcOid
);
182 static Oid
findLastBuiltinOid_V71(const char *);
183 static Oid
findLastBuiltinOid_V70(void);
184 static void selectSourceSchema(const char *schemaName
);
185 static char *getFormattedTypeName(Oid oid
, OidOptions opts
);
186 static char *myFormatType(const char *typname
, int32 typmod
);
187 static const char *fmtQualifiedId(const char *schema
, const char *id
);
188 static bool hasBlobs(Archive
*AH
);
189 static int dumpBlobs(Archive
*AH
, void *arg
);
190 static int dumpBlobComments(Archive
*AH
, void *arg
);
191 static void dumpDatabase(Archive
*AH
);
192 static void dumpEncoding(Archive
*AH
);
193 static void dumpStdStrings(Archive
*AH
);
194 static const char *getAttrName(int attrnum
, TableInfo
*tblInfo
);
195 static const char *fmtCopyColumnList(const TableInfo
*ti
);
196 static void do_sql_command(PGconn
*conn
, const char *query
);
197 static void check_sql_result(PGresult
*res
, PGconn
*conn
, const char *query
,
198 ExecStatusType expected
);
202 main(int argc
, char **argv
)
205 const char *filename
= NULL
;
206 const char *format
= "p";
207 const char *dbname
= NULL
;
208 const char *pghost
= NULL
;
209 const char *pgport
= NULL
;
210 const char *username
= NULL
;
211 const char *dumpencoding
= NULL
;
212 const char *std_strings
;
216 DumpableObject
**dobjs
;
219 enum trivalue prompt_password
= TRI_DEFAULT
;
220 int compressLevel
= -1;
223 int outputCreate
= 0;
224 bool outputBlobs
= false;
225 int outputNoOwner
= 0;
226 char *outputSuperuser
= NULL
;
227 char *use_role
= NULL
;
230 RestoreOptions
*ropt
;
232 static int disable_triggers
= 0;
233 static int outputNoTablespaces
= 0;
234 static int use_setsessauth
= 0;
236 struct option long_options
[] = {
237 {"data-only", no_argument
, NULL
, 'a'},
238 {"blobs", no_argument
, NULL
, 'b'},
239 {"clean", no_argument
, NULL
, 'c'},
240 {"create", no_argument
, NULL
, 'C'},
241 {"file", required_argument
, NULL
, 'f'},
242 {"format", required_argument
, NULL
, 'F'},
243 {"host", required_argument
, NULL
, 'h'},
244 {"ignore-version", no_argument
, NULL
, 'i'},
245 {"no-reconnect", no_argument
, NULL
, 'R'},
246 {"oids", no_argument
, NULL
, 'o'},
247 {"no-owner", no_argument
, NULL
, 'O'},
248 {"port", required_argument
, NULL
, 'p'},
249 {"schema", required_argument
, NULL
, 'n'},
250 {"exclude-schema", required_argument
, NULL
, 'N'},
251 {"schema-only", no_argument
, NULL
, 's'},
252 {"superuser", required_argument
, NULL
, 'S'},
253 {"table", required_argument
, NULL
, 't'},
254 {"exclude-table", required_argument
, NULL
, 'T'},
255 {"no-password", no_argument
, NULL
, 'w'},
256 {"password", no_argument
, NULL
, 'W'},
257 {"username", required_argument
, NULL
, 'U'},
258 {"verbose", no_argument
, NULL
, 'v'},
259 {"no-privileges", no_argument
, NULL
, 'x'},
260 {"no-acl", no_argument
, NULL
, 'x'},
261 {"compress", required_argument
, NULL
, 'Z'},
262 {"encoding", required_argument
, NULL
, 'E'},
263 {"help", no_argument
, NULL
, '?'},
264 {"version", no_argument
, NULL
, 'V'},
267 * the following options don't have an equivalent short option letter
269 {"attribute-inserts", no_argument
, &column_inserts
, 1},
270 {"binary-upgrade", no_argument
, &binary_upgrade
, 1},
271 {"column-inserts", no_argument
, &column_inserts
, 1},
272 {"disable-dollar-quoting", no_argument
, &disable_dollar_quoting
, 1},
273 {"disable-triggers", no_argument
, &disable_triggers
, 1},
274 {"inserts", no_argument
, &dump_inserts
, 1},
275 {"lock-wait-timeout", required_argument
, NULL
, 2},
276 {"no-tablespaces", no_argument
, &outputNoTablespaces
, 1},
277 {"role", required_argument
, NULL
, 3},
278 {"use-set-session-authorization", no_argument
, &use_setsessauth
, 1},
283 set_pglocale_pgservice(argv
[0], PG_TEXTDOMAIN("pg_dump"));
287 strcpy(g_comment_start
, "-- ");
288 g_comment_end
[0] = '\0';
289 strcpy(g_opaque_type
, "opaque");
291 dataOnly
= schemaOnly
= false;
292 lockWaitTimeout
= NULL
;
294 progname
= get_progname(argv
[0]);
296 /* Set default options based on progname */
297 if (strcmp(progname
, "pg_backup") == 0)
302 if (strcmp(argv
[1], "--help") == 0 || strcmp(argv
[1], "-?") == 0)
307 if (strcmp(argv
[1], "--version") == 0 || strcmp(argv
[1], "-V") == 0)
309 puts("pg_dump (PostgreSQL) " PG_VERSION
);
314 while ((c
= getopt_long(argc
, argv
, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxX:Z:",
315 long_options
, &optindex
)) != -1)
319 case 'a': /* Dump data only */
323 case 'b': /* Dump blobs */
327 case 'c': /* clean (i.e., drop) schema prior to create */
331 case 'C': /* Create DB */
335 case 'E': /* Dump encoding */
336 dumpencoding
= optarg
;
347 case 'h': /* server host */
352 /* ignored, deprecated option */
355 case 'n': /* include schema(s) */
356 simple_string_list_append(&schema_include_patterns
, optarg
);
357 include_everything
= false;
360 case 'N': /* exclude schema(s) */
361 simple_string_list_append(&schema_exclude_patterns
, optarg
);
364 case 'o': /* Dump oids */
368 case 'O': /* Don't reconnect to match owner */
372 case 'p': /* server port */
377 /* no-op, still accepted for backwards compatibility */
380 case 's': /* dump schema only */
384 case 'S': /* Username for superuser in plain text output */
385 outputSuperuser
= strdup(optarg
);
388 case 't': /* include table(s) */
389 simple_string_list_append(&table_include_patterns
, optarg
);
390 include_everything
= false;
393 case 'T': /* exclude table(s) */
394 simple_string_list_append(&table_exclude_patterns
, optarg
);
401 case 'v': /* verbose */
406 prompt_password
= TRI_NO
;
410 prompt_password
= TRI_YES
;
413 case 'x': /* skip ACL dump */
418 /* -X is a deprecated alternative to long options */
419 if (strcmp(optarg
, "disable-dollar-quoting") == 0)
420 disable_dollar_quoting
= 1;
421 else if (strcmp(optarg
, "disable-triggers") == 0)
422 disable_triggers
= 1;
423 else if (strcmp(optarg
, "no-tablespaces") == 0)
424 outputNoTablespaces
= 1;
425 else if (strcmp(optarg
, "use-set-session-authorization") == 0)
430 _("%s: invalid -X option -- %s\n"),
432 fprintf(stderr
, _("Try \"%s --help\" for more information.\n"), progname
);
437 case 'Z': /* Compression Level */
438 compressLevel
= atoi(optarg
);
442 /* This covers the long options equivalent to -X xxx. */
445 case 2: /* lock-wait-timeout */
446 lockWaitTimeout
= optarg
;
449 case 3: /* SET ROLE */
454 fprintf(stderr
, _("Try \"%s --help\" for more information.\n"), progname
);
459 if (optind
< (argc
- 1))
461 fprintf(stderr
, _("%s: too many command-line arguments (first is \"%s\")\n"),
462 progname
, argv
[optind
+ 1]);
463 fprintf(stderr
, _("Try \"%s --help\" for more information.\n"),
468 /* Get database name from command line */
470 dbname
= argv
[optind
];
472 /* --column-inserts implies --inserts */
476 if (dataOnly
&& schemaOnly
)
478 write_msg(NULL
, "options -s/--schema-only and -a/--data-only cannot be used together\n");
482 if (dataOnly
&& outputClean
)
484 write_msg(NULL
, "options -c/--clean and -a/--data-only cannot be used together\n");
488 if (dump_inserts
&& oids
)
490 write_msg(NULL
, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
491 write_msg(NULL
, "(The INSERT command cannot set OIDs.)\n");
495 /* open the output file */
496 if (pg_strcasecmp(format
, "a") == 0 || pg_strcasecmp(format
, "append") == 0)
498 /* This is used by pg_dumpall, and is not documented */
500 g_fout
= CreateArchive(filename
, archNull
, 0, archModeAppend
);
502 else if (pg_strcasecmp(format
, "c") == 0 || pg_strcasecmp(format
, "custom") == 0)
503 g_fout
= CreateArchive(filename
, archCustom
, compressLevel
, archModeWrite
);
504 else if (pg_strcasecmp(format
, "f") == 0 || pg_strcasecmp(format
, "file") == 0)
507 * Dump files into the current directory; for demonstration only, not
510 g_fout
= CreateArchive(filename
, archFiles
, compressLevel
, archModeWrite
);
512 else if (pg_strcasecmp(format
, "p") == 0 || pg_strcasecmp(format
, "plain") == 0)
515 g_fout
= CreateArchive(filename
, archNull
, 0, archModeWrite
);
517 else if (pg_strcasecmp(format
, "t") == 0 || pg_strcasecmp(format
, "tar") == 0)
518 g_fout
= CreateArchive(filename
, archTar
, compressLevel
, archModeWrite
);
521 write_msg(NULL
, "invalid output format \"%s\" specified\n", format
);
527 write_msg(NULL
, "could not open output file \"%s\" for writing\n", filename
);
531 /* Let the archiver know how noisy to be */
532 g_fout
->verbose
= g_verbose
;
534 my_version
= parse_version(PG_VERSION
);
537 write_msg(NULL
, "could not parse version string \"%s\"\n", PG_VERSION
);
542 * We allow the server to be back to 7.0, and up to any minor release of
543 * our own major version. (See also version check in pg_dumpall.c.)
545 g_fout
->minRemoteVersion
= 70000;
546 g_fout
->maxRemoteVersion
= (my_version
/ 100) * 100 + 99;
549 * Open the database using the Archiver, so it knows about it. Errors mean
552 g_conn
= ConnectDatabase(g_fout
, dbname
, pghost
, pgport
,
553 username
, prompt_password
);
555 /* Set the client encoding if requested */
558 if (PQsetClientEncoding(g_conn
, dumpencoding
) < 0)
560 write_msg(NULL
, "invalid client encoding \"%s\" specified\n",
567 * Get the active encoding and the standard_conforming_strings setting, so
568 * we know how to escape strings.
570 g_fout
->encoding
= PQclientEncoding(g_conn
);
572 std_strings
= PQparameterStatus(g_conn
, "standard_conforming_strings");
573 g_fout
->std_strings
= (std_strings
&& strcmp(std_strings
, "on") == 0);
575 /* Set the role if requested */
576 if (use_role
&& g_fout
->remoteVersion
>= 80100)
578 PQExpBuffer query
= createPQExpBuffer();
580 appendPQExpBuffer(query
, "SET ROLE %s", fmtId(use_role
));
581 do_sql_command(g_conn
, query
->data
);
582 destroyPQExpBuffer(query
);
585 /* Set the datestyle to ISO to ensure the dump's portability */
586 do_sql_command(g_conn
, "SET DATESTYLE = ISO");
588 /* Likewise, avoid using sql_standard intervalstyle */
589 if (g_fout
->remoteVersion
>= 80400)
590 do_sql_command(g_conn
, "SET INTERVALSTYLE = POSTGRES");
593 * If supported, set extra_float_digits so that we can dump float data
594 * exactly (given correctly implemented float I/O code, anyway)
596 if (g_fout
->remoteVersion
>= 70400)
597 do_sql_command(g_conn
, "SET extra_float_digits TO 2");
600 * If synchronized scanning is supported, disable it, to prevent
601 * unpredictable changes in row ordering across a dump and reload.
603 if (g_fout
->remoteVersion
>= 80300)
604 do_sql_command(g_conn
, "SET synchronize_seqscans TO off");
607 * Disable timeouts if supported.
609 if (g_fout
->remoteVersion
>= 70300)
610 do_sql_command(g_conn
, "SET statement_timeout = 0");
613 * Start serializable transaction to dump consistent data.
615 do_sql_command(g_conn
, "BEGIN");
617 do_sql_command(g_conn
, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
619 /* Select the appropriate subquery to convert user IDs to names */
620 if (g_fout
->remoteVersion
>= 80100)
621 username_subquery
= "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
622 else if (g_fout
->remoteVersion
>= 70300)
623 username_subquery
= "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
625 username_subquery
= "SELECT usename FROM pg_user WHERE usesysid =";
627 /* Find the last built-in OID, if needed */
628 if (g_fout
->remoteVersion
< 70300)
630 if (g_fout
->remoteVersion
>= 70100)
631 g_last_builtin_oid
= findLastBuiltinOid_V71(PQdb(g_conn
));
633 g_last_builtin_oid
= findLastBuiltinOid_V70();
635 write_msg(NULL
, "last built-in OID is %u\n", g_last_builtin_oid
);
638 /* Expand schema selection patterns into OID lists */
639 if (schema_include_patterns
.head
!= NULL
)
641 expand_schema_name_patterns(&schema_include_patterns
,
642 &schema_include_oids
);
643 if (schema_include_oids
.head
== NULL
)
645 write_msg(NULL
, "No matching schemas were found\n");
649 expand_schema_name_patterns(&schema_exclude_patterns
,
650 &schema_exclude_oids
);
651 /* non-matching exclusion patterns aren't an error */
653 /* Expand table selection patterns into OID lists */
654 if (table_include_patterns
.head
!= NULL
)
656 expand_table_name_patterns(&table_include_patterns
,
657 &table_include_oids
);
658 if (table_include_oids
.head
== NULL
)
660 write_msg(NULL
, "No matching tables were found\n");
664 expand_table_name_patterns(&table_exclude_patterns
,
665 &table_exclude_oids
);
666 /* non-matching exclusion patterns aren't an error */
669 * Dumping blobs is now default unless we saw an inclusion switch or -s
670 * ... but even if we did see one of these, -b turns it back on.
672 if (include_everything
&& !schemaOnly
)
676 * Now scan the database and create DumpableObject structs for all the
677 * objects we intend to dump.
679 tblinfo
= getSchemaData(&numTables
);
681 if (g_fout
->remoteVersion
< 80400)
682 guessConstraintInheritance(tblinfo
, numTables
);
686 getTableData(tblinfo
, numTables
, oids
);
688 getTableDataFKConstraints();
691 if (outputBlobs
&& hasBlobs(g_fout
))
693 /* Add placeholders to allow correct sorting of blobs */
694 DumpableObject
*blobobj
;
695 DumpableObject
*blobcobj
;
697 blobobj
= (DumpableObject
*) malloc(sizeof(DumpableObject
));
698 blobobj
->objType
= DO_BLOBS
;
699 blobobj
->catId
= nilCatalogId
;
700 AssignDumpId(blobobj
);
701 blobobj
->name
= strdup("BLOBS");
703 blobcobj
= (DumpableObject
*) malloc(sizeof(DumpableObject
));
704 blobcobj
->objType
= DO_BLOB_COMMENTS
;
705 blobcobj
->catId
= nilCatalogId
;
706 AssignDumpId(blobcobj
);
707 blobcobj
->name
= strdup("BLOB COMMENTS");
708 addObjectDependency(blobcobj
, blobobj
->dumpId
);
712 * Collect dependency data to assist in ordering the objects.
717 * Sort the objects into a safe dump order (no forward references).
719 * In 7.3 or later, we can rely on dependency information to help us
720 * determine a safe order, so the initial sort is mostly for cosmetic
721 * purposes: we sort by name to ensure that logically identical schemas
722 * will dump identically. Before 7.3 we don't have dependencies and we
723 * use OID ordering as an (unreliable) guide to creation order.
725 getDumpableObjects(&dobjs
, &numObjs
);
727 if (g_fout
->remoteVersion
>= 70300)
728 sortDumpableObjectsByTypeName(dobjs
, numObjs
);
730 sortDumpableObjectsByTypeOid(dobjs
, numObjs
);
732 sortDumpableObjects(dobjs
, numObjs
);
735 * Create archive TOC entries for all the objects to be dumped, in a safe
739 /* First the special ENCODING and STDSTRINGS entries. */
740 dumpEncoding(g_fout
);
741 dumpStdStrings(g_fout
);
743 /* The database item is always next, unless we don't want it at all */
744 if (include_everything
&& !dataOnly
)
745 dumpDatabase(g_fout
);
747 /* Now the rearrangeable objects. */
748 for (i
= 0; i
< numObjs
; i
++)
749 dumpDumpableObject(g_fout
, dobjs
[i
]);
752 * And finally we can do the actual output.
756 ropt
= NewRestoreOptions();
757 ropt
->filename
= (char *) filename
;
758 ropt
->dropSchema
= outputClean
;
759 ropt
->aclsSkip
= aclsSkip
;
760 ropt
->superuser
= outputSuperuser
;
761 ropt
->create
= outputCreate
;
762 ropt
->noOwner
= outputNoOwner
;
763 ropt
->noTablespace
= outputNoTablespaces
;
764 ropt
->disable_triggers
= disable_triggers
;
765 ropt
->use_setsessauth
= use_setsessauth
;
766 ropt
->dataOnly
= dataOnly
;
768 if (compressLevel
== -1)
769 ropt
->compression
= 0;
771 ropt
->compression
= compressLevel
;
773 ropt
->suppressDumpWarnings
= true; /* We've already shown them */
775 RestoreArchive(g_fout
, ropt
);
778 CloseArchive(g_fout
);
787 help(const char *progname
)
789 printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname
);
790 printf(_("Usage:\n"));
791 printf(_(" %s [OPTION]... [DBNAME]\n"), progname
);
793 printf(_("\nGeneral options:\n"));
794 printf(_(" -f, --file=FILENAME output file name\n"));
795 printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n"));
796 printf(_(" -v, --verbose verbose mode\n"));
797 printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
798 printf(_(" --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
799 printf(_(" --help show this help, then exit\n"));
800 printf(_(" --version output version information, then exit\n"));
802 printf(_("\nOptions controlling the output content:\n"));
803 printf(_(" -a, --data-only dump only the data, not the schema\n"));
804 printf(_(" -b, --blobs include large objects in dump\n"));
805 printf(_(" -c, --clean clean (drop) database objects before recreating\n"));
806 printf(_(" -C, --create include commands to create database in dump\n"));
807 printf(_(" -E, --encoding=ENCODING dump the data in encoding ENCODING\n"));
808 printf(_(" -n, --schema=SCHEMA dump the named schema(s) only\n"));
809 printf(_(" -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
810 printf(_(" -o, --oids include OIDs in dump\n"));
811 printf(_(" -O, --no-owner skip restoration of object ownership in\n"
812 " plain-text format\n"));
813 printf(_(" -s, --schema-only dump only the schema, no data\n"));
814 printf(_(" -S, --superuser=NAME superuser user name to use in plain-text format\n"));
815 printf(_(" -t, --table=TABLE dump the named table(s) only\n"));
816 printf(_(" -T, --exclude-table=TABLE do NOT dump the named table(s)\n"));
817 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
818 printf(_(" --binary-upgrade for use by upgrade utilities only\n"));
819 printf(_(" --inserts dump data as INSERT commands, rather than COPY\n"));
820 printf(_(" --column-inserts dump data as INSERT commands with column names\n"));
821 printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n"));
822 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
823 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
824 printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
825 printf(_(" --use-set-session-authorization\n"
826 " use SET SESSION AUTHORIZATION commands instead of\n"
827 " ALTER OWNER commands to set ownership\n"));
829 printf(_("\nConnection options:\n"));
830 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
831 printf(_(" -p, --port=PORT database server port number\n"));
832 printf(_(" -U, --username=NAME connect as specified database user\n"));
833 printf(_(" -w, --no-password never prompt for password\n"));
834 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
836 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
837 "variable value is used.\n\n"));
838 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
846 write_msg(NULL
, "*** aborted because of error\n");
851 * Find the OIDs of all schemas matching the given list of patterns,
852 * and append them to the given OID list.
855 expand_schema_name_patterns(SimpleStringList
*patterns
, SimpleOidList
*oids
)
859 SimpleStringListCell
*cell
;
862 if (patterns
->head
== NULL
)
863 return; /* nothing to do */
865 if (g_fout
->remoteVersion
< 70300)
867 write_msg(NULL
, "server version must be at least 7.3 to use schema selection switches\n");
871 query
= createPQExpBuffer();
874 * We use UNION ALL rather than UNION; this might sometimes result in
875 * duplicate entries in the OID list, but we don't care.
878 for (cell
= patterns
->head
; cell
; cell
= cell
->next
)
880 if (cell
!= patterns
->head
)
881 appendPQExpBuffer(query
, "UNION ALL\n");
882 appendPQExpBuffer(query
,
883 "SELECT oid FROM pg_catalog.pg_namespace n\n");
884 processSQLNamePattern(g_conn
, query
, cell
->val
, false, false,
885 NULL
, "n.nspname", NULL
,
889 res
= PQexec(g_conn
, query
->data
);
890 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
892 for (i
= 0; i
< PQntuples(res
); i
++)
894 simple_oid_list_append(oids
, atooid(PQgetvalue(res
, i
, 0)));
898 destroyPQExpBuffer(query
);
902 * Find the OIDs of all tables matching the given list of patterns,
903 * and append them to the given OID list.
906 expand_table_name_patterns(SimpleStringList
*patterns
, SimpleOidList
*oids
)
910 SimpleStringListCell
*cell
;
913 if (patterns
->head
== NULL
)
914 return; /* nothing to do */
916 query
= createPQExpBuffer();
919 * We use UNION ALL rather than UNION; this might sometimes result in
920 * duplicate entries in the OID list, but we don't care.
923 for (cell
= patterns
->head
; cell
; cell
= cell
->next
)
925 if (cell
!= patterns
->head
)
926 appendPQExpBuffer(query
, "UNION ALL\n");
927 appendPQExpBuffer(query
,
929 "\nFROM pg_catalog.pg_class c"
930 "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
931 "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
932 RELKIND_RELATION
, RELKIND_SEQUENCE
, RELKIND_VIEW
);
933 processSQLNamePattern(g_conn
, query
, cell
->val
, true, false,
934 "n.nspname", "c.relname", NULL
,
935 "pg_catalog.pg_table_is_visible(c.oid)");
938 res
= PQexec(g_conn
, query
->data
);
939 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
941 for (i
= 0; i
< PQntuples(res
); i
++)
943 simple_oid_list_append(oids
, atooid(PQgetvalue(res
, i
, 0)));
947 destroyPQExpBuffer(query
);
951 * selectDumpableNamespace: policy-setting subroutine
952 * Mark a namespace as to be dumped or not
955 selectDumpableNamespace(NamespaceInfo
*nsinfo
)
958 * If specific tables are being dumped, do not dump any complete
959 * namespaces. If specific namespaces are being dumped, dump just those
960 * namespaces. Otherwise, dump all non-system namespaces.
962 if (table_include_oids
.head
!= NULL
)
963 nsinfo
->dobj
.dump
= false;
964 else if (schema_include_oids
.head
!= NULL
)
965 nsinfo
->dobj
.dump
= simple_oid_list_member(&schema_include_oids
,
966 nsinfo
->dobj
.catId
.oid
);
967 else if (strncmp(nsinfo
->dobj
.name
, "pg_", 3) == 0 ||
968 strcmp(nsinfo
->dobj
.name
, "information_schema") == 0)
969 nsinfo
->dobj
.dump
= false;
971 nsinfo
->dobj
.dump
= true;
974 * In any case, a namespace can be excluded by an exclusion switch
976 if (nsinfo
->dobj
.dump
&&
977 simple_oid_list_member(&schema_exclude_oids
,
978 nsinfo
->dobj
.catId
.oid
))
979 nsinfo
->dobj
.dump
= false;
983 * selectDumpableTable: policy-setting subroutine
984 * Mark a table as to be dumped or not
987 selectDumpableTable(TableInfo
*tbinfo
)
990 * If specific tables are being dumped, dump just those tables; else, dump
991 * according to the parent namespace's dump flag.
993 if (table_include_oids
.head
!= NULL
)
994 tbinfo
->dobj
.dump
= simple_oid_list_member(&table_include_oids
,
995 tbinfo
->dobj
.catId
.oid
);
997 tbinfo
->dobj
.dump
= tbinfo
->dobj
.namespace->dobj
.dump
;
1000 * In any case, a table can be excluded by an exclusion switch
1002 if (tbinfo
->dobj
.dump
&&
1003 simple_oid_list_member(&table_exclude_oids
,
1004 tbinfo
->dobj
.catId
.oid
))
1005 tbinfo
->dobj
.dump
= false;
1009 * selectDumpableType: policy-setting subroutine
1010 * Mark a type as to be dumped or not
1012 * If it's a table's rowtype or an autogenerated array type, we also apply a
1013 * special type code to facilitate sorting into the desired order. (We don't
1014 * want to consider those to be ordinary types because that would bring tables
1015 * up into the datatype part of the dump order.) Those tests should be made
1016 * first to ensure the objType change is applied regardless of namespace etc.
1019 selectDumpableType(TypeInfo
*tinfo
)
1021 /* skip complex types, except for standalone composite types */
1022 if (OidIsValid(tinfo
->typrelid
) &&
1023 tinfo
->typrelkind
!= RELKIND_COMPOSITE_TYPE
)
1025 tinfo
->dobj
.dump
= false;
1026 tinfo
->dobj
.objType
= DO_DUMMY_TYPE
;
1029 /* skip auto-generated array types */
1030 else if (tinfo
->isArray
)
1032 tinfo
->dobj
.dump
= false;
1033 tinfo
->dobj
.objType
= DO_DUMMY_TYPE
;
1036 /* dump only types in dumpable namespaces */
1037 else if (!tinfo
->dobj
.namespace->dobj
.dump
)
1038 tinfo
->dobj
.dump
= false;
1040 /* skip undefined placeholder types */
1041 else if (!tinfo
->isDefined
)
1042 tinfo
->dobj
.dump
= false;
1045 tinfo
->dobj
.dump
= true;
1049 * selectDumpableObject: policy-setting subroutine
1050 * Mark a generic dumpable object as to be dumped or not
1052 * Use this only for object types without a special-case routine above.
1055 selectDumpableObject(DumpableObject
*dobj
)
1058 * Default policy is to dump if parent namespace is dumpable, or always
1059 * for non-namespace-associated items.
1061 if (dobj
->namespace)
1062 dobj
->dump
= dobj
->namespace->dobj
.dump
;
1068 * Dump a table's contents for loading using the COPY command
1069 * - this routine is called by the Archiver when it wants the table
1074 dumpTableData_copy(Archive
*fout
, void *dcontext
)
1076 TableDataInfo
*tdinfo
= (TableDataInfo
*) dcontext
;
1077 TableInfo
*tbinfo
= tdinfo
->tdtable
;
1078 const char *classname
= tbinfo
->dobj
.name
;
1079 const bool hasoids
= tbinfo
->hasoids
;
1080 const bool oids
= tdinfo
->oids
;
1081 PQExpBuffer q
= createPQExpBuffer();
1085 const char *column_list
;
1088 write_msg(NULL
, "dumping contents of table %s\n", classname
);
1091 * Make sure we are in proper schema. We will qualify the table name
1092 * below anyway (in case its name conflicts with a pg_catalog table); but
1093 * this ensures reproducible results in case the table contains regproc,
1094 * regclass, etc columns.
1096 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
1099 * If possible, specify the column list explicitly so that we have no
1100 * possibility of retrieving data in the wrong column order. (The default
1101 * column ordering of COPY will not be what we want in certain corner
1102 * cases involving ADD COLUMN and inheritance.)
1104 if (g_fout
->remoteVersion
>= 70300)
1105 column_list
= fmtCopyColumnList(tbinfo
);
1107 column_list
= ""; /* can't select columns in COPY */
1109 if (oids
&& hasoids
)
1111 appendPQExpBuffer(q
, "COPY %s %s WITH OIDS TO stdout;",
1112 fmtQualifiedId(tbinfo
->dobj
.namespace->dobj
.name
,
1118 appendPQExpBuffer(q
, "COPY %s %s TO stdout;",
1119 fmtQualifiedId(tbinfo
->dobj
.namespace->dobj
.name
,
1123 res
= PQexec(g_conn
, q
->data
);
1124 check_sql_result(res
, g_conn
, q
->data
, PGRES_COPY_OUT
);
1129 ret
= PQgetCopyData(g_conn
, ©buf
, 0);
1132 break; /* done or error */
1136 WriteData(fout
, copybuf
, ret
);
1143 * There was considerable discussion in late July, 2000 regarding
1144 * slowing down pg_dump when backing up large tables. Users with both
1145 * slow & fast (multi-processor) machines experienced performance
1146 * degradation when doing a backup.
1148 * Initial attempts based on sleeping for a number of ms for each ms
1149 * of work were deemed too complex, then a simple 'sleep in each loop'
1150 * implementation was suggested. The latter failed because the loop
1151 * was too tight. Finally, the following was implemented:
1153 * If throttle is non-zero, then
1154 * See how long since the last sleep.
1155 * Work out how long to sleep (based on ratio).
1156 * If sleep is more than 100ms, then
1162 * where the throttle value was the number of ms to sleep per ms of
1163 * work. The calculation was done in each loop.
1165 * Most of the hard work is done in the backend, and this solution
1166 * still did not work particularly well: on slow machines, the ratio
1167 * was 50:1, and on medium paced machines, 1:1, and on fast
1168 * multi-processor machines, it had little or no effect, for reasons
1169 * that were unclear.
1171 * Further discussion ensued, and the proposal was dropped.
1173 * For those people who want this feature, it can be implemented using
1174 * gettimeofday in each loop, calculating the time since last sleep,
1175 * multiplying that by the sleep ratio, then if the result is more
1176 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1177 * function to sleep for a subsecond period ie.
1179 * select(0, NULL, NULL, NULL, &tvi);
1181 * This will return after the interval specified in the structure tvi.
1182 * Finally, call gettimeofday again to save the 'last sleep time'.
1186 archprintf(fout
, "\\.\n\n\n");
1190 /* copy data transfer failed */
1191 write_msg(NULL
, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname
);
1192 write_msg(NULL
, "Error message from server: %s", PQerrorMessage(g_conn
));
1193 write_msg(NULL
, "The command was: %s\n", q
->data
);
1197 /* Check command status and return to normal libpq state */
1198 res
= PQgetResult(g_conn
);
1199 check_sql_result(res
, g_conn
, q
->data
, PGRES_COMMAND_OK
);
1202 destroyPQExpBuffer(q
);
1207 dumpTableData_insert(Archive
*fout
, void *dcontext
)
1209 TableDataInfo
*tdinfo
= (TableDataInfo
*) dcontext
;
1210 TableInfo
*tbinfo
= tdinfo
->tdtable
;
1211 const char *classname
= tbinfo
->dobj
.name
;
1212 PQExpBuffer q
= createPQExpBuffer();
1219 * Make sure we are in proper schema. We will qualify the table name
1220 * below anyway (in case its name conflicts with a pg_catalog table); but
1221 * this ensures reproducible results in case the table contains regproc,
1222 * regclass, etc columns.
1224 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
1226 if (fout
->remoteVersion
>= 70100)
1228 appendPQExpBuffer(q
, "DECLARE _pg_dump_cursor CURSOR FOR "
1229 "SELECT * FROM ONLY %s",
1230 fmtQualifiedId(tbinfo
->dobj
.namespace->dobj
.name
,
1235 appendPQExpBuffer(q
, "DECLARE _pg_dump_cursor CURSOR FOR "
1237 fmtQualifiedId(tbinfo
->dobj
.namespace->dobj
.name
,
1241 res
= PQexec(g_conn
, q
->data
);
1242 check_sql_result(res
, g_conn
, q
->data
, PGRES_COMMAND_OK
);
1248 res
= PQexec(g_conn
, "FETCH 100 FROM _pg_dump_cursor");
1249 check_sql_result(res
, g_conn
, "FETCH 100 FROM _pg_dump_cursor",
1251 nfields
= PQnfields(res
);
1252 for (tuple
= 0; tuple
< PQntuples(res
); tuple
++)
1254 archprintf(fout
, "INSERT INTO %s ", fmtId(classname
));
1257 /* corner case for zero-column table */
1258 archprintf(fout
, "DEFAULT VALUES;\n");
1263 resetPQExpBuffer(q
);
1264 appendPQExpBuffer(q
, "(");
1265 for (field
= 0; field
< nfields
; field
++)
1268 appendPQExpBuffer(q
, ", ");
1269 appendPQExpBufferStr(q
, fmtId(PQfname(res
, field
)));
1271 appendPQExpBuffer(q
, ") ");
1272 archputs(q
->data
, fout
);
1274 archprintf(fout
, "VALUES (");
1275 for (field
= 0; field
< nfields
; field
++)
1278 archprintf(fout
, ", ");
1279 if (PQgetisnull(res
, tuple
, field
))
1281 archprintf(fout
, "NULL");
1285 /* XXX This code is partially duplicated in ruleutils.c */
1286 switch (PQftype(res
, field
))
1297 * These types are printed without quotes unless
1298 * they contain values that aren't accepted by the
1299 * scanner unquoted (e.g., 'NaN'). Note that
1300 * strtod() and friends might accept NaN, so we
1301 * can't use that to test.
1303 * In reality we only need to defend against
1304 * infinity and NaN, so we need not get too crazy
1305 * about pattern matching here.
1307 const char *s
= PQgetvalue(res
, tuple
, field
);
1309 if (strspn(s
, "0123456789 +-eE.") == strlen(s
))
1310 archprintf(fout
, "%s", s
);
1312 archprintf(fout
, "'%s'", s
);
1318 archprintf(fout
, "B'%s'",
1319 PQgetvalue(res
, tuple
, field
));
1323 if (strcmp(PQgetvalue(res
, tuple
, field
), "t") == 0)
1324 archprintf(fout
, "true");
1326 archprintf(fout
, "false");
1330 /* All other types are printed as string literals. */
1331 resetPQExpBuffer(q
);
1332 appendStringLiteralAH(q
,
1333 PQgetvalue(res
, tuple
, field
),
1335 archputs(q
->data
, fout
);
1339 archprintf(fout
, ");\n");
1341 } while (PQntuples(res
) > 0);
1345 archprintf(fout
, "\n\n");
1347 do_sql_command(g_conn
, "CLOSE _pg_dump_cursor");
1349 destroyPQExpBuffer(q
);
1356 * dump the contents of a single table
1358 * Actually, this just makes an ArchiveEntry for the table contents.
1361 dumpTableData(Archive
*fout
, TableDataInfo
*tdinfo
)
1363 TableInfo
*tbinfo
= tdinfo
->tdtable
;
1364 PQExpBuffer copyBuf
= createPQExpBuffer();
1365 DataDumperPtr dumpFn
;
1370 /* Dump/restore using COPY */
1371 dumpFn
= dumpTableData_copy
;
1372 /* must use 2 steps here 'cause fmtId is nonreentrant */
1373 appendPQExpBuffer(copyBuf
, "COPY %s ",
1374 fmtId(tbinfo
->dobj
.name
));
1375 appendPQExpBuffer(copyBuf
, "%s %sFROM stdin;\n",
1376 fmtCopyColumnList(tbinfo
),
1377 (tdinfo
->oids
&& tbinfo
->hasoids
) ? "WITH OIDS " : "");
1378 copyStmt
= copyBuf
->data
;
1382 /* Restore using INSERT */
1383 dumpFn
= dumpTableData_insert
;
1387 ArchiveEntry(fout
, tdinfo
->dobj
.catId
, tdinfo
->dobj
.dumpId
,
1388 tbinfo
->dobj
.name
, tbinfo
->dobj
.namespace->dobj
.name
,
1389 NULL
, tbinfo
->rolname
,
1390 false, "TABLE DATA", SECTION_DATA
,
1392 tdinfo
->dobj
.dependencies
, tdinfo
->dobj
.nDeps
,
1395 destroyPQExpBuffer(copyBuf
);
1400 * set up dumpable objects representing the contents of tables
1403 getTableData(TableInfo
*tblinfo
, int numTables
, bool oids
)
1407 for (i
= 0; i
< numTables
; i
++)
1409 /* Skip VIEWs (no data to dump) */
1410 if (tblinfo
[i
].relkind
== RELKIND_VIEW
)
1412 /* Skip SEQUENCEs (handled elsewhere) */
1413 if (tblinfo
[i
].relkind
== RELKIND_SEQUENCE
)
1416 if (tblinfo
[i
].dobj
.dump
)
1418 TableDataInfo
*tdinfo
;
1420 tdinfo
= (TableDataInfo
*) malloc(sizeof(TableDataInfo
));
1422 tdinfo
->dobj
.objType
= DO_TABLE_DATA
;
1425 * Note: use tableoid 0 so that this object won't be mistaken for
1426 * something that pg_depend entries apply to.
1428 tdinfo
->dobj
.catId
.tableoid
= 0;
1429 tdinfo
->dobj
.catId
.oid
= tblinfo
[i
].dobj
.catId
.oid
;
1430 AssignDumpId(&tdinfo
->dobj
);
1431 tdinfo
->dobj
.name
= tblinfo
[i
].dobj
.name
;
1432 tdinfo
->dobj
.namespace = tblinfo
[i
].dobj
.namespace;
1433 tdinfo
->tdtable
= &(tblinfo
[i
]);
1434 tdinfo
->oids
= oids
;
1435 addObjectDependency(&tdinfo
->dobj
, tblinfo
[i
].dobj
.dumpId
);
1437 tblinfo
[i
].dataObj
= tdinfo
;
1443 * getTableDataFKConstraints -
1444 * add dump-order dependencies reflecting foreign key constraints
1446 * This code is executed only in a data-only dump --- in schema+data dumps
1447 * we handle foreign key issues by not creating the FK constraints until
1448 * after the data is loaded. In a data-only dump, however, we want to
1449 * order the table data objects in such a way that a table's referenced
1450 * tables are restored first. (In the presence of circular references or
1451 * self-references this may be impossible; we'll detect and complain about
1452 * that during the dependency sorting step.)
1455 getTableDataFKConstraints(void)
1457 DumpableObject
**dobjs
;
1461 /* Search through all the dumpable objects for FK constraints */
1462 getDumpableObjects(&dobjs
, &numObjs
);
1463 for (i
= 0; i
< numObjs
; i
++)
1465 if (dobjs
[i
]->objType
== DO_FK_CONSTRAINT
)
1467 ConstraintInfo
*cinfo
= (ConstraintInfo
*) dobjs
[i
];
1470 /* Not interesting unless both tables are to be dumped */
1471 if (cinfo
->contable
== NULL
||
1472 cinfo
->contable
->dataObj
== NULL
)
1474 ftable
= findTableByOid(cinfo
->confrelid
);
1475 if (ftable
== NULL
||
1476 ftable
->dataObj
== NULL
)
1480 * Okay, make referencing table's TABLE_DATA object depend on the
1481 * referenced table's TABLE_DATA object.
1483 addObjectDependency(&cinfo
->contable
->dataObj
->dobj
,
1484 ftable
->dataObj
->dobj
.dumpId
);
1492 * guessConstraintInheritance:
1493 * In pre-8.4 databases, we can't tell for certain which constraints
1494 * are inherited. We assume a CHECK constraint is inherited if its name
1495 * matches the name of any constraint in the parent. Originally this code
1496 * tried to compare the expression texts, but that can fail for various
1497 * reasons --- for example, if the parent and child tables are in different
1498 * schemas, reverse-listing of function calls may produce different text
1499 * (schema-qualified or not) depending on search path.
1501 * In 8.4 and up we can rely on the conislocal field to decide which
1502 * constraints must be dumped; much safer.
1504 * This function assumes all conislocal flags were initialized to TRUE.
1505 * It clears the flag on anything that seems to be inherited.
1508 guessConstraintInheritance(TableInfo
*tblinfo
, int numTables
)
1514 for (i
= 0; i
< numTables
; i
++)
1516 TableInfo
*tbinfo
= &(tblinfo
[i
]);
1518 TableInfo
**parents
;
1521 /* Sequences and views never have parents */
1522 if (tbinfo
->relkind
== RELKIND_SEQUENCE
||
1523 tbinfo
->relkind
== RELKIND_VIEW
)
1526 /* Don't bother computing anything for non-target tables, either */
1527 if (!tbinfo
->dobj
.dump
)
1530 numParents
= tbinfo
->numParents
;
1531 parents
= tbinfo
->parents
;
1533 if (numParents
== 0)
1534 continue; /* nothing to see here, move along */
1536 /* scan for inherited CHECK constraints */
1537 for (j
= 0; j
< tbinfo
->ncheck
; j
++)
1539 ConstraintInfo
*constr
;
1541 constr
= &(tbinfo
->checkexprs
[j
]);
1543 for (k
= 0; k
< numParents
; k
++)
1547 parent
= parents
[k
];
1548 for (l
= 0; l
< parent
->ncheck
; l
++)
1550 ConstraintInfo
*pconstr
= &(parent
->checkexprs
[l
]);
1552 if (strcmp(pconstr
->dobj
.name
, constr
->dobj
.name
) == 0)
1554 constr
->conislocal
= false;
1558 if (!constr
->conislocal
)
1568 * dump the database definition
1571 dumpDatabase(Archive
*AH
)
1573 PQExpBuffer dbQry
= createPQExpBuffer();
1574 PQExpBuffer delQry
= createPQExpBuffer();
1575 PQExpBuffer creaQry
= createPQExpBuffer();
1588 const char *datname
,
1596 datname
= PQdb(g_conn
);
1599 write_msg(NULL
, "saving database definition\n");
1601 /* Make sure we are in proper schema */
1602 selectSourceSchema("pg_catalog");
1604 /* Get the database owner and parameters from pg_database */
1605 if (g_fout
->remoteVersion
>= 80400)
1607 appendPQExpBuffer(dbQry
, "SELECT tableoid, oid, "
1608 "(%s datdba) AS dba, "
1609 "pg_encoding_to_char(encoding) AS encoding, "
1610 "datcollate, datctype, datfrozenxid, "
1611 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1612 "shobj_description(oid, 'pg_database') AS description "
1617 appendStringLiteralAH(dbQry
, datname
, AH
);
1619 else if (g_fout
->remoteVersion
>= 80200)
1621 appendPQExpBuffer(dbQry
, "SELECT tableoid, oid, "
1622 "(%s datdba) AS dba, "
1623 "pg_encoding_to_char(encoding) AS encoding, "
1624 "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1625 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1626 "shobj_description(oid, 'pg_database') AS description "
1631 appendStringLiteralAH(dbQry
, datname
, AH
);
1633 else if (g_fout
->remoteVersion
>= 80000)
1635 appendPQExpBuffer(dbQry
, "SELECT tableoid, oid, "
1636 "(%s datdba) AS dba, "
1637 "pg_encoding_to_char(encoding) AS encoding, "
1638 "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1639 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1643 appendStringLiteralAH(dbQry
, datname
, AH
);
1645 else if (g_fout
->remoteVersion
>= 70100)
1647 appendPQExpBuffer(dbQry
, "SELECT tableoid, oid, "
1648 "(%s datdba) AS dba, "
1649 "pg_encoding_to_char(encoding) AS encoding, "
1650 "NULL AS datcollate, NULL AS datctype, "
1651 "0 AS datfrozenxid, "
1652 "NULL AS tablespace "
1656 appendStringLiteralAH(dbQry
, datname
, AH
);
1660 appendPQExpBuffer(dbQry
, "SELECT "
1661 "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1663 "(%s datdba) AS dba, "
1664 "pg_encoding_to_char(encoding) AS encoding, "
1665 "NULL AS datcollate, NULL AS datctype, "
1666 "0 AS datfrozenxid, "
1667 "NULL AS tablespace "
1671 appendStringLiteralAH(dbQry
, datname
, AH
);
1674 res
= PQexec(g_conn
, dbQry
->data
);
1675 check_sql_result(res
, g_conn
, dbQry
->data
, PGRES_TUPLES_OK
);
1677 ntups
= PQntuples(res
);
1681 write_msg(NULL
, "missing pg_database entry for database \"%s\"\n",
1688 write_msg(NULL
, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1693 i_tableoid
= PQfnumber(res
, "tableoid");
1694 i_oid
= PQfnumber(res
, "oid");
1695 i_dba
= PQfnumber(res
, "dba");
1696 i_encoding
= PQfnumber(res
, "encoding");
1697 i_collate
= PQfnumber(res
, "datcollate");
1698 i_ctype
= PQfnumber(res
, "datctype");
1699 i_frozenxid
= PQfnumber(res
, "datfrozenxid");
1700 i_tablespace
= PQfnumber(res
, "tablespace");
1702 dbCatId
.tableoid
= atooid(PQgetvalue(res
, 0, i_tableoid
));
1703 dbCatId
.oid
= atooid(PQgetvalue(res
, 0, i_oid
));
1704 dba
= PQgetvalue(res
, 0, i_dba
);
1705 encoding
= PQgetvalue(res
, 0, i_encoding
);
1706 collate
= PQgetvalue(res
, 0, i_collate
);
1707 ctype
= PQgetvalue(res
, 0, i_ctype
);
1708 frozenxid
= atooid(PQgetvalue(res
, 0, i_frozenxid
));
1709 tablespace
= PQgetvalue(res
, 0, i_tablespace
);
1711 appendPQExpBuffer(creaQry
, "CREATE DATABASE %s WITH TEMPLATE = template0",
1713 if (strlen(encoding
) > 0)
1715 appendPQExpBuffer(creaQry
, " ENCODING = ");
1716 appendStringLiteralAH(creaQry
, encoding
, AH
);
1718 if (strlen(collate
) > 0)
1720 appendPQExpBuffer(creaQry
, " LC_COLLATE = ");
1721 appendStringLiteralAH(creaQry
, collate
, AH
);
1723 if (strlen(ctype
) > 0)
1725 appendPQExpBuffer(creaQry
, " LC_CTYPE = ");
1726 appendStringLiteralAH(creaQry
, ctype
, AH
);
1728 if (strlen(tablespace
) > 0 && strcmp(tablespace
, "pg_default") != 0)
1729 appendPQExpBuffer(creaQry
, " TABLESPACE = %s",
1731 appendPQExpBuffer(creaQry
, ";\n");
1735 appendPQExpBuffer(creaQry
, "\n-- For binary upgrade, set datfrozenxid.\n");
1736 appendPQExpBuffer(creaQry
, "UPDATE pg_database\n"
1737 "SET datfrozenxid = '%u'\n"
1740 appendStringLiteralAH(creaQry
, datname
, AH
);
1741 appendPQExpBuffer(creaQry
, ";\n");
1744 appendPQExpBuffer(delQry
, "DROP DATABASE %s;\n",
1747 dbDumpId
= createDumpId();
1750 dbCatId
, /* catalog ID */
1751 dbDumpId
, /* dump ID */
1753 NULL
, /* Namespace */
1754 NULL
, /* Tablespace */
1756 false, /* with oids */
1757 "DATABASE", /* Desc */
1758 SECTION_PRE_DATA
, /* Section */
1759 creaQry
->data
, /* Create */
1760 delQry
->data
, /* Del */
1765 NULL
); /* Dumper Arg */
1767 /* Dump DB comment if any */
1768 if (g_fout
->remoteVersion
>= 80200)
1771 * 8.2 keeps comments on shared objects in a shared table, so we
1772 * cannot use the dumpComment used for other database objects.
1774 char *comment
= PQgetvalue(res
, 0, PQfnumber(res
, "description"));
1776 if (comment
&& strlen(comment
))
1778 resetPQExpBuffer(dbQry
);
1781 * Generates warning when loaded into a differently-named
1784 appendPQExpBuffer(dbQry
, "COMMENT ON DATABASE %s IS ", fmtId(datname
));
1785 appendStringLiteralAH(dbQry
, comment
, AH
);
1786 appendPQExpBuffer(dbQry
, ";\n");
1788 ArchiveEntry(AH
, dbCatId
, createDumpId(), datname
, NULL
, NULL
,
1789 dba
, false, "COMMENT", SECTION_NONE
,
1790 dbQry
->data
, "", NULL
,
1791 &dbDumpId
, 1, NULL
, NULL
);
1796 resetPQExpBuffer(dbQry
);
1797 appendPQExpBuffer(dbQry
, "DATABASE %s", fmtId(datname
));
1798 dumpComment(AH
, dbQry
->data
, NULL
, "",
1799 dbCatId
, 0, dbDumpId
);
1804 destroyPQExpBuffer(dbQry
);
1805 destroyPQExpBuffer(delQry
);
1806 destroyPQExpBuffer(creaQry
);
1811 * dumpEncoding: put the correct encoding into the archive
1814 dumpEncoding(Archive
*AH
)
1816 const char *encname
= pg_encoding_to_char(AH
->encoding
);
1817 PQExpBuffer qry
= createPQExpBuffer();
1820 write_msg(NULL
, "saving encoding = %s\n", encname
);
1822 appendPQExpBuffer(qry
, "SET client_encoding = ");
1823 appendStringLiteralAH(qry
, encname
, AH
);
1824 appendPQExpBuffer(qry
, ";\n");
1826 ArchiveEntry(AH
, nilCatalogId
, createDumpId(),
1827 "ENCODING", NULL
, NULL
, "",
1828 false, "ENCODING", SECTION_PRE_DATA
,
1829 qry
->data
, "", NULL
,
1833 destroyPQExpBuffer(qry
);
1838 * dumpStdStrings: put the correct escape string behavior into the archive
1841 dumpStdStrings(Archive
*AH
)
1843 const char *stdstrings
= AH
->std_strings
? "on" : "off";
1844 PQExpBuffer qry
= createPQExpBuffer();
1847 write_msg(NULL
, "saving standard_conforming_strings = %s\n",
1850 appendPQExpBuffer(qry
, "SET standard_conforming_strings = '%s';\n",
1853 ArchiveEntry(AH
, nilCatalogId
, createDumpId(),
1854 "STDSTRINGS", NULL
, NULL
, "",
1855 false, "STDSTRINGS", SECTION_PRE_DATA
,
1856 qry
->data
, "", NULL
,
1860 destroyPQExpBuffer(qry
);
1866 * Test whether database contains any large objects
1869 hasBlobs(Archive
*AH
)
1872 const char *blobQry
;
1875 /* Make sure we are in proper schema */
1876 selectSourceSchema("pg_catalog");
1878 /* Check for BLOB OIDs */
1879 if (AH
->remoteVersion
>= 70100)
1880 blobQry
= "SELECT loid FROM pg_largeobject LIMIT 1";
1882 blobQry
= "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1884 res
= PQexec(g_conn
, blobQry
);
1885 check_sql_result(res
, g_conn
, blobQry
, PGRES_TUPLES_OK
);
1887 result
= PQntuples(res
) > 0;
1899 dumpBlobs(Archive
*AH
, void *arg
)
1901 const char *blobQry
;
1902 const char *blobFetchQry
;
1904 char buf
[LOBBUFSIZE
];
1909 write_msg(NULL
, "saving large objects\n");
1911 /* Make sure we are in proper schema */
1912 selectSourceSchema("pg_catalog");
1914 /* Cursor to get all BLOB OIDs */
1915 if (AH
->remoteVersion
>= 70100)
1916 blobQry
= "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1918 blobQry
= "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1920 res
= PQexec(g_conn
, blobQry
);
1921 check_sql_result(res
, g_conn
, blobQry
, PGRES_COMMAND_OK
);
1923 /* Command to fetch from cursor */
1924 blobFetchQry
= "FETCH 1000 IN bloboid";
1931 res
= PQexec(g_conn
, blobFetchQry
);
1932 check_sql_result(res
, g_conn
, blobFetchQry
, PGRES_TUPLES_OK
);
1934 /* Process the tuples, if any */
1935 for (i
= 0; i
< PQntuples(res
); i
++)
1940 blobOid
= atooid(PQgetvalue(res
, i
, 0));
1942 loFd
= lo_open(g_conn
, blobOid
, INV_READ
);
1945 write_msg(NULL
, "dumpBlobs(): could not open large object: %s",
1946 PQerrorMessage(g_conn
));
1950 StartBlob(AH
, blobOid
);
1952 /* Now read it in chunks, sending data to archive */
1955 cnt
= lo_read(g_conn
, loFd
, buf
, LOBBUFSIZE
);
1958 write_msg(NULL
, "dumpBlobs(): error reading large object: %s",
1959 PQerrorMessage(g_conn
));
1963 WriteData(AH
, buf
, cnt
);
1966 lo_close(g_conn
, loFd
);
1968 EndBlob(AH
, blobOid
);
1970 } while (PQntuples(res
) > 0);
1979 * dump all blob comments
1981 * Since we don't provide any way to be selective about dumping blobs,
1982 * there's no need to be selective about their comments either. We put
1983 * all the comments into one big TOC entry.
1986 dumpBlobComments(Archive
*AH
, void *arg
)
1988 const char *blobQry
;
1989 const char *blobFetchQry
;
1990 PQExpBuffer commentcmd
= createPQExpBuffer();
1995 write_msg(NULL
, "saving large object comments\n");
1997 /* Make sure we are in proper schema */
1998 selectSourceSchema("pg_catalog");
2000 /* Cursor to get all BLOB comments */
2001 if (AH
->remoteVersion
>= 70300)
2002 blobQry
= "DECLARE blobcmt CURSOR FOR SELECT loid, "
2003 "obj_description(loid, 'pg_largeobject') "
2004 "FROM (SELECT DISTINCT loid FROM "
2005 "pg_description d JOIN pg_largeobject l ON (objoid = loid) "
2006 "WHERE classoid = 'pg_largeobject'::regclass) ss";
2007 else if (AH
->remoteVersion
>= 70200)
2008 blobQry
= "DECLARE blobcmt CURSOR FOR SELECT loid, "
2009 "obj_description(loid, 'pg_largeobject') "
2010 "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2011 else if (AH
->remoteVersion
>= 70100)
2012 blobQry
= "DECLARE blobcmt CURSOR FOR SELECT loid, "
2013 "obj_description(loid) "
2014 "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2016 blobQry
= "DECLARE blobcmt CURSOR FOR SELECT oid, "
2018 " SELECT description "
2019 " FROM pg_description pd "
2020 " WHERE pd.objoid=pc.oid "
2022 "FROM pg_class pc WHERE relkind = 'l'";
2024 res
= PQexec(g_conn
, blobQry
);
2025 check_sql_result(res
, g_conn
, blobQry
, PGRES_COMMAND_OK
);
2027 /* Command to fetch from cursor */
2028 blobFetchQry
= "FETCH 100 IN blobcmt";
2035 res
= PQexec(g_conn
, blobFetchQry
);
2036 check_sql_result(res
, g_conn
, blobFetchQry
, PGRES_TUPLES_OK
);
2038 /* Process the tuples, if any */
2039 for (i
= 0; i
< PQntuples(res
); i
++)
2044 /* ignore blobs without comments */
2045 if (PQgetisnull(res
, i
, 1))
2048 blobOid
= atooid(PQgetvalue(res
, i
, 0));
2049 comment
= PQgetvalue(res
, i
, 1);
2051 printfPQExpBuffer(commentcmd
, "COMMENT ON LARGE OBJECT %u IS ",
2053 appendStringLiteralAH(commentcmd
, comment
, AH
);
2054 appendPQExpBuffer(commentcmd
, ";\n");
2056 archputs(commentcmd
->data
, AH
);
2058 } while (PQntuples(res
) > 0);
2064 destroyPQExpBuffer(commentcmd
);
2071 * read all namespaces in the system catalogs and return them in the
2072 * NamespaceInfo* structure
2074 * numNamespaces is set to the number of namespaces read in
2077 getNamespaces(int *numNamespaces
)
2083 NamespaceInfo
*nsinfo
;
2091 * Before 7.3, there are no real namespaces; create two dummy entries, one
2092 * for user stuff and one for system stuff.
2094 if (g_fout
->remoteVersion
< 70300)
2096 nsinfo
= (NamespaceInfo
*) malloc(2 * sizeof(NamespaceInfo
));
2098 nsinfo
[0].dobj
.objType
= DO_NAMESPACE
;
2099 nsinfo
[0].dobj
.catId
.tableoid
= 0;
2100 nsinfo
[0].dobj
.catId
.oid
= 0;
2101 AssignDumpId(&nsinfo
[0].dobj
);
2102 nsinfo
[0].dobj
.name
= strdup("public");
2103 nsinfo
[0].rolname
= strdup("");
2104 nsinfo
[0].nspacl
= strdup("");
2106 selectDumpableNamespace(&nsinfo
[0]);
2108 nsinfo
[1].dobj
.objType
= DO_NAMESPACE
;
2109 nsinfo
[1].dobj
.catId
.tableoid
= 0;
2110 nsinfo
[1].dobj
.catId
.oid
= 1;
2111 AssignDumpId(&nsinfo
[1].dobj
);
2112 nsinfo
[1].dobj
.name
= strdup("pg_catalog");
2113 nsinfo
[1].rolname
= strdup("");
2114 nsinfo
[1].nspacl
= strdup("");
2116 selectDumpableNamespace(&nsinfo
[1]);
2118 g_namespaces
= nsinfo
;
2119 g_numNamespaces
= *numNamespaces
= 2;
2124 query
= createPQExpBuffer();
2126 /* Make sure we are in proper schema */
2127 selectSourceSchema("pg_catalog");
2130 * we fetch all namespaces including system ones, so that every object we
2131 * read in can be linked to a containing namespace.
2133 appendPQExpBuffer(query
, "SELECT tableoid, oid, nspname, "
2134 "(%s nspowner) AS rolname, "
2135 "nspacl FROM pg_namespace",
2138 res
= PQexec(g_conn
, query
->data
);
2139 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2141 ntups
= PQntuples(res
);
2143 nsinfo
= (NamespaceInfo
*) malloc(ntups
* sizeof(NamespaceInfo
));
2145 i_tableoid
= PQfnumber(res
, "tableoid");
2146 i_oid
= PQfnumber(res
, "oid");
2147 i_nspname
= PQfnumber(res
, "nspname");
2148 i_rolname
= PQfnumber(res
, "rolname");
2149 i_nspacl
= PQfnumber(res
, "nspacl");
2151 for (i
= 0; i
< ntups
; i
++)
2153 nsinfo
[i
].dobj
.objType
= DO_NAMESPACE
;
2154 nsinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2155 nsinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2156 AssignDumpId(&nsinfo
[i
].dobj
);
2157 nsinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_nspname
));
2158 nsinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2159 nsinfo
[i
].nspacl
= strdup(PQgetvalue(res
, i
, i_nspacl
));
2161 /* Decide whether to dump this namespace */
2162 selectDumpableNamespace(&nsinfo
[i
]);
2164 if (strlen(nsinfo
[i
].rolname
) == 0)
2165 write_msg(NULL
, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2166 nsinfo
[i
].dobj
.name
);
2170 destroyPQExpBuffer(query
);
2172 g_namespaces
= nsinfo
;
2173 g_numNamespaces
= *numNamespaces
= ntups
;
2180 * given a namespace OID and an object OID, look up the info read by
2183 * NB: for pre-7.3 source database, we use object OID to guess whether it's
2184 * a system object or not. In 7.3 and later there is no guessing.
2186 static NamespaceInfo
*
2187 findNamespace(Oid nsoid
, Oid objoid
)
2191 if (g_fout
->remoteVersion
>= 70300)
2193 for (i
= 0; i
< g_numNamespaces
; i
++)
2195 NamespaceInfo
*nsinfo
= &g_namespaces
[i
];
2197 if (nsoid
== nsinfo
->dobj
.catId
.oid
)
2200 write_msg(NULL
, "schema with OID %u does not exist\n", nsoid
);
2205 /* This code depends on the layout set up by getNamespaces. */
2206 if (objoid
> g_last_builtin_oid
)
2207 i
= 0; /* user object */
2209 i
= 1; /* system object */
2210 return &g_namespaces
[i
];
2213 return NULL
; /* keep compiler quiet */
2218 * read all types in the system catalogs and return them in the
2219 * TypeInfo* structure
2221 * numTypes is set to the number of types read in
2223 * NB: this must run after getFuncs() because we assume we can do
2227 getTypes(int *numTypes
)
2232 PQExpBuffer query
= createPQExpBuffer();
2234 ShellTypeInfo
*stinfo
;
2250 * we include even the built-in types because those may be used as array
2251 * elements by user-defined types
2253 * we filter out the built-in types when we dump out the types
2255 * same approach for undefined (shell) types and array types
2257 * Note: as of 8.3 we can reliably detect whether a type is an
2258 * auto-generated array type by checking the element type's typarray.
2259 * (Before that the test is capable of generating false positives.) We
2260 * still check for name beginning with '_', though, so as to avoid the
2261 * cost of the subselect probe for all standard types. This would have to
2262 * be revisited if the backend ever allows renaming of array types.
2265 /* Make sure we are in proper schema */
2266 selectSourceSchema("pg_catalog");
2268 if (g_fout
->remoteVersion
>= 80300)
2270 appendPQExpBuffer(query
, "SELECT tableoid, oid, typname, "
2272 "(%s typowner) AS rolname, "
2273 "typinput::oid AS typinput, "
2274 "typoutput::oid AS typoutput, typelem, typrelid, "
2275 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2276 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2277 "typtype, typisdefined, "
2278 "typname[0] = '_' AND typelem != 0 AND "
2279 "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2283 else if (g_fout
->remoteVersion
>= 70300)
2285 appendPQExpBuffer(query
, "SELECT tableoid, oid, typname, "
2287 "(%s typowner) AS rolname, "
2288 "typinput::oid AS typinput, "
2289 "typoutput::oid AS typoutput, typelem, typrelid, "
2290 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2291 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2292 "typtype, typisdefined, "
2293 "typname[0] = '_' AND typelem != 0 AS isarray "
2297 else if (g_fout
->remoteVersion
>= 70100)
2299 appendPQExpBuffer(query
, "SELECT tableoid, oid, typname, "
2300 "0::oid AS typnamespace, "
2301 "(%s typowner) AS rolname, "
2302 "typinput::oid AS typinput, "
2303 "typoutput::oid AS typoutput, typelem, typrelid, "
2304 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2305 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2306 "typtype, typisdefined, "
2307 "typname[0] = '_' AND typelem != 0 AS isarray "
2313 appendPQExpBuffer(query
, "SELECT "
2314 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2316 "0::oid AS typnamespace, "
2317 "(%s typowner) AS rolname, "
2318 "typinput::oid AS typinput, "
2319 "typoutput::oid AS typoutput, typelem, typrelid, "
2320 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2321 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2322 "typtype, typisdefined, "
2323 "typname[0] = '_' AND typelem != 0 AS isarray "
2328 res
= PQexec(g_conn
, query
->data
);
2329 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2331 ntups
= PQntuples(res
);
2333 tinfo
= (TypeInfo
*) malloc(ntups
* sizeof(TypeInfo
));
2335 i_tableoid
= PQfnumber(res
, "tableoid");
2336 i_oid
= PQfnumber(res
, "oid");
2337 i_typname
= PQfnumber(res
, "typname");
2338 i_typnamespace
= PQfnumber(res
, "typnamespace");
2339 i_rolname
= PQfnumber(res
, "rolname");
2340 i_typinput
= PQfnumber(res
, "typinput");
2341 i_typoutput
= PQfnumber(res
, "typoutput");
2342 i_typelem
= PQfnumber(res
, "typelem");
2343 i_typrelid
= PQfnumber(res
, "typrelid");
2344 i_typrelkind
= PQfnumber(res
, "typrelkind");
2345 i_typtype
= PQfnumber(res
, "typtype");
2346 i_typisdefined
= PQfnumber(res
, "typisdefined");
2347 i_isarray
= PQfnumber(res
, "isarray");
2349 for (i
= 0; i
< ntups
; i
++)
2351 tinfo
[i
].dobj
.objType
= DO_TYPE
;
2352 tinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2353 tinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2354 AssignDumpId(&tinfo
[i
].dobj
);
2355 tinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_typname
));
2356 tinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_typnamespace
)),
2357 tinfo
[i
].dobj
.catId
.oid
);
2358 tinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2359 tinfo
[i
].typelem
= atooid(PQgetvalue(res
, i
, i_typelem
));
2360 tinfo
[i
].typrelid
= atooid(PQgetvalue(res
, i
, i_typrelid
));
2361 tinfo
[i
].typrelkind
= *PQgetvalue(res
, i
, i_typrelkind
);
2362 tinfo
[i
].typtype
= *PQgetvalue(res
, i
, i_typtype
);
2363 tinfo
[i
].shellType
= NULL
;
2365 if (strcmp(PQgetvalue(res
, i
, i_typisdefined
), "t") == 0)
2366 tinfo
[i
].isDefined
= true;
2368 tinfo
[i
].isDefined
= false;
2370 if (strcmp(PQgetvalue(res
, i
, i_isarray
), "t") == 0)
2371 tinfo
[i
].isArray
= true;
2373 tinfo
[i
].isArray
= false;
2375 /* Decide whether we want to dump it */
2376 selectDumpableType(&tinfo
[i
]);
2379 * If it's a domain, fetch info about its constraints, if any
2381 tinfo
[i
].nDomChecks
= 0;
2382 tinfo
[i
].domChecks
= NULL
;
2383 if (tinfo
[i
].dobj
.dump
&& tinfo
[i
].typtype
== TYPTYPE_DOMAIN
)
2384 getDomainConstraints(&(tinfo
[i
]));
2387 * If it's a base type, make a DumpableObject representing a shell
2388 * definition of the type. We will need to dump that ahead of the I/O
2389 * functions for the type.
2391 * Note: the shell type doesn't have a catId. You might think it
2392 * should copy the base type's catId, but then it might capture the
2393 * pg_depend entries for the type, which we don't want.
2395 if (tinfo
[i
].dobj
.dump
&& tinfo
[i
].typtype
== TYPTYPE_BASE
)
2397 stinfo
= (ShellTypeInfo
*) malloc(sizeof(ShellTypeInfo
));
2398 stinfo
->dobj
.objType
= DO_SHELL_TYPE
;
2399 stinfo
->dobj
.catId
= nilCatalogId
;
2400 AssignDumpId(&stinfo
->dobj
);
2401 stinfo
->dobj
.name
= strdup(tinfo
[i
].dobj
.name
);
2402 stinfo
->dobj
.namespace = tinfo
[i
].dobj
.namespace;
2403 stinfo
->baseType
= &(tinfo
[i
]);
2404 tinfo
[i
].shellType
= stinfo
;
2407 * Initially mark the shell type as not to be dumped. We'll only
2408 * dump it if the I/O functions need to be dumped; this is taken
2409 * care of while sorting dependencies.
2411 stinfo
->dobj
.dump
= false;
2414 * However, if dumping from pre-7.3, there will be no dependency
2415 * info so we have to fake it here. We only need to worry about
2416 * typinput and typoutput since the other functions only exist
2419 if (g_fout
->remoteVersion
< 70300)
2425 typinput
= atooid(PQgetvalue(res
, i
, i_typinput
));
2426 typoutput
= atooid(PQgetvalue(res
, i
, i_typoutput
));
2428 funcInfo
= findFuncByOid(typinput
);
2429 if (funcInfo
&& funcInfo
->dobj
.dump
)
2431 /* base type depends on function */
2432 addObjectDependency(&tinfo
[i
].dobj
,
2433 funcInfo
->dobj
.dumpId
);
2434 /* function depends on shell type */
2435 addObjectDependency(&funcInfo
->dobj
,
2436 stinfo
->dobj
.dumpId
);
2437 /* mark shell type as to be dumped */
2438 stinfo
->dobj
.dump
= true;
2441 funcInfo
= findFuncByOid(typoutput
);
2442 if (funcInfo
&& funcInfo
->dobj
.dump
)
2444 /* base type depends on function */
2445 addObjectDependency(&tinfo
[i
].dobj
,
2446 funcInfo
->dobj
.dumpId
);
2447 /* function depends on shell type */
2448 addObjectDependency(&funcInfo
->dobj
,
2449 stinfo
->dobj
.dumpId
);
2450 /* mark shell type as to be dumped */
2451 stinfo
->dobj
.dump
= true;
2456 if (strlen(tinfo
[i
].rolname
) == 0 && tinfo
[i
].isDefined
)
2457 write_msg(NULL
, "WARNING: owner of data type \"%s\" appears to be invalid\n",
2458 tinfo
[i
].dobj
.name
);
2465 destroyPQExpBuffer(query
);
2472 * read all operators in the system catalogs and return them in the
2473 * OprInfo* structure
2475 * numOprs is set to the number of operators read in
2478 getOperators(int *numOprs
)
2483 PQExpBuffer query
= createPQExpBuffer();
2493 * find all operators, including builtin operators; we filter out
2494 * system-defined operators at dump-out time.
2497 /* Make sure we are in proper schema */
2498 selectSourceSchema("pg_catalog");
2500 if (g_fout
->remoteVersion
>= 70300)
2502 appendPQExpBuffer(query
, "SELECT tableoid, oid, oprname, "
2504 "(%s oprowner) AS rolname, "
2505 "oprcode::oid AS oprcode "
2509 else if (g_fout
->remoteVersion
>= 70100)
2511 appendPQExpBuffer(query
, "SELECT tableoid, oid, oprname, "
2512 "0::oid AS oprnamespace, "
2513 "(%s oprowner) AS rolname, "
2514 "oprcode::oid AS oprcode "
2520 appendPQExpBuffer(query
, "SELECT "
2521 "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2523 "0::oid AS oprnamespace, "
2524 "(%s oprowner) AS rolname, "
2525 "oprcode::oid AS oprcode "
2530 res
= PQexec(g_conn
, query
->data
);
2531 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2533 ntups
= PQntuples(res
);
2536 oprinfo
= (OprInfo
*) malloc(ntups
* sizeof(OprInfo
));
2538 i_tableoid
= PQfnumber(res
, "tableoid");
2539 i_oid
= PQfnumber(res
, "oid");
2540 i_oprname
= PQfnumber(res
, "oprname");
2541 i_oprnamespace
= PQfnumber(res
, "oprnamespace");
2542 i_rolname
= PQfnumber(res
, "rolname");
2543 i_oprcode
= PQfnumber(res
, "oprcode");
2545 for (i
= 0; i
< ntups
; i
++)
2547 oprinfo
[i
].dobj
.objType
= DO_OPERATOR
;
2548 oprinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2549 oprinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2550 AssignDumpId(&oprinfo
[i
].dobj
);
2551 oprinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_oprname
));
2552 oprinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_oprnamespace
)),
2553 oprinfo
[i
].dobj
.catId
.oid
);
2554 oprinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2555 oprinfo
[i
].oprcode
= atooid(PQgetvalue(res
, i
, i_oprcode
));
2557 /* Decide whether we want to dump it */
2558 selectDumpableObject(&(oprinfo
[i
].dobj
));
2560 if (strlen(oprinfo
[i
].rolname
) == 0)
2561 write_msg(NULL
, "WARNING: owner of operator \"%s\" appears to be invalid\n",
2562 oprinfo
[i
].dobj
.name
);
2567 destroyPQExpBuffer(query
);
2574 * read all conversions in the system catalogs and return them in the
2575 * ConvInfo* structure
2577 * numConversions is set to the number of conversions read in
2580 getConversions(int *numConversions
)
2585 PQExpBuffer query
= createPQExpBuffer();
2593 /* Conversions didn't exist pre-7.3 */
2594 if (g_fout
->remoteVersion
< 70300)
2596 *numConversions
= 0;
2601 * find all conversions, including builtin conversions; we filter out
2602 * system-defined conversions at dump-out time.
2605 /* Make sure we are in proper schema */
2606 selectSourceSchema("pg_catalog");
2608 appendPQExpBuffer(query
, "SELECT tableoid, oid, conname, "
2610 "(%s conowner) AS rolname "
2611 "FROM pg_conversion",
2614 res
= PQexec(g_conn
, query
->data
);
2615 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2617 ntups
= PQntuples(res
);
2618 *numConversions
= ntups
;
2620 convinfo
= (ConvInfo
*) malloc(ntups
* sizeof(ConvInfo
));
2622 i_tableoid
= PQfnumber(res
, "tableoid");
2623 i_oid
= PQfnumber(res
, "oid");
2624 i_conname
= PQfnumber(res
, "conname");
2625 i_connamespace
= PQfnumber(res
, "connamespace");
2626 i_rolname
= PQfnumber(res
, "rolname");
2628 for (i
= 0; i
< ntups
; i
++)
2630 convinfo
[i
].dobj
.objType
= DO_CONVERSION
;
2631 convinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2632 convinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2633 AssignDumpId(&convinfo
[i
].dobj
);
2634 convinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_conname
));
2635 convinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_connamespace
)),
2636 convinfo
[i
].dobj
.catId
.oid
);
2637 convinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2639 /* Decide whether we want to dump it */
2640 selectDumpableObject(&(convinfo
[i
].dobj
));
2645 destroyPQExpBuffer(query
);
2652 * read all opclasses in the system catalogs and return them in the
2653 * OpclassInfo* structure
2655 * numOpclasses is set to the number of opclasses read in
2658 getOpclasses(int *numOpclasses
)
2663 PQExpBuffer query
= createPQExpBuffer();
2664 OpclassInfo
*opcinfo
;
2672 * find all opclasses, including builtin opclasses; we filter out
2673 * system-defined opclasses at dump-out time.
2676 /* Make sure we are in proper schema */
2677 selectSourceSchema("pg_catalog");
2679 if (g_fout
->remoteVersion
>= 70300)
2681 appendPQExpBuffer(query
, "SELECT tableoid, oid, opcname, "
2683 "(%s opcowner) AS rolname "
2687 else if (g_fout
->remoteVersion
>= 70100)
2689 appendPQExpBuffer(query
, "SELECT tableoid, oid, opcname, "
2690 "0::oid AS opcnamespace, "
2691 "''::name AS rolname "
2696 appendPQExpBuffer(query
, "SELECT "
2697 "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2699 "0::oid AS opcnamespace, "
2700 "''::name AS rolname "
2704 res
= PQexec(g_conn
, query
->data
);
2705 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2707 ntups
= PQntuples(res
);
2708 *numOpclasses
= ntups
;
2710 opcinfo
= (OpclassInfo
*) malloc(ntups
* sizeof(OpclassInfo
));
2712 i_tableoid
= PQfnumber(res
, "tableoid");
2713 i_oid
= PQfnumber(res
, "oid");
2714 i_opcname
= PQfnumber(res
, "opcname");
2715 i_opcnamespace
= PQfnumber(res
, "opcnamespace");
2716 i_rolname
= PQfnumber(res
, "rolname");
2718 for (i
= 0; i
< ntups
; i
++)
2720 opcinfo
[i
].dobj
.objType
= DO_OPCLASS
;
2721 opcinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2722 opcinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2723 AssignDumpId(&opcinfo
[i
].dobj
);
2724 opcinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_opcname
));
2725 opcinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_opcnamespace
)),
2726 opcinfo
[i
].dobj
.catId
.oid
);
2727 opcinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2729 /* Decide whether we want to dump it */
2730 selectDumpableObject(&(opcinfo
[i
].dobj
));
2732 if (g_fout
->remoteVersion
>= 70300)
2734 if (strlen(opcinfo
[i
].rolname
) == 0)
2735 write_msg(NULL
, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2736 opcinfo
[i
].dobj
.name
);
2742 destroyPQExpBuffer(query
);
2749 * read all opfamilies in the system catalogs and return them in the
2750 * OpfamilyInfo* structure
2752 * numOpfamilies is set to the number of opfamilies read in
2755 getOpfamilies(int *numOpfamilies
)
2761 OpfamilyInfo
*opfinfo
;
2768 /* Before 8.3, there is no separate concept of opfamilies */
2769 if (g_fout
->remoteVersion
< 80300)
2775 query
= createPQExpBuffer();
2778 * find all opfamilies, including builtin opfamilies; we filter out
2779 * system-defined opfamilies at dump-out time.
2782 /* Make sure we are in proper schema */
2783 selectSourceSchema("pg_catalog");
2785 appendPQExpBuffer(query
, "SELECT tableoid, oid, opfname, "
2787 "(%s opfowner) AS rolname "
2791 res
= PQexec(g_conn
, query
->data
);
2792 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2794 ntups
= PQntuples(res
);
2795 *numOpfamilies
= ntups
;
2797 opfinfo
= (OpfamilyInfo
*) malloc(ntups
* sizeof(OpfamilyInfo
));
2799 i_tableoid
= PQfnumber(res
, "tableoid");
2800 i_oid
= PQfnumber(res
, "oid");
2801 i_opfname
= PQfnumber(res
, "opfname");
2802 i_opfnamespace
= PQfnumber(res
, "opfnamespace");
2803 i_rolname
= PQfnumber(res
, "rolname");
2805 for (i
= 0; i
< ntups
; i
++)
2807 opfinfo
[i
].dobj
.objType
= DO_OPFAMILY
;
2808 opfinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2809 opfinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2810 AssignDumpId(&opfinfo
[i
].dobj
);
2811 opfinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_opfname
));
2812 opfinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_opfnamespace
)),
2813 opfinfo
[i
].dobj
.catId
.oid
);
2814 opfinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2816 /* Decide whether we want to dump it */
2817 selectDumpableObject(&(opfinfo
[i
].dobj
));
2819 if (g_fout
->remoteVersion
>= 70300)
2821 if (strlen(opfinfo
[i
].rolname
) == 0)
2822 write_msg(NULL
, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
2823 opfinfo
[i
].dobj
.name
);
2829 destroyPQExpBuffer(query
);
2836 * read all the user-defined aggregates in the system catalogs and
2837 * return them in the AggInfo* structure
2839 * numAggs is set to the number of aggregates read in
2842 getAggregates(int *numAggs
)
2847 PQExpBuffer query
= createPQExpBuffer();
2858 /* Make sure we are in proper schema */
2859 selectSourceSchema("pg_catalog");
2861 /* find all user-defined aggregates */
2863 if (g_fout
->remoteVersion
>= 80200)
2865 appendPQExpBuffer(query
, "SELECT tableoid, oid, proname AS aggname, "
2866 "pronamespace AS aggnamespace, "
2867 "pronargs, proargtypes, "
2868 "(%s proowner) AS rolname, "
2872 "AND pronamespace != "
2873 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2876 else if (g_fout
->remoteVersion
>= 70300)
2878 appendPQExpBuffer(query
, "SELECT tableoid, oid, proname AS aggname, "
2879 "pronamespace AS aggnamespace, "
2880 "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
2882 "(%s proowner) AS rolname, "
2886 "AND pronamespace != "
2887 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2890 else if (g_fout
->remoteVersion
>= 70100)
2892 appendPQExpBuffer(query
, "SELECT tableoid, oid, aggname, "
2893 "0::oid AS aggnamespace, "
2894 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2895 "aggbasetype AS proargtypes, "
2896 "(%s aggowner) AS rolname, "
2898 "FROM pg_aggregate "
2899 "where oid > '%u'::oid",
2901 g_last_builtin_oid
);
2905 appendPQExpBuffer(query
, "SELECT "
2906 "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
2908 "0::oid AS aggnamespace, "
2909 "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2910 "aggbasetype AS proargtypes, "
2911 "(%s aggowner) AS rolname, "
2913 "FROM pg_aggregate "
2914 "where oid > '%u'::oid",
2916 g_last_builtin_oid
);
2919 res
= PQexec(g_conn
, query
->data
);
2920 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
2922 ntups
= PQntuples(res
);
2925 agginfo
= (AggInfo
*) malloc(ntups
* sizeof(AggInfo
));
2927 i_tableoid
= PQfnumber(res
, "tableoid");
2928 i_oid
= PQfnumber(res
, "oid");
2929 i_aggname
= PQfnumber(res
, "aggname");
2930 i_aggnamespace
= PQfnumber(res
, "aggnamespace");
2931 i_pronargs
= PQfnumber(res
, "pronargs");
2932 i_proargtypes
= PQfnumber(res
, "proargtypes");
2933 i_rolname
= PQfnumber(res
, "rolname");
2934 i_aggacl
= PQfnumber(res
, "aggacl");
2936 for (i
= 0; i
< ntups
; i
++)
2938 agginfo
[i
].aggfn
.dobj
.objType
= DO_AGG
;
2939 agginfo
[i
].aggfn
.dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
2940 agginfo
[i
].aggfn
.dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
2941 AssignDumpId(&agginfo
[i
].aggfn
.dobj
);
2942 agginfo
[i
].aggfn
.dobj
.name
= strdup(PQgetvalue(res
, i
, i_aggname
));
2943 agginfo
[i
].aggfn
.dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_aggnamespace
)),
2944 agginfo
[i
].aggfn
.dobj
.catId
.oid
);
2945 agginfo
[i
].aggfn
.rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
2946 if (strlen(agginfo
[i
].aggfn
.rolname
) == 0)
2947 write_msg(NULL
, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
2948 agginfo
[i
].aggfn
.dobj
.name
);
2949 agginfo
[i
].aggfn
.lang
= InvalidOid
; /* not currently interesting */
2950 agginfo
[i
].aggfn
.prorettype
= InvalidOid
; /* not saved */
2951 agginfo
[i
].aggfn
.proacl
= strdup(PQgetvalue(res
, i
, i_aggacl
));
2952 agginfo
[i
].aggfn
.nargs
= atoi(PQgetvalue(res
, i
, i_pronargs
));
2953 if (agginfo
[i
].aggfn
.nargs
== 0)
2954 agginfo
[i
].aggfn
.argtypes
= NULL
;
2957 agginfo
[i
].aggfn
.argtypes
= (Oid
*) malloc(agginfo
[i
].aggfn
.nargs
* sizeof(Oid
));
2958 if (g_fout
->remoteVersion
>= 70300)
2959 parseOidArray(PQgetvalue(res
, i
, i_proargtypes
),
2960 agginfo
[i
].aggfn
.argtypes
,
2961 agginfo
[i
].aggfn
.nargs
);
2963 /* it's just aggbasetype */
2964 agginfo
[i
].aggfn
.argtypes
[0] = atooid(PQgetvalue(res
, i
, i_proargtypes
));
2967 /* Decide whether we want to dump it */
2968 selectDumpableObject(&(agginfo
[i
].aggfn
.dobj
));
2973 destroyPQExpBuffer(query
);
2980 * read all the user-defined functions in the system catalogs and
2981 * return them in the FuncInfo* structure
2983 * numFuncs is set to the number of functions read in
2986 getFuncs(int *numFuncs
)
2991 PQExpBuffer query
= createPQExpBuffer();
3004 /* Make sure we are in proper schema */
3005 selectSourceSchema("pg_catalog");
3007 /* find all user-defined funcs */
3009 if (g_fout
->remoteVersion
>= 70300)
3011 appendPQExpBuffer(query
,
3012 "SELECT tableoid, oid, proname, prolang, "
3013 "pronargs, proargtypes, prorettype, proacl, "
3015 "(%s proowner) AS rolname "
3017 "WHERE NOT proisagg "
3018 "AND pronamespace != "
3019 "(SELECT oid FROM pg_namespace "
3020 "WHERE nspname = 'pg_catalog')",
3023 else if (g_fout
->remoteVersion
>= 70100)
3025 appendPQExpBuffer(query
,
3026 "SELECT tableoid, oid, proname, prolang, "
3027 "pronargs, proargtypes, prorettype, "
3028 "'{=X}' AS proacl, "
3029 "0::oid AS pronamespace, "
3030 "(%s proowner) AS rolname "
3032 "WHERE pg_proc.oid > '%u'::oid",
3034 g_last_builtin_oid
);
3038 appendPQExpBuffer(query
,
3040 "(SELECT oid FROM pg_class "
3041 " WHERE relname = 'pg_proc') AS tableoid, "
3042 "oid, proname, prolang, "
3043 "pronargs, proargtypes, prorettype, "
3044 "'{=X}' AS proacl, "
3045 "0::oid AS pronamespace, "
3046 "(%s proowner) AS rolname "
3048 "where pg_proc.oid > '%u'::oid",
3050 g_last_builtin_oid
);
3053 res
= PQexec(g_conn
, query
->data
);
3054 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
3056 ntups
= PQntuples(res
);
3060 finfo
= (FuncInfo
*) calloc(ntups
, sizeof(FuncInfo
));
3062 i_tableoid
= PQfnumber(res
, "tableoid");
3063 i_oid
= PQfnumber(res
, "oid");
3064 i_proname
= PQfnumber(res
, "proname");
3065 i_pronamespace
= PQfnumber(res
, "pronamespace");
3066 i_rolname
= PQfnumber(res
, "rolname");
3067 i_prolang
= PQfnumber(res
, "prolang");
3068 i_pronargs
= PQfnumber(res
, "pronargs");
3069 i_proargtypes
= PQfnumber(res
, "proargtypes");
3070 i_prorettype
= PQfnumber(res
, "prorettype");
3071 i_proacl
= PQfnumber(res
, "proacl");
3073 for (i
= 0; i
< ntups
; i
++)
3075 finfo
[i
].dobj
.objType
= DO_FUNC
;
3076 finfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
3077 finfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
3078 AssignDumpId(&finfo
[i
].dobj
);
3079 finfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_proname
));
3080 finfo
[i
].dobj
.namespace =
3081 findNamespace(atooid(PQgetvalue(res
, i
, i_pronamespace
)),
3082 finfo
[i
].dobj
.catId
.oid
);
3083 finfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
3084 finfo
[i
].lang
= atooid(PQgetvalue(res
, i
, i_prolang
));
3085 finfo
[i
].prorettype
= atooid(PQgetvalue(res
, i
, i_prorettype
));
3086 finfo
[i
].proacl
= strdup(PQgetvalue(res
, i
, i_proacl
));
3087 finfo
[i
].nargs
= atoi(PQgetvalue(res
, i
, i_pronargs
));
3088 if (finfo
[i
].nargs
== 0)
3089 finfo
[i
].argtypes
= NULL
;
3092 finfo
[i
].argtypes
= (Oid
*) malloc(finfo
[i
].nargs
* sizeof(Oid
));
3093 parseOidArray(PQgetvalue(res
, i
, i_proargtypes
),
3094 finfo
[i
].argtypes
, finfo
[i
].nargs
);
3097 /* Decide whether we want to dump it */
3098 selectDumpableObject(&(finfo
[i
].dobj
));
3100 if (strlen(finfo
[i
].rolname
) == 0)
3102 "WARNING: owner of function \"%s\" appears to be invalid\n",
3103 finfo
[i
].dobj
.name
);
3108 destroyPQExpBuffer(query
);
3115 * read all the user-defined tables (no indexes, no catalogs)
3116 * in the system catalogs return them in the TableInfo* structure
3118 * numTables is set to the number of tables read in
3121 getTables(int *numTables
)
3126 PQExpBuffer query
= createPQExpBuffer();
3136 int i_relhastriggers
;
3143 int i_reltablespace
;
3145 int i_toastreloptions
;
3147 /* Make sure we are in proper schema */
3148 selectSourceSchema("pg_catalog");
3151 * Find all the tables (including views and sequences).
3153 * We include system catalogs, so that we can work if a user table is
3154 * defined to inherit from a system catalog (pretty weird, but...)
3156 * We ignore tables that are not type 'r' (ordinary relation), 'S'
3157 * (sequence), 'v' (view), or 'c' (composite type).
3159 * Composite-type table entries won't be dumped as such, but we have to
3160 * make a DumpableObject for them so that we can track dependencies of the
3161 * composite type (pg_depend entries for columns of the composite type
3162 * link to the pg_class entry not the pg_type entry).
3164 * Note: in this phase we should collect only a minimal amount of
3165 * information about each table, basically just enough to decide if it is
3166 * interesting. We must fetch all tables in this phase because otherwise
3167 * we cannot correctly identify inherited columns, owned sequences, etc.
3170 if (g_fout
->remoteVersion
>= 80400)
3173 * Left join to pick up dependency info linking sequences to their
3174 * owning column, if any (note this dependency is AUTO as of 8.2)
3176 appendPQExpBuffer(query
,
3177 "SELECT c.tableoid, c.oid, c.relname, "
3178 "c.relacl, c.relkind, c.relnamespace, "
3179 "(%s c.relowner) AS rolname, "
3180 "c.relchecks, c.relhastriggers, "
3181 "c.relhasindex, c.relhasrules, c.relhasoids, "
3183 "d.refobjid AS owning_tab, "
3184 "d.refobjsubid AS owning_col, "
3185 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3186 "array_to_string(c.reloptions, ', ') AS reloptions, "
3187 "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3189 "LEFT JOIN pg_depend d ON "
3190 "(c.relkind = '%c' AND "
3191 "d.classid = c.tableoid AND d.objid = c.oid AND "
3192 "d.objsubid = 0 AND "
3193 "d.refclassid = c.tableoid AND d.deptype = 'a') "
3194 "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3195 "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3199 RELKIND_RELATION
, RELKIND_SEQUENCE
,
3200 RELKIND_VIEW
, RELKIND_COMPOSITE_TYPE
);
3202 else if (g_fout
->remoteVersion
>= 80200)
3205 * Left join to pick up dependency info linking sequences to their
3206 * owning column, if any (note this dependency is AUTO as of 8.2)
3208 appendPQExpBuffer(query
,
3209 "SELECT c.tableoid, c.oid, relname, "
3210 "relacl, relkind, relnamespace, "
3211 "(%s relowner) AS rolname, "
3212 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3213 "relhasindex, relhasrules, relhasoids, "
3215 "d.refobjid AS owning_tab, "
3216 "d.refobjsubid AS owning_col, "
3217 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3218 "array_to_string(c.reloptions, ', ') AS reloptions, "
3219 "NULL AS toast_reloptions "
3221 "LEFT JOIN pg_depend d ON "
3222 "(c.relkind = '%c' AND "
3223 "d.classid = c.tableoid AND d.objid = c.oid AND "
3224 "d.objsubid = 0 AND "
3225 "d.refclassid = c.tableoid AND d.deptype = 'a') "
3226 "WHERE relkind in ('%c', '%c', '%c', '%c') "
3230 RELKIND_RELATION
, RELKIND_SEQUENCE
,
3231 RELKIND_VIEW
, RELKIND_COMPOSITE_TYPE
);
3233 else if (g_fout
->remoteVersion
>= 80000)
3236 * Left join to pick up dependency info linking sequences to their
3237 * owning column, if any
3239 appendPQExpBuffer(query
,
3240 "SELECT c.tableoid, c.oid, relname, "
3241 "relacl, relkind, relnamespace, "
3242 "(%s relowner) AS rolname, "
3243 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3244 "relhasindex, relhasrules, relhasoids, "
3245 "0 AS relfrozenxid, "
3246 "d.refobjid AS owning_tab, "
3247 "d.refobjsubid AS owning_col, "
3248 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3249 "NULL AS reloptions, "
3250 "NULL AS toast_reloptions "
3252 "LEFT JOIN pg_depend d ON "
3253 "(c.relkind = '%c' AND "
3254 "d.classid = c.tableoid AND d.objid = c.oid AND "
3255 "d.objsubid = 0 AND "
3256 "d.refclassid = c.tableoid AND d.deptype = 'i') "
3257 "WHERE relkind in ('%c', '%c', '%c', '%c') "
3261 RELKIND_RELATION
, RELKIND_SEQUENCE
,
3262 RELKIND_VIEW
, RELKIND_COMPOSITE_TYPE
);
3264 else if (g_fout
->remoteVersion
>= 70300)
3267 * Left join to pick up dependency info linking sequences to their
3268 * owning column, if any
3270 appendPQExpBuffer(query
,
3271 "SELECT c.tableoid, c.oid, relname, "
3272 "relacl, relkind, relnamespace, "
3273 "(%s relowner) AS rolname, "
3274 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3275 "relhasindex, relhasrules, relhasoids, "
3276 "0 AS relfrozenxid, "
3277 "d.refobjid AS owning_tab, "
3278 "d.refobjsubid AS owning_col, "
3279 "NULL AS reltablespace, "
3280 "NULL AS reloptions, "
3281 "NULL AS toast_reloptions "
3283 "LEFT JOIN pg_depend d ON "
3284 "(c.relkind = '%c' AND "
3285 "d.classid = c.tableoid AND d.objid = c.oid AND "
3286 "d.objsubid = 0 AND "
3287 "d.refclassid = c.tableoid AND d.deptype = 'i') "
3288 "WHERE relkind IN ('%c', '%c', '%c', '%c') "
3292 RELKIND_RELATION
, RELKIND_SEQUENCE
,
3293 RELKIND_VIEW
, RELKIND_COMPOSITE_TYPE
);
3295 else if (g_fout
->remoteVersion
>= 70200)
3297 appendPQExpBuffer(query
,
3298 "SELECT tableoid, oid, relname, relacl, relkind, "
3299 "0::oid AS relnamespace, "
3300 "(%s relowner) AS rolname, "
3301 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3302 "relhasindex, relhasrules, relhasoids, "
3303 "0 AS relfrozenxid, "
3304 "NULL::oid AS owning_tab, "
3305 "NULL::int4 AS owning_col, "
3306 "NULL AS reltablespace, "
3307 "NULL AS reloptions, "
3308 "NULL AS toast_reloptions "
3310 "WHERE relkind IN ('%c', '%c', '%c') "
3313 RELKIND_RELATION
, RELKIND_SEQUENCE
, RELKIND_VIEW
);
3315 else if (g_fout
->remoteVersion
>= 70100)
3317 /* all tables have oids in 7.1 */
3318 appendPQExpBuffer(query
,
3319 "SELECT tableoid, oid, relname, relacl, relkind, "
3320 "0::oid AS relnamespace, "
3321 "(%s relowner) AS rolname, "
3322 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3323 "relhasindex, relhasrules, "
3324 "'t'::bool AS relhasoids, "
3325 "0 AS relfrozenxid, "
3326 "NULL::oid AS owning_tab, "
3327 "NULL::int4 AS owning_col, "
3328 "NULL AS reltablespace, "
3329 "NULL AS reloptions, "
3330 "NULL AS toast_reloptions "
3332 "WHERE relkind IN ('%c', '%c', '%c') "
3335 RELKIND_RELATION
, RELKIND_SEQUENCE
, RELKIND_VIEW
);
3340 * Before 7.1, view relkind was not set to 'v', so we must check if we
3341 * have a view by looking for a rule in pg_rewrite.
3343 appendPQExpBuffer(query
,
3345 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3346 "oid, relname, relacl, "
3347 "CASE WHEN relhasrules and relkind = 'r' "
3348 " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
3349 " r.ev_class = c.oid AND r.ev_type = '1') "
3350 "THEN '%c'::\"char\" "
3351 "ELSE relkind END AS relkind,"
3352 "0::oid AS relnamespace, "
3353 "(%s relowner) AS rolname, "
3354 "relchecks, (reltriggers <> 0) AS relhastriggers, "
3355 "relhasindex, relhasrules, "
3356 "'t'::bool AS relhasoids, "
3357 "0 as relfrozenxid, "
3358 "NULL::oid AS owning_tab, "
3359 "NULL::int4 AS owning_col, "
3360 "NULL AS reltablespace, "
3361 "NULL AS reloptions, "
3362 "NULL AS toast_reloptions "
3364 "WHERE relkind IN ('%c', '%c') "
3368 RELKIND_RELATION
, RELKIND_SEQUENCE
);
3371 res
= PQexec(g_conn
, query
->data
);
3372 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
3374 ntups
= PQntuples(res
);
3379 * Extract data from result and lock dumpable tables. We do the locking
3380 * before anything else, to minimize the window wherein a table could
3381 * disappear under us.
3383 * Note that we have to save info about all tables here, even when dumping
3384 * only one, because we don't yet know which tables might be inheritance
3385 * ancestors of the target table.
3387 tblinfo
= (TableInfo
*) calloc(ntups
, sizeof(TableInfo
));
3389 i_reltableoid
= PQfnumber(res
, "tableoid");
3390 i_reloid
= PQfnumber(res
, "oid");
3391 i_relname
= PQfnumber(res
, "relname");
3392 i_relnamespace
= PQfnumber(res
, "relnamespace");
3393 i_relacl
= PQfnumber(res
, "relacl");
3394 i_relkind
= PQfnumber(res
, "relkind");
3395 i_rolname
= PQfnumber(res
, "rolname");
3396 i_relchecks
= PQfnumber(res
, "relchecks");
3397 i_relhastriggers
= PQfnumber(res
, "relhastriggers");
3398 i_relhasindex
= PQfnumber(res
, "relhasindex");
3399 i_relhasrules
= PQfnumber(res
, "relhasrules");
3400 i_relhasoids
= PQfnumber(res
, "relhasoids");
3401 i_relfrozenxid
= PQfnumber(res
, "relfrozenxid");
3402 i_owning_tab
= PQfnumber(res
, "owning_tab");
3403 i_owning_col
= PQfnumber(res
, "owning_col");
3404 i_reltablespace
= PQfnumber(res
, "reltablespace");
3405 i_reloptions
= PQfnumber(res
, "reloptions");
3406 i_toastreloptions
= PQfnumber(res
, "toast_reloptions");
3408 if (lockWaitTimeout
&& g_fout
->remoteVersion
>= 70300)
3411 * Arrange to fail instead of waiting forever for a table lock.
3413 * NB: this coding assumes that the only queries issued within the
3414 * following loop are LOCK TABLEs; else the timeout may be undesirably
3415 * applied to other things too.
3417 resetPQExpBuffer(query
);
3418 appendPQExpBuffer(query
, "SET statement_timeout = ");
3419 appendStringLiteralConn(query
, lockWaitTimeout
, g_conn
);
3420 do_sql_command(g_conn
, query
->data
);
3423 for (i
= 0; i
< ntups
; i
++)
3425 tblinfo
[i
].dobj
.objType
= DO_TABLE
;
3426 tblinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_reltableoid
));
3427 tblinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_reloid
));
3428 AssignDumpId(&tblinfo
[i
].dobj
);
3429 tblinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_relname
));
3430 tblinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_relnamespace
)),
3431 tblinfo
[i
].dobj
.catId
.oid
);
3432 tblinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
3433 tblinfo
[i
].relacl
= strdup(PQgetvalue(res
, i
, i_relacl
));
3434 tblinfo
[i
].relkind
= *(PQgetvalue(res
, i
, i_relkind
));
3435 tblinfo
[i
].hasindex
= (strcmp(PQgetvalue(res
, i
, i_relhasindex
), "t") == 0);
3436 tblinfo
[i
].hasrules
= (strcmp(PQgetvalue(res
, i
, i_relhasrules
), "t") == 0);
3437 tblinfo
[i
].hastriggers
= (strcmp(PQgetvalue(res
, i
, i_relhastriggers
), "t") == 0);
3438 tblinfo
[i
].hasoids
= (strcmp(PQgetvalue(res
, i
, i_relhasoids
), "t") == 0);
3439 tblinfo
[i
].frozenxid
= atooid(PQgetvalue(res
, i
, i_relfrozenxid
));
3440 tblinfo
[i
].ncheck
= atoi(PQgetvalue(res
, i
, i_relchecks
));
3441 if (PQgetisnull(res
, i
, i_owning_tab
))
3443 tblinfo
[i
].owning_tab
= InvalidOid
;
3444 tblinfo
[i
].owning_col
= 0;
3448 tblinfo
[i
].owning_tab
= atooid(PQgetvalue(res
, i
, i_owning_tab
));
3449 tblinfo
[i
].owning_col
= atoi(PQgetvalue(res
, i
, i_owning_col
));
3451 tblinfo
[i
].reltablespace
= strdup(PQgetvalue(res
, i
, i_reltablespace
));
3452 tblinfo
[i
].reloptions
= strdup(PQgetvalue(res
, i
, i_reloptions
));
3453 tblinfo
[i
].toast_reloptions
= strdup(PQgetvalue(res
, i
, i_toastreloptions
));
3455 /* other fields were zeroed above */
3458 * Decide whether we want to dump this table.
3460 if (tblinfo
[i
].relkind
== RELKIND_COMPOSITE_TYPE
)
3461 tblinfo
[i
].dobj
.dump
= false;
3463 selectDumpableTable(&tblinfo
[i
]);
3464 tblinfo
[i
].interesting
= tblinfo
[i
].dobj
.dump
;
3467 * Read-lock target tables to make sure they aren't DROPPED or altered
3468 * in schema before we get around to dumping them.
3470 * Note that we don't explicitly lock parents of the target tables; we
3471 * assume our lock on the child is enough to prevent schema
3472 * alterations to parent tables.
3474 * NOTE: it'd be kinda nice to lock views and sequences too, not only
3475 * plain tables, but the backend doesn't presently allow that.
3477 if (tblinfo
[i
].dobj
.dump
&& tblinfo
[i
].relkind
== RELKIND_RELATION
)
3479 resetPQExpBuffer(query
);
3480 appendPQExpBuffer(query
,
3481 "LOCK TABLE %s IN ACCESS SHARE MODE",
3482 fmtQualifiedId(tblinfo
[i
].dobj
.namespace->dobj
.name
,
3483 tblinfo
[i
].dobj
.name
));
3484 do_sql_command(g_conn
, query
->data
);
3487 /* Emit notice if join for owner failed */
3488 if (strlen(tblinfo
[i
].rolname
) == 0)
3489 write_msg(NULL
, "WARNING: owner of table \"%s\" appears to be invalid\n",
3490 tblinfo
[i
].dobj
.name
);
3493 if (lockWaitTimeout
&& g_fout
->remoteVersion
>= 70300)
3495 do_sql_command(g_conn
, "SET statement_timeout = 0");
3501 * Force sequences that are "owned" by table columns to be dumped whenever
3502 * their owning table is being dumped.
3504 for (i
= 0; i
< ntups
; i
++)
3506 TableInfo
*seqinfo
= &tblinfo
[i
];
3509 if (!OidIsValid(seqinfo
->owning_tab
))
3510 continue; /* not an owned sequence */
3511 if (seqinfo
->dobj
.dump
)
3512 continue; /* no need to search */
3514 /* can't use findTableByOid yet, unfortunately */
3515 for (j
= 0; j
< ntups
; j
++)
3517 if (tblinfo
[j
].dobj
.catId
.oid
== seqinfo
->owning_tab
)
3519 if (tblinfo
[j
].dobj
.dump
)
3521 seqinfo
->interesting
= true;
3522 seqinfo
->dobj
.dump
= true;
3529 destroyPQExpBuffer(query
);
3536 * read all the inheritance information
3537 * from the system catalogs return them in the InhInfo* structure
3539 * numInherits is set to the number of pairs read in
3542 getInherits(int *numInherits
)
3547 PQExpBuffer query
= createPQExpBuffer();
3553 /* Make sure we are in proper schema */
3554 selectSourceSchema("pg_catalog");
3556 /* find all the inheritance information */
3558 appendPQExpBuffer(query
, "SELECT inhrelid, inhparent FROM pg_inherits");
3560 res
= PQexec(g_conn
, query
->data
);
3561 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
3563 ntups
= PQntuples(res
);
3565 *numInherits
= ntups
;
3567 inhinfo
= (InhInfo
*) malloc(ntups
* sizeof(InhInfo
));
3569 i_inhrelid
= PQfnumber(res
, "inhrelid");
3570 i_inhparent
= PQfnumber(res
, "inhparent");
3572 for (i
= 0; i
< ntups
; i
++)
3574 inhinfo
[i
].inhrelid
= atooid(PQgetvalue(res
, i
, i_inhrelid
));
3575 inhinfo
[i
].inhparent
= atooid(PQgetvalue(res
, i
, i_inhparent
));
3580 destroyPQExpBuffer(query
);
3587 * get information about every index on a dumpable table
3589 * Note: index data is not returned directly to the caller, but it
3590 * does get entered into the DumpableObject tables.
3593 getIndexes(TableInfo tblinfo
[], int numTables
)
3597 PQExpBuffer query
= createPQExpBuffer();
3600 ConstraintInfo
*constrinfo
;
3616 for (i
= 0; i
< numTables
; i
++)
3618 TableInfo
*tbinfo
= &tblinfo
[i
];
3620 /* Only plain tables have indexes */
3621 if (tbinfo
->relkind
!= RELKIND_RELATION
|| !tbinfo
->hasindex
)
3624 /* Ignore indexes of tables not to be dumped */
3625 if (!tbinfo
->dobj
.dump
)
3629 write_msg(NULL
, "reading indexes for table \"%s\"\n",
3632 /* Make sure we are in proper schema so indexdef is right */
3633 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
3636 * The point of the messy-looking outer join is to find a constraint
3637 * that is related by an internal dependency link to the index. If we
3638 * find one, create a CONSTRAINT entry linked to the INDEX entry. We
3639 * assume an index won't have more than one internal dependency.
3641 resetPQExpBuffer(query
);
3642 if (g_fout
->remoteVersion
>= 80200)
3644 appendPQExpBuffer(query
,
3645 "SELECT t.tableoid, t.oid, "
3646 "t.relname AS indexname, "
3647 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3648 "t.relnatts AS indnkeys, "
3649 "i.indkey, i.indisclustered, "
3650 "c.contype, c.conname, "
3651 "c.tableoid AS contableoid, "
3653 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3654 "array_to_string(t.reloptions, ', ') AS options "
3655 "FROM pg_catalog.pg_index i "
3656 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3657 "LEFT JOIN pg_catalog.pg_depend d "
3658 "ON (d.classid = t.tableoid "
3659 "AND d.objid = t.oid "
3660 "AND d.deptype = 'i') "
3661 "LEFT JOIN pg_catalog.pg_constraint c "
3662 "ON (d.refclassid = c.tableoid "
3663 "AND d.refobjid = c.oid) "
3664 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3665 "ORDER BY indexname",
3666 tbinfo
->dobj
.catId
.oid
);
3668 else if (g_fout
->remoteVersion
>= 80000)
3670 appendPQExpBuffer(query
,
3671 "SELECT t.tableoid, t.oid, "
3672 "t.relname AS indexname, "
3673 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3674 "t.relnatts AS indnkeys, "
3675 "i.indkey, i.indisclustered, "
3676 "c.contype, c.conname, "
3677 "c.tableoid AS contableoid, "
3679 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3681 "FROM pg_catalog.pg_index i "
3682 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3683 "LEFT JOIN pg_catalog.pg_depend d "
3684 "ON (d.classid = t.tableoid "
3685 "AND d.objid = t.oid "
3686 "AND d.deptype = 'i') "
3687 "LEFT JOIN pg_catalog.pg_constraint c "
3688 "ON (d.refclassid = c.tableoid "
3689 "AND d.refobjid = c.oid) "
3690 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3691 "ORDER BY indexname",
3692 tbinfo
->dobj
.catId
.oid
);
3694 else if (g_fout
->remoteVersion
>= 70300)
3696 appendPQExpBuffer(query
,
3697 "SELECT t.tableoid, t.oid, "
3698 "t.relname AS indexname, "
3699 "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3700 "t.relnatts AS indnkeys, "
3701 "i.indkey, i.indisclustered, "
3702 "c.contype, c.conname, "
3703 "c.tableoid AS contableoid, "
3705 "NULL AS tablespace, "
3707 "FROM pg_catalog.pg_index i "
3708 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3709 "LEFT JOIN pg_catalog.pg_depend d "
3710 "ON (d.classid = t.tableoid "
3711 "AND d.objid = t.oid "
3712 "AND d.deptype = 'i') "
3713 "LEFT JOIN pg_catalog.pg_constraint c "
3714 "ON (d.refclassid = c.tableoid "
3715 "AND d.refobjid = c.oid) "
3716 "WHERE i.indrelid = '%u'::pg_catalog.oid "
3717 "ORDER BY indexname",
3718 tbinfo
->dobj
.catId
.oid
);
3720 else if (g_fout
->remoteVersion
>= 70100)
3722 appendPQExpBuffer(query
,
3723 "SELECT t.tableoid, t.oid, "
3724 "t.relname AS indexname, "
3725 "pg_get_indexdef(i.indexrelid) AS indexdef, "
3726 "t.relnatts AS indnkeys, "
3727 "i.indkey, false AS indisclustered, "
3728 "CASE WHEN i.indisprimary THEN 'p'::char "
3729 "ELSE '0'::char END AS contype, "
3730 "t.relname AS conname, "
3731 "0::oid AS contableoid, "
3733 "NULL AS tablespace, "
3735 "FROM pg_index i, pg_class t "
3736 "WHERE t.oid = i.indexrelid "
3737 "AND i.indrelid = '%u'::oid "
3738 "ORDER BY indexname",
3739 tbinfo
->dobj
.catId
.oid
);
3743 appendPQExpBuffer(query
,
3745 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3747 "t.relname AS indexname, "
3748 "pg_get_indexdef(i.indexrelid) AS indexdef, "
3749 "t.relnatts AS indnkeys, "
3750 "i.indkey, false AS indisclustered, "
3751 "CASE WHEN i.indisprimary THEN 'p'::char "
3752 "ELSE '0'::char END AS contype, "
3753 "t.relname AS conname, "
3754 "0::oid AS contableoid, "
3756 "NULL AS tablespace, "
3758 "FROM pg_index i, pg_class t "
3759 "WHERE t.oid = i.indexrelid "
3760 "AND i.indrelid = '%u'::oid "
3761 "ORDER BY indexname",
3762 tbinfo
->dobj
.catId
.oid
);
3765 res
= PQexec(g_conn
, query
->data
);
3766 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
3768 ntups
= PQntuples(res
);
3770 i_tableoid
= PQfnumber(res
, "tableoid");
3771 i_oid
= PQfnumber(res
, "oid");
3772 i_indexname
= PQfnumber(res
, "indexname");
3773 i_indexdef
= PQfnumber(res
, "indexdef");
3774 i_indnkeys
= PQfnumber(res
, "indnkeys");
3775 i_indkey
= PQfnumber(res
, "indkey");
3776 i_indisclustered
= PQfnumber(res
, "indisclustered");
3777 i_contype
= PQfnumber(res
, "contype");
3778 i_conname
= PQfnumber(res
, "conname");
3779 i_contableoid
= PQfnumber(res
, "contableoid");
3780 i_conoid
= PQfnumber(res
, "conoid");
3781 i_tablespace
= PQfnumber(res
, "tablespace");
3782 i_options
= PQfnumber(res
, "options");
3784 indxinfo
= (IndxInfo
*) malloc(ntups
* sizeof(IndxInfo
));
3785 constrinfo
= (ConstraintInfo
*) malloc(ntups
* sizeof(ConstraintInfo
));
3787 for (j
= 0; j
< ntups
; j
++)
3791 indxinfo
[j
].dobj
.objType
= DO_INDEX
;
3792 indxinfo
[j
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, j
, i_tableoid
));
3793 indxinfo
[j
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, j
, i_oid
));
3794 AssignDumpId(&indxinfo
[j
].dobj
);
3795 indxinfo
[j
].dobj
.name
= strdup(PQgetvalue(res
, j
, i_indexname
));
3796 indxinfo
[j
].dobj
.namespace = tbinfo
->dobj
.namespace;
3797 indxinfo
[j
].indextable
= tbinfo
;
3798 indxinfo
[j
].indexdef
= strdup(PQgetvalue(res
, j
, i_indexdef
));
3799 indxinfo
[j
].indnkeys
= atoi(PQgetvalue(res
, j
, i_indnkeys
));
3800 indxinfo
[j
].tablespace
= strdup(PQgetvalue(res
, j
, i_tablespace
));
3801 indxinfo
[j
].options
= strdup(PQgetvalue(res
, j
, i_options
));
3804 * In pre-7.4 releases, indkeys may contain more entries than
3805 * indnkeys says (since indnkeys will be 1 for a functional
3806 * index). We don't actually care about this case since we don't
3807 * examine indkeys except for indexes associated with PRIMARY and
3808 * UNIQUE constraints, which are never functional indexes. But we
3809 * have to allocate enough space to keep parseOidArray from
3812 indxinfo
[j
].indkeys
= (Oid
*) malloc(INDEX_MAX_KEYS
* sizeof(Oid
));
3813 parseOidArray(PQgetvalue(res
, j
, i_indkey
),
3814 indxinfo
[j
].indkeys
, INDEX_MAX_KEYS
);
3815 indxinfo
[j
].indisclustered
= (PQgetvalue(res
, j
, i_indisclustered
)[0] == 't');
3816 contype
= *(PQgetvalue(res
, j
, i_contype
));
3818 if (contype
== 'p' || contype
== 'u')
3821 * If we found a constraint matching the index, create an
3824 * In a pre-7.3 database, we take this path iff the index was
3825 * marked indisprimary.
3827 constrinfo
[j
].dobj
.objType
= DO_CONSTRAINT
;
3828 constrinfo
[j
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, j
, i_contableoid
));
3829 constrinfo
[j
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, j
, i_conoid
));
3830 AssignDumpId(&constrinfo
[j
].dobj
);
3831 constrinfo
[j
].dobj
.name
= strdup(PQgetvalue(res
, j
, i_conname
));
3832 constrinfo
[j
].dobj
.namespace = tbinfo
->dobj
.namespace;
3833 constrinfo
[j
].contable
= tbinfo
;
3834 constrinfo
[j
].condomain
= NULL
;
3835 constrinfo
[j
].contype
= contype
;
3836 constrinfo
[j
].condef
= NULL
;
3837 constrinfo
[j
].confrelid
= InvalidOid
;
3838 constrinfo
[j
].conindex
= indxinfo
[j
].dobj
.dumpId
;
3839 constrinfo
[j
].conislocal
= true;
3840 constrinfo
[j
].separate
= true;
3842 indxinfo
[j
].indexconstraint
= constrinfo
[j
].dobj
.dumpId
;
3844 /* If pre-7.3 DB, better make sure table comes first */
3845 addObjectDependency(&constrinfo
[j
].dobj
,
3846 tbinfo
->dobj
.dumpId
);
3850 /* Plain secondary index */
3851 indxinfo
[j
].indexconstraint
= 0;
3858 destroyPQExpBuffer(query
);
3864 * Get info about constraints on dumpable tables.
3866 * Currently handles foreign keys only.
3867 * Unique and primary key constraints are handled with indexes,
3868 * while check constraints are processed in getTableAttrs().
3871 getConstraints(TableInfo tblinfo
[], int numTables
)
3875 ConstraintInfo
*constrinfo
;
3885 /* pg_constraint was created in 7.3, so nothing to do if older */
3886 if (g_fout
->remoteVersion
< 70300)
3889 query
= createPQExpBuffer();
3891 for (i
= 0; i
< numTables
; i
++)
3893 TableInfo
*tbinfo
= &tblinfo
[i
];
3895 if (!tbinfo
->hastriggers
|| !tbinfo
->dobj
.dump
)
3899 write_msg(NULL
, "reading foreign key constraints for table \"%s\"\n",
3903 * select table schema to ensure constraint expr is qualified if
3906 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
3908 resetPQExpBuffer(query
);
3909 appendPQExpBuffer(query
,
3910 "SELECT tableoid, oid, conname, confrelid, "
3911 "pg_catalog.pg_get_constraintdef(oid) AS condef "
3912 "FROM pg_catalog.pg_constraint "
3913 "WHERE conrelid = '%u'::pg_catalog.oid "
3914 "AND contype = 'f'",
3915 tbinfo
->dobj
.catId
.oid
);
3916 res
= PQexec(g_conn
, query
->data
);
3917 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
3919 ntups
= PQntuples(res
);
3921 i_contableoid
= PQfnumber(res
, "tableoid");
3922 i_conoid
= PQfnumber(res
, "oid");
3923 i_conname
= PQfnumber(res
, "conname");
3924 i_confrelid
= PQfnumber(res
, "confrelid");
3925 i_condef
= PQfnumber(res
, "condef");
3927 constrinfo
= (ConstraintInfo
*) malloc(ntups
* sizeof(ConstraintInfo
));
3929 for (j
= 0; j
< ntups
; j
++)
3931 constrinfo
[j
].dobj
.objType
= DO_FK_CONSTRAINT
;
3932 constrinfo
[j
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, j
, i_contableoid
));
3933 constrinfo
[j
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, j
, i_conoid
));
3934 AssignDumpId(&constrinfo
[j
].dobj
);
3935 constrinfo
[j
].dobj
.name
= strdup(PQgetvalue(res
, j
, i_conname
));
3936 constrinfo
[j
].dobj
.namespace = tbinfo
->dobj
.namespace;
3937 constrinfo
[j
].contable
= tbinfo
;
3938 constrinfo
[j
].condomain
= NULL
;
3939 constrinfo
[j
].contype
= 'f';
3940 constrinfo
[j
].condef
= strdup(PQgetvalue(res
, j
, i_condef
));
3941 constrinfo
[j
].confrelid
= atooid(PQgetvalue(res
, j
, i_confrelid
));
3942 constrinfo
[j
].conindex
= 0;
3943 constrinfo
[j
].conislocal
= true;
3944 constrinfo
[j
].separate
= true;
3950 destroyPQExpBuffer(query
);
3954 * getDomainConstraints
3956 * Get info about constraints on a domain.
3959 getDomainConstraints(TypeInfo
*tinfo
)
3962 ConstraintInfo
*constrinfo
;
3971 /* pg_constraint was created in 7.3, so nothing to do if older */
3972 if (g_fout
->remoteVersion
< 70300)
3976 * select appropriate schema to ensure names in constraint are properly
3979 selectSourceSchema(tinfo
->dobj
.namespace->dobj
.name
);
3981 query
= createPQExpBuffer();
3983 if (g_fout
->remoteVersion
>= 70400)
3984 appendPQExpBuffer(query
, "SELECT tableoid, oid, conname, "
3985 "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3986 "FROM pg_catalog.pg_constraint "
3987 "WHERE contypid = '%u'::pg_catalog.oid "
3989 tinfo
->dobj
.catId
.oid
);
3991 appendPQExpBuffer(query
, "SELECT tableoid, oid, conname, "
3992 "'CHECK (' || consrc || ')' AS consrc "
3993 "FROM pg_catalog.pg_constraint "
3994 "WHERE contypid = '%u'::pg_catalog.oid "
3996 tinfo
->dobj
.catId
.oid
);
3998 res
= PQexec(g_conn
, query
->data
);
3999 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
4001 ntups
= PQntuples(res
);
4003 i_tableoid
= PQfnumber(res
, "tableoid");
4004 i_oid
= PQfnumber(res
, "oid");
4005 i_conname
= PQfnumber(res
, "conname");
4006 i_consrc
= PQfnumber(res
, "consrc");
4008 constrinfo
= (ConstraintInfo
*) malloc(ntups
* sizeof(ConstraintInfo
));
4010 tinfo
->nDomChecks
= ntups
;
4011 tinfo
->domChecks
= constrinfo
;
4013 for (i
= 0; i
< ntups
; i
++)
4015 constrinfo
[i
].dobj
.objType
= DO_CONSTRAINT
;
4016 constrinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
4017 constrinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
4018 AssignDumpId(&constrinfo
[i
].dobj
);
4019 constrinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_conname
));
4020 constrinfo
[i
].dobj
.namespace = tinfo
->dobj
.namespace;
4021 constrinfo
[i
].contable
= NULL
;
4022 constrinfo
[i
].condomain
= tinfo
;
4023 constrinfo
[i
].contype
= 'c';
4024 constrinfo
[i
].condef
= strdup(PQgetvalue(res
, i
, i_consrc
));
4025 constrinfo
[i
].confrelid
= InvalidOid
;
4026 constrinfo
[i
].conindex
= 0;
4027 constrinfo
[i
].conislocal
= true;
4028 constrinfo
[i
].separate
= false;
4031 * Make the domain depend on the constraint, ensuring it won't be
4032 * output till any constraint dependencies are OK.
4034 addObjectDependency(&tinfo
->dobj
,
4035 constrinfo
[i
].dobj
.dumpId
);
4040 destroyPQExpBuffer(query
);
4045 * get basic information about every rule in the system
4047 * numRules is set to the number of rules read in
4050 getRules(int *numRules
)
4055 PQExpBuffer query
= createPQExpBuffer();
4065 /* Make sure we are in proper schema */
4066 selectSourceSchema("pg_catalog");
4068 if (g_fout
->remoteVersion
>= 80300)
4070 appendPQExpBuffer(query
, "SELECT "
4071 "tableoid, oid, rulename, "
4072 "ev_class AS ruletable, ev_type, is_instead, "
4077 else if (g_fout
->remoteVersion
>= 70100)
4079 appendPQExpBuffer(query
, "SELECT "
4080 "tableoid, oid, rulename, "
4081 "ev_class AS ruletable, ev_type, is_instead, "
4082 "'O'::char AS ev_enabled "
4088 appendPQExpBuffer(query
, "SELECT "
4089 "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4091 "ev_class AS ruletable, ev_type, is_instead, "
4092 "'O'::char AS ev_enabled "
4097 res
= PQexec(g_conn
, query
->data
);
4098 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
4100 ntups
= PQntuples(res
);
4104 ruleinfo
= (RuleInfo
*) malloc(ntups
* sizeof(RuleInfo
));
4106 i_tableoid
= PQfnumber(res
, "tableoid");
4107 i_oid
= PQfnumber(res
, "oid");
4108 i_rulename
= PQfnumber(res
, "rulename");
4109 i_ruletable
= PQfnumber(res
, "ruletable");
4110 i_ev_type
= PQfnumber(res
, "ev_type");
4111 i_is_instead
= PQfnumber(res
, "is_instead");
4112 i_ev_enabled
= PQfnumber(res
, "ev_enabled");
4114 for (i
= 0; i
< ntups
; i
++)
4118 ruleinfo
[i
].dobj
.objType
= DO_RULE
;
4119 ruleinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
4120 ruleinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
4121 AssignDumpId(&ruleinfo
[i
].dobj
);
4122 ruleinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_rulename
));
4123 ruletableoid
= atooid(PQgetvalue(res
, i
, i_ruletable
));
4124 ruleinfo
[i
].ruletable
= findTableByOid(ruletableoid
);
4125 if (ruleinfo
[i
].ruletable
== NULL
)
4127 write_msg(NULL
, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4129 ruleinfo
[i
].dobj
.catId
.oid
);
4132 ruleinfo
[i
].dobj
.namespace = ruleinfo
[i
].ruletable
->dobj
.namespace;
4133 ruleinfo
[i
].dobj
.dump
= ruleinfo
[i
].ruletable
->dobj
.dump
;
4134 ruleinfo
[i
].ev_type
= *(PQgetvalue(res
, i
, i_ev_type
));
4135 ruleinfo
[i
].is_instead
= *(PQgetvalue(res
, i
, i_is_instead
)) == 't';
4136 ruleinfo
[i
].ev_enabled
= *(PQgetvalue(res
, i
, i_ev_enabled
));
4137 if (ruleinfo
[i
].ruletable
)
4140 * If the table is a view, force its ON SELECT rule to be sorted
4141 * before the view itself --- this ensures that any dependencies
4142 * for the rule affect the table's positioning. Other rules are
4143 * forced to appear after their table.
4145 if (ruleinfo
[i
].ruletable
->relkind
== RELKIND_VIEW
&&
4146 ruleinfo
[i
].ev_type
== '1' && ruleinfo
[i
].is_instead
)
4148 addObjectDependency(&ruleinfo
[i
].ruletable
->dobj
,
4149 ruleinfo
[i
].dobj
.dumpId
);
4150 /* We'll merge the rule into CREATE VIEW, if possible */
4151 ruleinfo
[i
].separate
= false;
4155 addObjectDependency(&ruleinfo
[i
].dobj
,
4156 ruleinfo
[i
].ruletable
->dobj
.dumpId
);
4157 ruleinfo
[i
].separate
= true;
4161 ruleinfo
[i
].separate
= true;
4166 destroyPQExpBuffer(query
);
4173 * get information about every trigger on a dumpable table
4175 * Note: trigger data is not returned directly to the caller, but it
4176 * does get entered into the DumpableObject tables.
4179 getTriggers(TableInfo tblinfo
[], int numTables
)
4183 PQExpBuffer query
= createPQExpBuffer();
4185 TriggerInfo
*tginfo
;
4202 for (i
= 0; i
< numTables
; i
++)
4204 TableInfo
*tbinfo
= &tblinfo
[i
];
4206 if (!tbinfo
->hastriggers
|| !tbinfo
->dobj
.dump
)
4210 write_msg(NULL
, "reading triggers for table \"%s\"\n",
4214 * select table schema to ensure regproc name is qualified if needed
4216 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
4218 resetPQExpBuffer(query
);
4219 if (g_fout
->remoteVersion
>= 80300)
4222 * We ignore triggers that are tied to a foreign-key constraint
4224 appendPQExpBuffer(query
,
4226 "tgfoid::pg_catalog.regproc AS tgfname, "
4227 "tgtype, tgnargs, tgargs, tgenabled, "
4228 "tgisconstraint, tgconstrname, tgdeferrable, "
4229 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4230 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4231 "FROM pg_catalog.pg_trigger t "
4232 "WHERE tgrelid = '%u'::pg_catalog.oid "
4233 "AND tgconstraint = 0",
4234 tbinfo
->dobj
.catId
.oid
);
4236 else if (g_fout
->remoteVersion
>= 70300)
4239 * We ignore triggers that are tied to a foreign-key constraint,
4240 * but in these versions we have to grovel through pg_constraint
4243 appendPQExpBuffer(query
,
4245 "tgfoid::pg_catalog.regproc AS tgfname, "
4246 "tgtype, tgnargs, tgargs, tgenabled, "
4247 "tgisconstraint, tgconstrname, tgdeferrable, "
4248 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4249 "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4250 "FROM pg_catalog.pg_trigger t "
4251 "WHERE tgrelid = '%u'::pg_catalog.oid "
4252 "AND (NOT tgisconstraint "
4254 " (SELECT 1 FROM pg_catalog.pg_depend d "
4255 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
4256 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
4257 tbinfo
->dobj
.catId
.oid
);
4259 else if (g_fout
->remoteVersion
>= 70100)
4261 appendPQExpBuffer(query
,
4262 "SELECT tgname, tgfoid::regproc AS tgfname, "
4263 "tgtype, tgnargs, tgargs, tgenabled, "
4264 "tgisconstraint, tgconstrname, tgdeferrable, "
4265 "tgconstrrelid, tginitdeferred, tableoid, oid, "
4266 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4267 " AS tgconstrrelname "
4269 "WHERE tgrelid = '%u'::oid",
4270 tbinfo
->dobj
.catId
.oid
);
4274 appendPQExpBuffer(query
,
4275 "SELECT tgname, tgfoid::regproc AS tgfname, "
4276 "tgtype, tgnargs, tgargs, tgenabled, "
4277 "tgisconstraint, tgconstrname, tgdeferrable, "
4278 "tgconstrrelid, tginitdeferred, "
4279 "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
4281 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4282 " AS tgconstrrelname "
4284 "WHERE tgrelid = '%u'::oid",
4285 tbinfo
->dobj
.catId
.oid
);
4287 res
= PQexec(g_conn
, query
->data
);
4288 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
4290 ntups
= PQntuples(res
);
4292 i_tableoid
= PQfnumber(res
, "tableoid");
4293 i_oid
= PQfnumber(res
, "oid");
4294 i_tgname
= PQfnumber(res
, "tgname");
4295 i_tgfname
= PQfnumber(res
, "tgfname");
4296 i_tgtype
= PQfnumber(res
, "tgtype");
4297 i_tgnargs
= PQfnumber(res
, "tgnargs");
4298 i_tgargs
= PQfnumber(res
, "tgargs");
4299 i_tgisconstraint
= PQfnumber(res
, "tgisconstraint");
4300 i_tgconstrname
= PQfnumber(res
, "tgconstrname");
4301 i_tgconstrrelid
= PQfnumber(res
, "tgconstrrelid");
4302 i_tgconstrrelname
= PQfnumber(res
, "tgconstrrelname");
4303 i_tgenabled
= PQfnumber(res
, "tgenabled");
4304 i_tgdeferrable
= PQfnumber(res
, "tgdeferrable");
4305 i_tginitdeferred
= PQfnumber(res
, "tginitdeferred");
4307 tginfo
= (TriggerInfo
*) malloc(ntups
* sizeof(TriggerInfo
));
4309 for (j
= 0; j
< ntups
; j
++)
4311 tginfo
[j
].dobj
.objType
= DO_TRIGGER
;
4312 tginfo
[j
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, j
, i_tableoid
));
4313 tginfo
[j
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, j
, i_oid
));
4314 AssignDumpId(&tginfo
[j
].dobj
);
4315 tginfo
[j
].dobj
.name
= strdup(PQgetvalue(res
, j
, i_tgname
));
4316 tginfo
[j
].dobj
.namespace = tbinfo
->dobj
.namespace;
4317 tginfo
[j
].tgtable
= tbinfo
;
4318 tginfo
[j
].tgfname
= strdup(PQgetvalue(res
, j
, i_tgfname
));
4319 tginfo
[j
].tgtype
= atoi(PQgetvalue(res
, j
, i_tgtype
));
4320 tginfo
[j
].tgnargs
= atoi(PQgetvalue(res
, j
, i_tgnargs
));
4321 tginfo
[j
].tgargs
= strdup(PQgetvalue(res
, j
, i_tgargs
));
4322 tginfo
[j
].tgisconstraint
= *(PQgetvalue(res
, j
, i_tgisconstraint
)) == 't';
4323 tginfo
[j
].tgenabled
= *(PQgetvalue(res
, j
, i_tgenabled
));
4324 tginfo
[j
].tgdeferrable
= *(PQgetvalue(res
, j
, i_tgdeferrable
)) == 't';
4325 tginfo
[j
].tginitdeferred
= *(PQgetvalue(res
, j
, i_tginitdeferred
)) == 't';
4327 if (tginfo
[j
].tgisconstraint
)
4329 tginfo
[j
].tgconstrname
= strdup(PQgetvalue(res
, j
, i_tgconstrname
));
4330 tginfo
[j
].tgconstrrelid
= atooid(PQgetvalue(res
, j
, i_tgconstrrelid
));
4331 if (OidIsValid(tginfo
[j
].tgconstrrelid
))
4333 if (PQgetisnull(res
, j
, i_tgconstrrelname
))
4335 write_msg(NULL
, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
4336 tginfo
[j
].dobj
.name
, tbinfo
->dobj
.name
,
4337 tginfo
[j
].tgconstrrelid
);
4340 tginfo
[j
].tgconstrrelname
= strdup(PQgetvalue(res
, j
, i_tgconstrrelname
));
4343 tginfo
[j
].tgconstrrelname
= NULL
;
4347 tginfo
[j
].tgconstrname
= NULL
;
4348 tginfo
[j
].tgconstrrelid
= InvalidOid
;
4349 tginfo
[j
].tgconstrrelname
= NULL
;
4356 destroyPQExpBuffer(query
);
4361 * get basic information about every procedural language in the system
4363 * numProcLangs is set to the number of langs read in
4365 * NB: this must run after getFuncs() because we assume we can do
4369 getProcLangs(int *numProcLangs
)
4374 PQExpBuffer query
= createPQExpBuffer();
4375 ProcLangInfo
*planginfo
;
4380 int i_lanplcallfoid
;
4385 /* Make sure we are in proper schema */
4386 selectSourceSchema("pg_catalog");
4388 if (g_fout
->remoteVersion
>= 80300)
4390 /* pg_language has a lanowner column */
4391 appendPQExpBuffer(query
, "SELECT tableoid, oid, "
4392 "lanname, lanpltrusted, lanplcallfoid, "
4393 "lanvalidator, lanacl, "
4394 "(%s lanowner) AS lanowner "
4400 else if (g_fout
->remoteVersion
>= 80100)
4402 /* Languages are owned by the bootstrap superuser, OID 10 */
4403 appendPQExpBuffer(query
, "SELECT tableoid, oid, *, "
4404 "(%s '10') AS lanowner "
4410 else if (g_fout
->remoteVersion
>= 70400)
4412 /* Languages are owned by the bootstrap superuser, sysid 1 */
4413 appendPQExpBuffer(query
, "SELECT tableoid, oid, *, "
4414 "(%s '1') AS lanowner "
4420 else if (g_fout
->remoteVersion
>= 70100)
4422 /* No clear notion of an owner at all before 7.4 ... */
4423 appendPQExpBuffer(query
, "SELECT tableoid, oid, * FROM pg_language "
4429 appendPQExpBuffer(query
, "SELECT "
4430 "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4431 "oid, * FROM pg_language "
4436 res
= PQexec(g_conn
, query
->data
);
4437 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
4439 ntups
= PQntuples(res
);
4441 *numProcLangs
= ntups
;
4443 planginfo
= (ProcLangInfo
*) malloc(ntups
* sizeof(ProcLangInfo
));
4445 i_tableoid
= PQfnumber(res
, "tableoid");
4446 i_oid
= PQfnumber(res
, "oid");
4447 i_lanname
= PQfnumber(res
, "lanname");
4448 i_lanpltrusted
= PQfnumber(res
, "lanpltrusted");
4449 i_lanplcallfoid
= PQfnumber(res
, "lanplcallfoid");
4450 /* these may fail and return -1: */
4451 i_lanvalidator
= PQfnumber(res
, "lanvalidator");
4452 i_lanacl
= PQfnumber(res
, "lanacl");
4453 i_lanowner
= PQfnumber(res
, "lanowner");
4455 for (i
= 0; i
< ntups
; i
++)
4457 planginfo
[i
].dobj
.objType
= DO_PROCLANG
;
4458 planginfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
4459 planginfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
4460 AssignDumpId(&planginfo
[i
].dobj
);
4462 planginfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_lanname
));
4463 planginfo
[i
].lanpltrusted
= *(PQgetvalue(res
, i
, i_lanpltrusted
)) == 't';
4464 planginfo
[i
].lanplcallfoid
= atooid(PQgetvalue(res
, i
, i_lanplcallfoid
));
4465 if (i_lanvalidator
>= 0)
4466 planginfo
[i
].lanvalidator
= atooid(PQgetvalue(res
, i
, i_lanvalidator
));
4468 planginfo
[i
].lanvalidator
= InvalidOid
;
4470 planginfo
[i
].lanacl
= strdup(PQgetvalue(res
, i
, i_lanacl
));
4472 planginfo
[i
].lanacl
= strdup("{=U}");
4473 if (i_lanowner
>= 0)
4474 planginfo
[i
].lanowner
= strdup(PQgetvalue(res
, i
, i_lanowner
));
4476 planginfo
[i
].lanowner
= strdup("");
4478 if (g_fout
->remoteVersion
< 70300)
4481 * We need to make a dependency to ensure the function will be
4482 * dumped first. (In 7.3 and later the regular dependency
4483 * mechanism will handle this for us.)
4485 FuncInfo
*funcInfo
= findFuncByOid(planginfo
[i
].lanplcallfoid
);
4488 addObjectDependency(&planginfo
[i
].dobj
,
4489 funcInfo
->dobj
.dumpId
);
4495 destroyPQExpBuffer(query
);
4502 * get basic information about every cast in the system
4504 * numCasts is set to the number of casts read in
4507 getCasts(int *numCasts
)
4512 PQExpBuffer query
= createPQExpBuffer();
4522 /* Make sure we are in proper schema */
4523 selectSourceSchema("pg_catalog");
4525 if (g_fout
->remoteVersion
>= 80400)
4527 appendPQExpBuffer(query
, "SELECT tableoid, oid, "
4528 "castsource, casttarget, castfunc, castcontext, "
4530 "FROM pg_cast ORDER BY 3,4");
4532 else if (g_fout
->remoteVersion
>= 70300)
4534 appendPQExpBuffer(query
, "SELECT tableoid, oid, "
4535 "castsource, casttarget, castfunc, castcontext, "
4536 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
4537 "FROM pg_cast ORDER BY 3,4");
4541 appendPQExpBuffer(query
, "SELECT 0 AS tableoid, p.oid, "
4542 "t1.oid AS castsource, t2.oid AS casttarget, "
4543 "p.oid AS castfunc, 'e' AS castcontext, "
4544 "'f' AS castmethod "
4545 "FROM pg_type t1, pg_type t2, pg_proc p "
4546 "WHERE p.pronargs = 1 AND "
4547 "p.proargtypes[0] = t1.oid AND "
4548 "p.prorettype = t2.oid AND p.proname = t2.typname "
4552 res
= PQexec(g_conn
, query
->data
);
4553 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
4555 ntups
= PQntuples(res
);
4559 castinfo
= (CastInfo
*) malloc(ntups
* sizeof(CastInfo
));
4561 i_tableoid
= PQfnumber(res
, "tableoid");
4562 i_oid
= PQfnumber(res
, "oid");
4563 i_castsource
= PQfnumber(res
, "castsource");
4564 i_casttarget
= PQfnumber(res
, "casttarget");
4565 i_castfunc
= PQfnumber(res
, "castfunc");
4566 i_castcontext
= PQfnumber(res
, "castcontext");
4567 i_castmethod
= PQfnumber(res
, "castmethod");
4569 for (i
= 0; i
< ntups
; i
++)
4571 PQExpBufferData namebuf
;
4572 TypeInfo
*sTypeInfo
;
4573 TypeInfo
*tTypeInfo
;
4575 castinfo
[i
].dobj
.objType
= DO_CAST
;
4576 castinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
4577 castinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
4578 AssignDumpId(&castinfo
[i
].dobj
);
4579 castinfo
[i
].castsource
= atooid(PQgetvalue(res
, i
, i_castsource
));
4580 castinfo
[i
].casttarget
= atooid(PQgetvalue(res
, i
, i_casttarget
));
4581 castinfo
[i
].castfunc
= atooid(PQgetvalue(res
, i
, i_castfunc
));
4582 castinfo
[i
].castcontext
= *(PQgetvalue(res
, i
, i_castcontext
));
4583 castinfo
[i
].castmethod
= *(PQgetvalue(res
, i
, i_castmethod
));
4586 * Try to name cast as concatenation of typnames. This is only used
4587 * for purposes of sorting. If we fail to find either type, the name
4588 * will be an empty string.
4590 initPQExpBuffer(&namebuf
);
4591 sTypeInfo
= findTypeByOid(castinfo
[i
].castsource
);
4592 tTypeInfo
= findTypeByOid(castinfo
[i
].casttarget
);
4593 if (sTypeInfo
&& tTypeInfo
)
4594 appendPQExpBuffer(&namebuf
, "%s %s",
4595 sTypeInfo
->dobj
.name
, tTypeInfo
->dobj
.name
);
4596 castinfo
[i
].dobj
.name
= namebuf
.data
;
4598 if (OidIsValid(castinfo
[i
].castfunc
))
4601 * We need to make a dependency to ensure the function will be
4602 * dumped first. (In 7.3 and later the regular dependency
4603 * mechanism will handle this for us.)
4607 funcInfo
= findFuncByOid(castinfo
[i
].castfunc
);
4609 addObjectDependency(&castinfo
[i
].dobj
,
4610 funcInfo
->dobj
.dumpId
);
4616 destroyPQExpBuffer(query
);
4623 * for each interesting table, read info about its attributes
4624 * (names, types, default values, CHECK constraints, etc)
4626 * This is implemented in a very inefficient way right now, looping
4627 * through the tblinfo and doing a join per table to find the attrs and their
4628 * types. However, because we want type names and so forth to be named
4629 * relative to the schema of each table, we couldn't do it in just one
4630 * query. (Maybe one query per schema?)
4635 getTableAttrs(TableInfo
*tblinfo
, int numTables
)
4639 PQExpBuffer q
= createPQExpBuffer();
4644 int i_attstattarget
;
4657 for (i
= 0; i
< numTables
; i
++)
4659 TableInfo
*tbinfo
= &tblinfo
[i
];
4661 /* Don't bother to collect info for sequences */
4662 if (tbinfo
->relkind
== RELKIND_SEQUENCE
)
4665 /* Don't bother with uninteresting tables, either */
4666 if (!tbinfo
->interesting
)
4670 * Make sure we are in proper schema for this table; this allows
4671 * correct retrieval of formatted type names and default exprs
4673 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
4675 /* find all the user attributes and their types */
4678 * we must read the attribute names in attribute number order! because
4679 * we will use the attnum to index into the attnames array later. We
4680 * actually ask to order by "attrelid, attnum" because (at least up to
4681 * 7.3) the planner is not smart enough to realize it needn't re-sort
4682 * the output of an indexscan on pg_attribute_relid_attnum_index.
4685 write_msg(NULL
, "finding the columns and types of table \"%s\"\n",
4688 resetPQExpBuffer(q
);
4690 if (g_fout
->remoteVersion
>= 70300)
4692 /* need left join here to not fail on dropped columns ... */
4693 appendPQExpBuffer(q
, "SELECT a.attnum, a.attname, a.atttypmod, "
4694 "a.attstattarget, a.attstorage, t.typstorage, "
4695 "a.attnotnull, a.atthasdef, a.attisdropped, "
4696 "a.attlen, a.attalign, a.attislocal, "
4697 "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
4698 "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
4699 "ON a.atttypid = t.oid "
4700 "WHERE a.attrelid = '%u'::pg_catalog.oid "
4701 "AND a.attnum > 0::pg_catalog.int2 "
4702 "ORDER BY a.attrelid, a.attnum",
4703 tbinfo
->dobj
.catId
.oid
);
4705 else if (g_fout
->remoteVersion
>= 70100)
4708 * attstattarget doesn't exist in 7.1. It does exist in 7.2, but
4709 * we don't dump it because we can't tell whether it's been
4710 * explicitly set or was just a default.
4712 appendPQExpBuffer(q
, "SELECT a.attnum, a.attname, "
4713 "a.atttypmod, -1 AS attstattarget, a.attstorage, "
4714 "t.typstorage, a.attnotnull, a.atthasdef, "
4715 "false AS attisdropped, 0 AS attlen, "
4716 "' ' AS attalign, false AS attislocal, "
4717 "format_type(t.oid,a.atttypmod) AS atttypname "
4718 "FROM pg_attribute a LEFT JOIN pg_type t "
4719 "ON a.atttypid = t.oid "
4720 "WHERE a.attrelid = '%u'::oid "
4721 "AND a.attnum > 0::int2 "
4722 "ORDER BY a.attrelid, a.attnum",
4723 tbinfo
->dobj
.catId
.oid
);
4727 /* format_type not available before 7.1 */
4728 appendPQExpBuffer(q
, "SELECT attnum, attname, atttypmod, "
4729 "-1 AS attstattarget, attstorage, "
4730 "attstorage AS typstorage, "
4731 "attnotnull, atthasdef, false AS attisdropped, "
4732 "0 AS attlen, ' ' AS attalign, "
4733 "false AS attislocal, "
4734 "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
4735 "FROM pg_attribute a "
4736 "WHERE attrelid = '%u'::oid "
4737 "AND attnum > 0::int2 "
4738 "ORDER BY attrelid, attnum",
4739 tbinfo
->dobj
.catId
.oid
);
4742 res
= PQexec(g_conn
, q
->data
);
4743 check_sql_result(res
, g_conn
, q
->data
, PGRES_TUPLES_OK
);
4745 ntups
= PQntuples(res
);
4747 i_attnum
= PQfnumber(res
, "attnum");
4748 i_attname
= PQfnumber(res
, "attname");
4749 i_atttypname
= PQfnumber(res
, "atttypname");
4750 i_atttypmod
= PQfnumber(res
, "atttypmod");
4751 i_attstattarget
= PQfnumber(res
, "attstattarget");
4752 i_attstorage
= PQfnumber(res
, "attstorage");
4753 i_typstorage
= PQfnumber(res
, "typstorage");
4754 i_attnotnull
= PQfnumber(res
, "attnotnull");
4755 i_atthasdef
= PQfnumber(res
, "atthasdef");
4756 i_attisdropped
= PQfnumber(res
, "attisdropped");
4757 i_attlen
= PQfnumber(res
, "attlen");
4758 i_attalign
= PQfnumber(res
, "attalign");
4759 i_attislocal
= PQfnumber(res
, "attislocal");
4761 tbinfo
->numatts
= ntups
;
4762 tbinfo
->attnames
= (char **) malloc(ntups
* sizeof(char *));
4763 tbinfo
->atttypnames
= (char **) malloc(ntups
* sizeof(char *));
4764 tbinfo
->atttypmod
= (int *) malloc(ntups
* sizeof(int));
4765 tbinfo
->attstattarget
= (int *) malloc(ntups
* sizeof(int));
4766 tbinfo
->attstorage
= (char *) malloc(ntups
* sizeof(char));
4767 tbinfo
->typstorage
= (char *) malloc(ntups
* sizeof(char));
4768 tbinfo
->attisdropped
= (bool *) malloc(ntups
* sizeof(bool));
4769 tbinfo
->attlen
= (int *) malloc(ntups
* sizeof(int));
4770 tbinfo
->attalign
= (char *) malloc(ntups
* sizeof(char));
4771 tbinfo
->attislocal
= (bool *) malloc(ntups
* sizeof(bool));
4772 tbinfo
->notnull
= (bool *) malloc(ntups
* sizeof(bool));
4773 tbinfo
->attrdefs
= (AttrDefInfo
**) malloc(ntups
* sizeof(AttrDefInfo
*));
4774 tbinfo
->inhAttrs
= (bool *) malloc(ntups
* sizeof(bool));
4775 tbinfo
->inhAttrDef
= (bool *) malloc(ntups
* sizeof(bool));
4776 tbinfo
->inhNotNull
= (bool *) malloc(ntups
* sizeof(bool));
4777 hasdefaults
= false;
4779 for (j
= 0; j
< ntups
; j
++)
4781 if (j
+ 1 != atoi(PQgetvalue(res
, j
, i_attnum
)))
4783 write_msg(NULL
, "invalid column numbering in table \"%s\"\n",
4787 tbinfo
->attnames
[j
] = strdup(PQgetvalue(res
, j
, i_attname
));
4788 tbinfo
->atttypnames
[j
] = strdup(PQgetvalue(res
, j
, i_atttypname
));
4789 tbinfo
->atttypmod
[j
] = atoi(PQgetvalue(res
, j
, i_atttypmod
));
4790 tbinfo
->attstattarget
[j
] = atoi(PQgetvalue(res
, j
, i_attstattarget
));
4791 tbinfo
->attstorage
[j
] = *(PQgetvalue(res
, j
, i_attstorage
));
4792 tbinfo
->typstorage
[j
] = *(PQgetvalue(res
, j
, i_typstorage
));
4793 tbinfo
->attisdropped
[j
] = (PQgetvalue(res
, j
, i_attisdropped
)[0] == 't');
4794 tbinfo
->attlen
[j
] = atoi(PQgetvalue(res
, j
, i_attlen
));
4795 tbinfo
->attalign
[j
] = *(PQgetvalue(res
, j
, i_attalign
));
4796 tbinfo
->attislocal
[j
] = (PQgetvalue(res
, j
, i_attislocal
)[0] == 't');
4797 tbinfo
->notnull
[j
] = (PQgetvalue(res
, j
, i_attnotnull
)[0] == 't');
4798 tbinfo
->attrdefs
[j
] = NULL
; /* fix below */
4799 if (PQgetvalue(res
, j
, i_atthasdef
)[0] == 't')
4801 /* these flags will be set in flagInhAttrs() */
4802 tbinfo
->inhAttrs
[j
] = false;
4803 tbinfo
->inhAttrDef
[j
] = false;
4804 tbinfo
->inhNotNull
[j
] = false;
4811 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, so we set the
4812 * column data type to 'TEXT; we will later drop the column.
4816 for (j
= 0; j
< ntups
; j
++)
4818 if (tbinfo
->attisdropped
[j
])
4819 tbinfo
->atttypnames
[j
] = strdup("TEXT");
4824 * Get info about column defaults
4828 AttrDefInfo
*attrdefs
;
4832 write_msg(NULL
, "finding default expressions of table \"%s\"\n",
4835 resetPQExpBuffer(q
);
4836 if (g_fout
->remoteVersion
>= 70300)
4838 appendPQExpBuffer(q
, "SELECT tableoid, oid, adnum, "
4839 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
4840 "FROM pg_catalog.pg_attrdef "
4841 "WHERE adrelid = '%u'::pg_catalog.oid",
4842 tbinfo
->dobj
.catId
.oid
);
4844 else if (g_fout
->remoteVersion
>= 70200)
4846 /* 7.2 did not have OIDs in pg_attrdef */
4847 appendPQExpBuffer(q
, "SELECT tableoid, 0 AS oid, adnum, "
4848 "pg_get_expr(adbin, adrelid) AS adsrc "
4850 "WHERE adrelid = '%u'::oid",
4851 tbinfo
->dobj
.catId
.oid
);
4853 else if (g_fout
->remoteVersion
>= 70100)
4855 /* no pg_get_expr, so must rely on adsrc */
4856 appendPQExpBuffer(q
, "SELECT tableoid, oid, adnum, adsrc "
4858 "WHERE adrelid = '%u'::oid",
4859 tbinfo
->dobj
.catId
.oid
);
4863 /* no pg_get_expr, no tableoid either */
4864 appendPQExpBuffer(q
, "SELECT "
4865 "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
4866 "oid, adnum, adsrc "
4868 "WHERE adrelid = '%u'::oid",
4869 tbinfo
->dobj
.catId
.oid
);
4871 res
= PQexec(g_conn
, q
->data
);
4872 check_sql_result(res
, g_conn
, q
->data
, PGRES_TUPLES_OK
);
4874 numDefaults
= PQntuples(res
);
4875 attrdefs
= (AttrDefInfo
*) malloc(numDefaults
* sizeof(AttrDefInfo
));
4877 for (j
= 0; j
< numDefaults
; j
++)
4881 attrdefs
[j
].dobj
.objType
= DO_ATTRDEF
;
4882 attrdefs
[j
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, j
, 0));
4883 attrdefs
[j
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, j
, 1));
4884 AssignDumpId(&attrdefs
[j
].dobj
);
4885 attrdefs
[j
].adtable
= tbinfo
;
4886 attrdefs
[j
].adnum
= adnum
= atoi(PQgetvalue(res
, j
, 2));
4887 attrdefs
[j
].adef_expr
= strdup(PQgetvalue(res
, j
, 3));
4889 attrdefs
[j
].dobj
.name
= strdup(tbinfo
->dobj
.name
);
4890 attrdefs
[j
].dobj
.namespace = tbinfo
->dobj
.namespace;
4892 attrdefs
[j
].dobj
.dump
= tbinfo
->dobj
.dump
;
4895 * Defaults on a VIEW must always be dumped as separate ALTER
4896 * TABLE commands. Defaults on regular tables are dumped as
4897 * part of the CREATE TABLE if possible. To check if it's
4898 * safe, we mark the default as needing to appear before the
4901 if (tbinfo
->relkind
== RELKIND_VIEW
)
4903 attrdefs
[j
].separate
= true;
4904 /* needed in case pre-7.3 DB: */
4905 addObjectDependency(&attrdefs
[j
].dobj
,
4906 tbinfo
->dobj
.dumpId
);
4910 attrdefs
[j
].separate
= false;
4911 addObjectDependency(&tbinfo
->dobj
,
4912 attrdefs
[j
].dobj
.dumpId
);
4915 if (adnum
<= 0 || adnum
> ntups
)
4917 write_msg(NULL
, "invalid adnum value %d for table \"%s\"\n",
4918 adnum
, tbinfo
->dobj
.name
);
4921 tbinfo
->attrdefs
[adnum
- 1] = &attrdefs
[j
];
4927 * Get info about table CHECK constraints
4929 if (tbinfo
->ncheck
> 0)
4931 ConstraintInfo
*constrs
;
4935 write_msg(NULL
, "finding check constraints for table \"%s\"\n",
4938 resetPQExpBuffer(q
);
4939 if (g_fout
->remoteVersion
>= 80400)
4941 appendPQExpBuffer(q
, "SELECT tableoid, oid, conname, "
4942 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4944 "FROM pg_catalog.pg_constraint "
4945 "WHERE conrelid = '%u'::pg_catalog.oid "
4946 " AND contype = 'c' "
4948 tbinfo
->dobj
.catId
.oid
);
4950 else if (g_fout
->remoteVersion
>= 70400)
4952 appendPQExpBuffer(q
, "SELECT tableoid, oid, conname, "
4953 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4954 "true AS conislocal "
4955 "FROM pg_catalog.pg_constraint "
4956 "WHERE conrelid = '%u'::pg_catalog.oid "
4957 " AND contype = 'c' "
4959 tbinfo
->dobj
.catId
.oid
);
4961 else if (g_fout
->remoteVersion
>= 70300)
4963 /* no pg_get_constraintdef, must use consrc */
4964 appendPQExpBuffer(q
, "SELECT tableoid, oid, conname, "
4965 "'CHECK (' || consrc || ')' AS consrc, "
4966 "true AS conislocal "
4967 "FROM pg_catalog.pg_constraint "
4968 "WHERE conrelid = '%u'::pg_catalog.oid "
4969 " AND contype = 'c' "
4971 tbinfo
->dobj
.catId
.oid
);
4973 else if (g_fout
->remoteVersion
>= 70200)
4975 /* 7.2 did not have OIDs in pg_relcheck */
4976 appendPQExpBuffer(q
, "SELECT tableoid, 0 AS oid, "
4977 "rcname AS conname, "
4978 "'CHECK (' || rcsrc || ')' AS consrc, "
4979 "true AS conislocal "
4981 "WHERE rcrelid = '%u'::oid "
4983 tbinfo
->dobj
.catId
.oid
);
4985 else if (g_fout
->remoteVersion
>= 70100)
4987 appendPQExpBuffer(q
, "SELECT tableoid, oid, "
4988 "rcname AS conname, "
4989 "'CHECK (' || rcsrc || ')' AS consrc, "
4990 "true AS conislocal "
4992 "WHERE rcrelid = '%u'::oid "
4994 tbinfo
->dobj
.catId
.oid
);
4998 /* no tableoid in 7.0 */
4999 appendPQExpBuffer(q
, "SELECT "
5000 "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
5001 "oid, rcname AS conname, "
5002 "'CHECK (' || rcsrc || ')' AS consrc, "
5003 "true AS conislocal "
5005 "WHERE rcrelid = '%u'::oid "
5007 tbinfo
->dobj
.catId
.oid
);
5009 res
= PQexec(g_conn
, q
->data
);
5010 check_sql_result(res
, g_conn
, q
->data
, PGRES_TUPLES_OK
);
5012 numConstrs
= PQntuples(res
);
5013 if (numConstrs
!= tbinfo
->ncheck
)
5015 write_msg(NULL
, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
5016 "expected %d check constraints on table \"%s\" but found %d\n",
5018 tbinfo
->ncheck
, tbinfo
->dobj
.name
, numConstrs
);
5019 write_msg(NULL
, "(The system catalogs might be corrupted.)\n");
5023 constrs
= (ConstraintInfo
*) malloc(numConstrs
* sizeof(ConstraintInfo
));
5024 tbinfo
->checkexprs
= constrs
;
5026 for (j
= 0; j
< numConstrs
; j
++)
5028 constrs
[j
].dobj
.objType
= DO_CONSTRAINT
;
5029 constrs
[j
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, j
, 0));
5030 constrs
[j
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, j
, 1));
5031 AssignDumpId(&constrs
[j
].dobj
);
5032 constrs
[j
].dobj
.name
= strdup(PQgetvalue(res
, j
, 2));
5033 constrs
[j
].dobj
.namespace = tbinfo
->dobj
.namespace;
5034 constrs
[j
].contable
= tbinfo
;
5035 constrs
[j
].condomain
= NULL
;
5036 constrs
[j
].contype
= 'c';
5037 constrs
[j
].condef
= strdup(PQgetvalue(res
, j
, 3));
5038 constrs
[j
].confrelid
= InvalidOid
;
5039 constrs
[j
].conindex
= 0;
5040 constrs
[j
].conislocal
= (PQgetvalue(res
, j
, 4)[0] == 't');
5041 constrs
[j
].separate
= false;
5043 constrs
[j
].dobj
.dump
= tbinfo
->dobj
.dump
;
5046 * Mark the constraint as needing to appear before the table
5047 * --- this is so that any other dependencies of the
5048 * constraint will be emitted before we try to create the
5051 addObjectDependency(&tbinfo
->dobj
,
5052 constrs
[j
].dobj
.dumpId
);
5055 * If the constraint is inherited, this will be detected later
5056 * (in pre-8.4 databases). We also detect later if the
5057 * constraint must be split out from the table definition.
5064 destroyPQExpBuffer(q
);
5070 * read all text search parsers in the system catalogs and return them
5071 * in the TSParserInfo* structure
5073 * numTSParsers is set to the number of parsers read in
5076 getTSParsers(int *numTSParsers
)
5081 PQExpBuffer query
= createPQExpBuffer();
5082 TSParserInfo
*prsinfo
;
5093 /* Before 8.3, there is no built-in text search support */
5094 if (g_fout
->remoteVersion
< 80300)
5101 * find all text search objects, including builtin ones; we filter out
5102 * system-defined objects at dump-out time.
5105 /* Make sure we are in proper schema */
5106 selectSourceSchema("pg_catalog");
5108 appendPQExpBuffer(query
, "SELECT tableoid, oid, prsname, prsnamespace, "
5109 "prsstart::oid, prstoken::oid, "
5110 "prsend::oid, prsheadline::oid, prslextype::oid "
5111 "FROM pg_ts_parser");
5113 res
= PQexec(g_conn
, query
->data
);
5114 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5116 ntups
= PQntuples(res
);
5117 *numTSParsers
= ntups
;
5119 prsinfo
= (TSParserInfo
*) malloc(ntups
* sizeof(TSParserInfo
));
5121 i_tableoid
= PQfnumber(res
, "tableoid");
5122 i_oid
= PQfnumber(res
, "oid");
5123 i_prsname
= PQfnumber(res
, "prsname");
5124 i_prsnamespace
= PQfnumber(res
, "prsnamespace");
5125 i_prsstart
= PQfnumber(res
, "prsstart");
5126 i_prstoken
= PQfnumber(res
, "prstoken");
5127 i_prsend
= PQfnumber(res
, "prsend");
5128 i_prsheadline
= PQfnumber(res
, "prsheadline");
5129 i_prslextype
= PQfnumber(res
, "prslextype");
5131 for (i
= 0; i
< ntups
; i
++)
5133 prsinfo
[i
].dobj
.objType
= DO_TSPARSER
;
5134 prsinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
5135 prsinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
5136 AssignDumpId(&prsinfo
[i
].dobj
);
5137 prsinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_prsname
));
5138 prsinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_prsnamespace
)),
5139 prsinfo
[i
].dobj
.catId
.oid
);
5140 prsinfo
[i
].prsstart
= atooid(PQgetvalue(res
, i
, i_prsstart
));
5141 prsinfo
[i
].prstoken
= atooid(PQgetvalue(res
, i
, i_prstoken
));
5142 prsinfo
[i
].prsend
= atooid(PQgetvalue(res
, i
, i_prsend
));
5143 prsinfo
[i
].prsheadline
= atooid(PQgetvalue(res
, i
, i_prsheadline
));
5144 prsinfo
[i
].prslextype
= atooid(PQgetvalue(res
, i
, i_prslextype
));
5146 /* Decide whether we want to dump it */
5147 selectDumpableObject(&(prsinfo
[i
].dobj
));
5152 destroyPQExpBuffer(query
);
5158 * getTSDictionaries:
5159 * read all text search dictionaries in the system catalogs and return them
5160 * in the TSDictInfo* structure
5162 * numTSDicts is set to the number of dictionaries read in
5165 getTSDictionaries(int *numTSDicts
)
5170 PQExpBuffer query
= createPQExpBuffer();
5171 TSDictInfo
*dictinfo
;
5175 int i_dictnamespace
;
5178 int i_dictinitoption
;
5180 /* Before 8.3, there is no built-in text search support */
5181 if (g_fout
->remoteVersion
< 80300)
5187 /* Make sure we are in proper schema */
5188 selectSourceSchema("pg_catalog");
5190 appendPQExpBuffer(query
, "SELECT tableoid, oid, dictname, "
5191 "dictnamespace, (%s dictowner) AS rolname, "
5192 "dicttemplate, dictinitoption "
5196 res
= PQexec(g_conn
, query
->data
);
5197 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5199 ntups
= PQntuples(res
);
5200 *numTSDicts
= ntups
;
5202 dictinfo
= (TSDictInfo
*) malloc(ntups
* sizeof(TSDictInfo
));
5204 i_tableoid
= PQfnumber(res
, "tableoid");
5205 i_oid
= PQfnumber(res
, "oid");
5206 i_dictname
= PQfnumber(res
, "dictname");
5207 i_dictnamespace
= PQfnumber(res
, "dictnamespace");
5208 i_rolname
= PQfnumber(res
, "rolname");
5209 i_dictinitoption
= PQfnumber(res
, "dictinitoption");
5210 i_dicttemplate
= PQfnumber(res
, "dicttemplate");
5212 for (i
= 0; i
< ntups
; i
++)
5214 dictinfo
[i
].dobj
.objType
= DO_TSDICT
;
5215 dictinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
5216 dictinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
5217 AssignDumpId(&dictinfo
[i
].dobj
);
5218 dictinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_dictname
));
5219 dictinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_dictnamespace
)),
5220 dictinfo
[i
].dobj
.catId
.oid
);
5221 dictinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
5222 dictinfo
[i
].dicttemplate
= atooid(PQgetvalue(res
, i
, i_dicttemplate
));
5223 if (PQgetisnull(res
, i
, i_dictinitoption
))
5224 dictinfo
[i
].dictinitoption
= NULL
;
5226 dictinfo
[i
].dictinitoption
= strdup(PQgetvalue(res
, i
, i_dictinitoption
));
5228 /* Decide whether we want to dump it */
5229 selectDumpableObject(&(dictinfo
[i
].dobj
));
5234 destroyPQExpBuffer(query
);
5241 * read all text search templates in the system catalogs and return them
5242 * in the TSTemplateInfo* structure
5244 * numTSTemplates is set to the number of templates read in
5247 getTSTemplates(int *numTSTemplates
)
5252 PQExpBuffer query
= createPQExpBuffer();
5253 TSTemplateInfo
*tmplinfo
;
5257 int i_tmplnamespace
;
5261 /* Before 8.3, there is no built-in text search support */
5262 if (g_fout
->remoteVersion
< 80300)
5264 *numTSTemplates
= 0;
5268 /* Make sure we are in proper schema */
5269 selectSourceSchema("pg_catalog");
5271 appendPQExpBuffer(query
, "SELECT tableoid, oid, tmplname, "
5272 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5273 "FROM pg_ts_template");
5275 res
= PQexec(g_conn
, query
->data
);
5276 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5278 ntups
= PQntuples(res
);
5279 *numTSTemplates
= ntups
;
5281 tmplinfo
= (TSTemplateInfo
*) malloc(ntups
* sizeof(TSTemplateInfo
));
5283 i_tableoid
= PQfnumber(res
, "tableoid");
5284 i_oid
= PQfnumber(res
, "oid");
5285 i_tmplname
= PQfnumber(res
, "tmplname");
5286 i_tmplnamespace
= PQfnumber(res
, "tmplnamespace");
5287 i_tmplinit
= PQfnumber(res
, "tmplinit");
5288 i_tmpllexize
= PQfnumber(res
, "tmpllexize");
5290 for (i
= 0; i
< ntups
; i
++)
5292 tmplinfo
[i
].dobj
.objType
= DO_TSTEMPLATE
;
5293 tmplinfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
5294 tmplinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
5295 AssignDumpId(&tmplinfo
[i
].dobj
);
5296 tmplinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_tmplname
));
5297 tmplinfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_tmplnamespace
)),
5298 tmplinfo
[i
].dobj
.catId
.oid
);
5299 tmplinfo
[i
].tmplinit
= atooid(PQgetvalue(res
, i
, i_tmplinit
));
5300 tmplinfo
[i
].tmpllexize
= atooid(PQgetvalue(res
, i
, i_tmpllexize
));
5302 /* Decide whether we want to dump it */
5303 selectDumpableObject(&(tmplinfo
[i
].dobj
));
5308 destroyPQExpBuffer(query
);
5314 * getTSConfigurations:
5315 * read all text search configurations in the system catalogs and return
5316 * them in the TSConfigInfo* structure
5318 * numTSConfigs is set to the number of configurations read in
5321 getTSConfigurations(int *numTSConfigs
)
5326 PQExpBuffer query
= createPQExpBuffer();
5327 TSConfigInfo
*cfginfo
;
5335 /* Before 8.3, there is no built-in text search support */
5336 if (g_fout
->remoteVersion
< 80300)
5342 /* Make sure we are in proper schema */
5343 selectSourceSchema("pg_catalog");
5345 appendPQExpBuffer(query
, "SELECT tableoid, oid, cfgname, "
5346 "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5347 "FROM pg_ts_config",
5350 res
= PQexec(g_conn
, query
->data
);
5351 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5353 ntups
= PQntuples(res
);
5354 *numTSConfigs
= ntups
;
5356 cfginfo
= (TSConfigInfo
*) malloc(ntups
* sizeof(TSConfigInfo
));
5358 i_tableoid
= PQfnumber(res
, "tableoid");
5359 i_oid
= PQfnumber(res
, "oid");
5360 i_cfgname
= PQfnumber(res
, "cfgname");
5361 i_cfgnamespace
= PQfnumber(res
, "cfgnamespace");
5362 i_rolname
= PQfnumber(res
, "rolname");
5363 i_cfgparser
= PQfnumber(res
, "cfgparser");
5365 for (i
= 0; i
< ntups
; i
++)
5367 cfginfo
[i
].dobj
.objType
= DO_TSCONFIG
;
5368 cfginfo
[i
].dobj
.catId
.tableoid
= atooid(PQgetvalue(res
, i
, i_tableoid
));
5369 cfginfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
5370 AssignDumpId(&cfginfo
[i
].dobj
);
5371 cfginfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_cfgname
));
5372 cfginfo
[i
].dobj
.namespace = findNamespace(atooid(PQgetvalue(res
, i
, i_cfgnamespace
)),
5373 cfginfo
[i
].dobj
.catId
.oid
);
5374 cfginfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
5375 cfginfo
[i
].cfgparser
= atooid(PQgetvalue(res
, i
, i_cfgparser
));
5377 /* Decide whether we want to dump it */
5378 selectDumpableObject(&(cfginfo
[i
].dobj
));
5383 destroyPQExpBuffer(query
);
5389 * getForeignDataWrappers:
5390 * read all foreign-data wrappers in the system catalogs and return
5391 * them in the FdwInfo* structure
5393 * numForeignDataWrappers is set to the number of fdws read in
5396 getForeignDataWrappers(int *numForeignDataWrappers
)
5401 PQExpBuffer query
= createPQExpBuffer();
5410 /* Before 8.4, there are no foreign-data wrappers */
5411 if (g_fout
->remoteVersion
< 80400)
5413 *numForeignDataWrappers
= 0;
5417 /* Make sure we are in proper schema */
5418 selectSourceSchema("pg_catalog");
5420 appendPQExpBuffer(query
, "SELECT oid, fdwname, "
5421 "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
5422 "array_to_string(ARRAY("
5423 " SELECT option_name || ' ' || quote_literal(option_value) "
5424 " FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
5425 "FROM pg_foreign_data_wrapper",
5428 res
= PQexec(g_conn
, query
->data
);
5429 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5431 ntups
= PQntuples(res
);
5432 *numForeignDataWrappers
= ntups
;
5434 fdwinfo
= (FdwInfo
*) malloc(ntups
* sizeof(FdwInfo
));
5436 i_oid
= PQfnumber(res
, "oid");
5437 i_fdwname
= PQfnumber(res
, "fdwname");
5438 i_rolname
= PQfnumber(res
, "rolname");
5439 i_fdwvalidator
= PQfnumber(res
, "fdwvalidator");
5440 i_fdwacl
= PQfnumber(res
, "fdwacl");
5441 i_fdwoptions
= PQfnumber(res
, "fdwoptions");
5443 for (i
= 0; i
< ntups
; i
++)
5445 fdwinfo
[i
].dobj
.objType
= DO_FDW
;
5446 fdwinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
5447 AssignDumpId(&fdwinfo
[i
].dobj
);
5448 fdwinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_fdwname
));
5449 fdwinfo
[i
].dobj
.namespace = NULL
;
5450 fdwinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
5451 fdwinfo
[i
].fdwvalidator
= strdup(PQgetvalue(res
, i
, i_fdwvalidator
));
5452 fdwinfo
[i
].fdwoptions
= strdup(PQgetvalue(res
, i
, i_fdwoptions
));
5453 fdwinfo
[i
].fdwacl
= strdup(PQgetvalue(res
, i
, i_fdwacl
));
5456 /* Decide whether we want to dump it */
5457 selectDumpableObject(&(fdwinfo
[i
].dobj
));
5462 destroyPQExpBuffer(query
);
5468 * getForeignServers:
5469 * read all foreign servers in the system catalogs and return
5470 * them in the ForeignServerInfo * structure
5472 * numForeignServers is set to the number of servers read in
5475 getForeignServers(int *numForeignServers
)
5480 PQExpBuffer query
= createPQExpBuffer();
5481 ForeignServerInfo
*srvinfo
;
5491 /* Before 8.4, there are no foreign servers */
5492 if (g_fout
->remoteVersion
< 80400)
5494 *numForeignServers
= 0;
5498 /* Make sure we are in proper schema */
5499 selectSourceSchema("pg_catalog");
5501 appendPQExpBuffer(query
, "SELECT oid, srvname, "
5502 "(%s srvowner) AS rolname, "
5503 "srvfdw, srvtype, srvversion, srvacl,"
5504 "array_to_string(ARRAY("
5505 " SELECT option_name || ' ' || quote_literal(option_value) "
5506 " FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
5507 "FROM pg_foreign_server",
5510 res
= PQexec(g_conn
, query
->data
);
5511 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5513 ntups
= PQntuples(res
);
5514 *numForeignServers
= ntups
;
5516 srvinfo
= (ForeignServerInfo
*) malloc(ntups
* sizeof(ForeignServerInfo
));
5518 i_oid
= PQfnumber(res
, "oid");
5519 i_srvname
= PQfnumber(res
, "srvname");
5520 i_rolname
= PQfnumber(res
, "rolname");
5521 i_srvfdw
= PQfnumber(res
, "srvfdw");
5522 i_srvtype
= PQfnumber(res
, "srvtype");
5523 i_srvversion
= PQfnumber(res
, "srvversion");
5524 i_srvacl
= PQfnumber(res
, "srvacl");
5525 i_srvoptions
= PQfnumber(res
, "srvoptions");
5527 for (i
= 0; i
< ntups
; i
++)
5529 srvinfo
[i
].dobj
.objType
= DO_FOREIGN_SERVER
;
5530 srvinfo
[i
].dobj
.catId
.oid
= atooid(PQgetvalue(res
, i
, i_oid
));
5531 AssignDumpId(&srvinfo
[i
].dobj
);
5532 srvinfo
[i
].dobj
.name
= strdup(PQgetvalue(res
, i
, i_srvname
));
5533 srvinfo
[i
].dobj
.namespace = NULL
;
5534 srvinfo
[i
].rolname
= strdup(PQgetvalue(res
, i
, i_rolname
));
5535 srvinfo
[i
].srvfdw
= atooid(PQgetvalue(res
, i
, i_srvfdw
));
5536 srvinfo
[i
].srvtype
= strdup(PQgetvalue(res
, i
, i_srvtype
));
5537 srvinfo
[i
].srvversion
= strdup(PQgetvalue(res
, i
, i_srvversion
));
5538 srvinfo
[i
].srvoptions
= strdup(PQgetvalue(res
, i
, i_srvoptions
));
5539 srvinfo
[i
].srvacl
= strdup(PQgetvalue(res
, i
, i_srvacl
));
5541 /* Decide whether we want to dump it */
5542 selectDumpableObject(&(srvinfo
[i
].dobj
));
5547 destroyPQExpBuffer(query
);
5555 * This routine is used to dump any comments associated with the
5556 * object handed to this routine. The routine takes a constant character
5557 * string for the target part of the comment-creation command, plus
5558 * the namespace and owner of the object (for labeling the ArchiveEntry),
5559 * plus catalog ID and subid which are the lookup key for pg_description,
5560 * plus the dump ID for the object (for setting a dependency).
5561 * If a matching pg_description entry is found, it is dumped.
5563 * Note: although this routine takes a dumpId for dependency purposes,
5564 * that purpose is just to mark the dependency in the emitted dump file
5565 * for possible future use by pg_restore. We do NOT use it for determining
5566 * ordering of the comment in the dump file, because this routine is called
5567 * after dependency sorting occurs. This routine should be called just after
5568 * calling ArchiveEntry() for the specified object.
5571 dumpComment(Archive
*fout
, const char *target
,
5572 const char *namespace, const char *owner
,
5573 CatalogId catalogId
, int subid
, DumpId dumpId
)
5575 CommentItem
*comments
;
5578 /* Comments are SCHEMA not data */
5582 /* Search for comments associated with catalogId, using table */
5583 ncomments
= findComments(fout
, catalogId
.tableoid
, catalogId
.oid
,
5586 /* Is there one matching the subid? */
5587 while (ncomments
> 0)
5589 if (comments
->objsubid
== subid
)
5595 /* If a comment exists, build COMMENT ON statement */
5598 PQExpBuffer query
= createPQExpBuffer();
5600 appendPQExpBuffer(query
, "COMMENT ON %s IS ", target
);
5601 appendStringLiteralAH(query
, comments
->descr
, fout
);
5602 appendPQExpBuffer(query
, ";\n");
5605 * We mark comments as SECTION_NONE because they really belong in the
5606 * same section as their parent, whether that is pre-data or
5609 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
5610 target
, namespace, NULL
, owner
,
5611 false, "COMMENT", SECTION_NONE
,
5612 query
->data
, "", NULL
,
5616 destroyPQExpBuffer(query
);
5621 * dumpTableComment --
5623 * As above, but dump comments for both the specified table (or view)
5627 dumpTableComment(Archive
*fout
, TableInfo
*tbinfo
,
5628 const char *reltypename
)
5630 CommentItem
*comments
;
5635 /* Comments are SCHEMA not data */
5639 /* Search for comments associated with relation, using table */
5640 ncomments
= findComments(fout
,
5641 tbinfo
->dobj
.catId
.tableoid
,
5642 tbinfo
->dobj
.catId
.oid
,
5645 /* If comments exist, build COMMENT ON statements */
5649 query
= createPQExpBuffer();
5650 target
= createPQExpBuffer();
5652 while (ncomments
> 0)
5654 const char *descr
= comments
->descr
;
5655 int objsubid
= comments
->objsubid
;
5659 resetPQExpBuffer(target
);
5660 appendPQExpBuffer(target
, "%s %s", reltypename
,
5661 fmtId(tbinfo
->dobj
.name
));
5663 resetPQExpBuffer(query
);
5664 appendPQExpBuffer(query
, "COMMENT ON %s IS ", target
->data
);
5665 appendStringLiteralAH(query
, descr
, fout
);
5666 appendPQExpBuffer(query
, ";\n");
5668 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
5670 tbinfo
->dobj
.namespace->dobj
.name
,
5671 NULL
, tbinfo
->rolname
,
5672 false, "COMMENT", SECTION_NONE
,
5673 query
->data
, "", NULL
,
5674 &(tbinfo
->dobj
.dumpId
), 1,
5677 else if (objsubid
> 0 && objsubid
<= tbinfo
->numatts
)
5679 resetPQExpBuffer(target
);
5680 appendPQExpBuffer(target
, "COLUMN %s.",
5681 fmtId(tbinfo
->dobj
.name
));
5682 appendPQExpBuffer(target
, "%s",
5683 fmtId(tbinfo
->attnames
[objsubid
- 1]));
5685 resetPQExpBuffer(query
);
5686 appendPQExpBuffer(query
, "COMMENT ON %s IS ", target
->data
);
5687 appendStringLiteralAH(query
, descr
, fout
);
5688 appendPQExpBuffer(query
, ";\n");
5690 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
5692 tbinfo
->dobj
.namespace->dobj
.name
,
5693 NULL
, tbinfo
->rolname
,
5694 false, "COMMENT", SECTION_NONE
,
5695 query
->data
, "", NULL
,
5696 &(tbinfo
->dobj
.dumpId
), 1,
5704 destroyPQExpBuffer(query
);
5705 destroyPQExpBuffer(target
);
5711 * Find the comment(s), if any, associated with the given object. All the
5712 * objsubid values associated with the given classoid/objoid are found with
5716 findComments(Archive
*fout
, Oid classoid
, Oid objoid
,
5717 CommentItem
**items
)
5719 /* static storage for table of comments */
5720 static CommentItem
*comments
= NULL
;
5721 static int ncomments
= -1;
5723 CommentItem
*middle
= NULL
;
5728 /* Get comments if we didn't already */
5730 ncomments
= collectComments(fout
, &comments
);
5733 * Pre-7.2, pg_description does not contain classoid, so collectComments
5734 * just stores a zero. If there's a collision on object OID, well, you
5735 * get duplicate comments.
5737 if (fout
->remoteVersion
< 70200)
5741 * Do binary search to find some item matching the object.
5744 high
= &comments
[ncomments
- 1];
5747 middle
= low
+ (high
- low
) / 2;
5749 if (classoid
< middle
->classoid
)
5751 else if (classoid
> middle
->classoid
)
5753 else if (objoid
< middle
->objoid
)
5755 else if (objoid
> middle
->objoid
)
5758 break; /* found a match */
5761 if (low
> high
) /* no matches */
5768 * Now determine how many items match the object. The search loop
5769 * invariant still holds: only items between low and high inclusive could
5773 while (middle
> low
)
5775 if (classoid
!= middle
[-1].classoid
||
5776 objoid
!= middle
[-1].objoid
)
5785 while (middle
<= high
)
5787 if (classoid
!= middle
->classoid
||
5788 objoid
!= middle
->objoid
)
5798 * collectComments --
5800 * Construct a table of all comments available for database objects.
5801 * We used to do per-object queries for the comments, but it's much faster
5802 * to pull them all over at once, and on most databases the memory cost
5805 * The table is sorted by classoid/objid/objsubid for speed in lookup.
5808 collectComments(Archive
*fout
, CommentItem
**items
)
5818 CommentItem
*comments
;
5821 * Note we do NOT change source schema here; preserve the caller's
5825 query
= createPQExpBuffer();
5827 if (fout
->remoteVersion
>= 70300)
5829 appendPQExpBuffer(query
, "SELECT description, classoid, objoid, objsubid "
5830 "FROM pg_catalog.pg_description "
5831 "ORDER BY classoid, objoid, objsubid");
5833 else if (fout
->remoteVersion
>= 70200)
5835 appendPQExpBuffer(query
, "SELECT description, classoid, objoid, objsubid "
5836 "FROM pg_description "
5837 "ORDER BY classoid, objoid, objsubid");
5841 /* Note: this will fail to find attribute comments in pre-7.2... */
5842 appendPQExpBuffer(query
, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
5843 "FROM pg_description "
5847 res
= PQexec(g_conn
, query
->data
);
5848 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
5850 /* Construct lookup table containing OIDs in numeric form */
5852 i_description
= PQfnumber(res
, "description");
5853 i_classoid
= PQfnumber(res
, "classoid");
5854 i_objoid
= PQfnumber(res
, "objoid");
5855 i_objsubid
= PQfnumber(res
, "objsubid");
5857 ntups
= PQntuples(res
);
5859 comments
= (CommentItem
*) malloc(ntups
* sizeof(CommentItem
));
5861 for (i
= 0; i
< ntups
; i
++)
5863 comments
[i
].descr
= PQgetvalue(res
, i
, i_description
);
5864 comments
[i
].classoid
= atooid(PQgetvalue(res
, i
, i_classoid
));
5865 comments
[i
].objoid
= atooid(PQgetvalue(res
, i
, i_objoid
));
5866 comments
[i
].objsubid
= atoi(PQgetvalue(res
, i
, i_objsubid
));
5869 /* Do NOT free the PGresult since we are keeping pointers into it */
5870 destroyPQExpBuffer(query
);
5877 * dumpDumpableObject
5879 * This routine and its subsidiaries are responsible for creating
5880 * ArchiveEntries (TOC objects) for each object to be dumped.
5883 dumpDumpableObject(Archive
*fout
, DumpableObject
*dobj
)
5885 switch (dobj
->objType
)
5888 dumpNamespace(fout
, (NamespaceInfo
*) dobj
);
5891 dumpType(fout
, (TypeInfo
*) dobj
);
5894 dumpShellType(fout
, (ShellTypeInfo
*) dobj
);
5897 dumpFunc(fout
, (FuncInfo
*) dobj
);
5900 dumpAgg(fout
, (AggInfo
*) dobj
);
5903 dumpOpr(fout
, (OprInfo
*) dobj
);
5906 dumpOpclass(fout
, (OpclassInfo
*) dobj
);
5909 dumpOpfamily(fout
, (OpfamilyInfo
*) dobj
);
5912 dumpConversion(fout
, (ConvInfo
*) dobj
);
5915 dumpTable(fout
, (TableInfo
*) dobj
);
5918 dumpAttrDef(fout
, (AttrDefInfo
*) dobj
);
5921 dumpIndex(fout
, (IndxInfo
*) dobj
);
5924 dumpRule(fout
, (RuleInfo
*) dobj
);
5927 dumpTrigger(fout
, (TriggerInfo
*) dobj
);
5930 dumpConstraint(fout
, (ConstraintInfo
*) dobj
);
5932 case DO_FK_CONSTRAINT
:
5933 dumpConstraint(fout
, (ConstraintInfo
*) dobj
);
5936 dumpProcLang(fout
, (ProcLangInfo
*) dobj
);
5939 dumpCast(fout
, (CastInfo
*) dobj
);
5942 dumpTableData(fout
, (TableDataInfo
*) dobj
);
5945 /* table rowtypes and array types are never dumped separately */
5948 dumpTSParser(fout
, (TSParserInfo
*) dobj
);
5951 dumpTSDictionary(fout
, (TSDictInfo
*) dobj
);
5954 dumpTSTemplate(fout
, (TSTemplateInfo
*) dobj
);
5957 dumpTSConfig(fout
, (TSConfigInfo
*) dobj
);
5960 dumpForeignDataWrapper(fout
, (FdwInfo
*) dobj
);
5962 case DO_FOREIGN_SERVER
:
5963 dumpForeignServer(fout
, (ForeignServerInfo
*) dobj
);
5966 ArchiveEntry(fout
, dobj
->catId
, dobj
->dumpId
,
5967 dobj
->name
, NULL
, NULL
, "",
5968 false, "BLOBS", SECTION_DATA
,
5970 dobj
->dependencies
, dobj
->nDeps
,
5973 case DO_BLOB_COMMENTS
:
5974 ArchiveEntry(fout
, dobj
->catId
, dobj
->dumpId
,
5975 dobj
->name
, NULL
, NULL
, "",
5976 false, "BLOB COMMENTS", SECTION_DATA
,
5978 dobj
->dependencies
, dobj
->nDeps
,
5979 dumpBlobComments
, NULL
);
5986 * writes out to fout the queries to recreate a user-defined namespace
5989 dumpNamespace(Archive
*fout
, NamespaceInfo
*nspinfo
)
5995 /* Skip if not to be dumped */
5996 if (!nspinfo
->dobj
.dump
|| dataOnly
)
5999 /* don't dump dummy namespace from pre-7.3 source */
6000 if (strlen(nspinfo
->dobj
.name
) == 0)
6003 q
= createPQExpBuffer();
6004 delq
= createPQExpBuffer();
6006 qnspname
= strdup(fmtId(nspinfo
->dobj
.name
));
6008 appendPQExpBuffer(delq
, "DROP SCHEMA %s;\n", qnspname
);
6010 appendPQExpBuffer(q
, "CREATE SCHEMA %s;\n", qnspname
);
6012 ArchiveEntry(fout
, nspinfo
->dobj
.catId
, nspinfo
->dobj
.dumpId
,
6016 false, "SCHEMA", SECTION_PRE_DATA
,
6017 q
->data
, delq
->data
, NULL
,
6018 nspinfo
->dobj
.dependencies
, nspinfo
->dobj
.nDeps
,
6021 /* Dump Schema Comments */
6022 resetPQExpBuffer(q
);
6023 appendPQExpBuffer(q
, "SCHEMA %s", qnspname
);
6024 dumpComment(fout
, q
->data
,
6025 NULL
, nspinfo
->rolname
,
6026 nspinfo
->dobj
.catId
, 0, nspinfo
->dobj
.dumpId
);
6028 dumpACL(fout
, nspinfo
->dobj
.catId
, nspinfo
->dobj
.dumpId
, "SCHEMA",
6029 qnspname
, NULL
, nspinfo
->dobj
.name
, NULL
,
6030 nspinfo
->rolname
, nspinfo
->nspacl
);
6034 destroyPQExpBuffer(q
);
6035 destroyPQExpBuffer(delq
);
6040 * writes out to fout the queries to recreate a user-defined type
6043 dumpType(Archive
*fout
, TypeInfo
*tinfo
)
6045 /* Skip if not to be dumped */
6046 if (!tinfo
->dobj
.dump
|| dataOnly
)
6049 /* Dump out in proper style */
6050 if (tinfo
->typtype
== TYPTYPE_BASE
)
6051 dumpBaseType(fout
, tinfo
);
6052 else if (tinfo
->typtype
== TYPTYPE_DOMAIN
)
6053 dumpDomain(fout
, tinfo
);
6054 else if (tinfo
->typtype
== TYPTYPE_COMPOSITE
)
6055 dumpCompositeType(fout
, tinfo
);
6056 else if (tinfo
->typtype
== TYPTYPE_ENUM
)
6057 dumpEnumType(fout
, tinfo
);
6062 * writes out to fout the queries to recreate a user-defined enum type
6065 dumpEnumType(Archive
*fout
, TypeInfo
*tinfo
)
6067 PQExpBuffer q
= createPQExpBuffer();
6068 PQExpBuffer delq
= createPQExpBuffer();
6069 PQExpBuffer query
= createPQExpBuffer();
6075 /* Set proper schema search path so regproc references list correctly */
6076 selectSourceSchema(tinfo
->dobj
.namespace->dobj
.name
);
6078 appendPQExpBuffer(query
, "SELECT enumlabel FROM pg_catalog.pg_enum "
6079 "WHERE enumtypid = '%u'"
6081 tinfo
->dobj
.catId
.oid
);
6083 res
= PQexec(g_conn
, query
->data
);
6084 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
6086 num
= PQntuples(res
);
6087 /* should be at least 1 value */
6090 write_msg(NULL
, "no label definitions found for enum ID %u\n", tinfo
->dobj
.catId
.oid
);
6095 * DROP must be fully qualified in case same name appears in pg_catalog.
6096 * CASCADE shouldn't be required here as for normal types since the I/O
6097 * functions are generic and do not get dropped.
6099 appendPQExpBuffer(delq
, "DROP TYPE %s.",
6100 fmtId(tinfo
->dobj
.namespace->dobj
.name
));
6101 appendPQExpBuffer(delq
, "%s;\n",
6102 fmtId(tinfo
->dobj
.name
));
6103 appendPQExpBuffer(q
, "CREATE TYPE %s AS ENUM (\n",
6104 fmtId(tinfo
->dobj
.name
));
6105 for (i
= 0; i
< num
; i
++)
6107 label
= PQgetvalue(res
, i
, 0);
6109 appendPQExpBuffer(q
, ",\n");
6110 appendPQExpBuffer(q
, " ");
6111 appendStringLiteralAH(q
, label
, fout
);
6113 appendPQExpBuffer(q
, "\n);\n");
6115 ArchiveEntry(fout
, tinfo
->dobj
.catId
, tinfo
->dobj
.dumpId
,
6117 tinfo
->dobj
.namespace->dobj
.name
,
6119 tinfo
->rolname
, false,
6120 "TYPE", SECTION_PRE_DATA
,
6121 q
->data
, delq
->data
, NULL
,
6122 tinfo
->dobj
.dependencies
, tinfo
->dobj
.nDeps
,
6125 /* Dump Type Comments */
6126 resetPQExpBuffer(q
);
6128 appendPQExpBuffer(q
, "TYPE %s", fmtId(tinfo
->dobj
.name
));
6129 dumpComment(fout
, q
->data
,
6130 tinfo
->dobj
.namespace->dobj
.name
, tinfo
->rolname
,
6131 tinfo
->dobj
.catId
, 0, tinfo
->dobj
.dumpId
);
6134 destroyPQExpBuffer(q
);
6135 destroyPQExpBuffer(delq
);
6136 destroyPQExpBuffer(query
);
6141 * writes out to fout the queries to recreate a user-defined base type
6144 dumpBaseType(Archive
*fout
, TypeInfo
*tinfo
)
6146 PQExpBuffer q
= createPQExpBuffer();
6147 PQExpBuffer delq
= createPQExpBuffer();
6148 PQExpBuffer query
= createPQExpBuffer();
6167 char *typispreferred
;
6173 bool typdefault_is_literal
= false;
6175 /* Set proper schema search path so regproc references list correctly */
6176 selectSourceSchema(tinfo
->dobj
.namespace->dobj
.name
);
6178 /* Fetch type-specific details */
6179 if (fout
->remoteVersion
>= 80400)
6181 appendPQExpBuffer(query
, "SELECT typlen, "
6182 "typinput, typoutput, typreceive, typsend, "
6183 "typmodin, typmodout, typanalyze, "
6184 "typinput::pg_catalog.oid AS typinputoid, "
6185 "typoutput::pg_catalog.oid AS typoutputoid, "
6186 "typreceive::pg_catalog.oid AS typreceiveoid, "
6187 "typsend::pg_catalog.oid AS typsendoid, "
6188 "typmodin::pg_catalog.oid AS typmodinoid, "
6189 "typmodout::pg_catalog.oid AS typmodoutoid, "
6190 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6191 "typcategory, typispreferred, "
6192 "typdelim, typbyval, typalign, typstorage, "
6193 "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
6194 "FROM pg_catalog.pg_type "
6195 "WHERE oid = '%u'::pg_catalog.oid",
6196 tinfo
->dobj
.catId
.oid
);
6198 else if (fout
->remoteVersion
>= 80300)
6200 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
6201 appendPQExpBuffer(query
, "SELECT typlen, "
6202 "typinput, typoutput, typreceive, typsend, "
6203 "typmodin, typmodout, typanalyze, "
6204 "typinput::pg_catalog.oid AS typinputoid, "
6205 "typoutput::pg_catalog.oid AS typoutputoid, "
6206 "typreceive::pg_catalog.oid AS typreceiveoid, "
6207 "typsend::pg_catalog.oid AS typsendoid, "
6208 "typmodin::pg_catalog.oid AS typmodinoid, "
6209 "typmodout::pg_catalog.oid AS typmodoutoid, "
6210 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6211 "'U' AS typcategory, false AS typispreferred, "
6212 "typdelim, typbyval, typalign, typstorage, "
6213 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6214 "FROM pg_catalog.pg_type "
6215 "WHERE oid = '%u'::pg_catalog.oid",
6216 tinfo
->dobj
.catId
.oid
);
6218 else if (fout
->remoteVersion
>= 80000)
6220 appendPQExpBuffer(query
, "SELECT typlen, "
6221 "typinput, typoutput, typreceive, typsend, "
6222 "'-' AS typmodin, '-' AS typmodout, "
6224 "typinput::pg_catalog.oid AS typinputoid, "
6225 "typoutput::pg_catalog.oid AS typoutputoid, "
6226 "typreceive::pg_catalog.oid AS typreceiveoid, "
6227 "typsend::pg_catalog.oid AS typsendoid, "
6228 "0 AS typmodinoid, 0 AS typmodoutoid, "
6229 "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6230 "'U' AS typcategory, false AS typispreferred, "
6231 "typdelim, typbyval, typalign, typstorage, "
6232 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6233 "FROM pg_catalog.pg_type "
6234 "WHERE oid = '%u'::pg_catalog.oid",
6235 tinfo
->dobj
.catId
.oid
);
6237 else if (fout
->remoteVersion
>= 70400)
6239 appendPQExpBuffer(query
, "SELECT typlen, "
6240 "typinput, typoutput, typreceive, typsend, "
6241 "'-' AS typmodin, '-' AS typmodout, "
6242 "'-' AS typanalyze, "
6243 "typinput::pg_catalog.oid AS typinputoid, "
6244 "typoutput::pg_catalog.oid AS typoutputoid, "
6245 "typreceive::pg_catalog.oid AS typreceiveoid, "
6246 "typsend::pg_catalog.oid AS typsendoid, "
6247 "0 AS typmodinoid, 0 AS typmodoutoid, "
6248 "0 AS typanalyzeoid, "
6249 "'U' AS typcategory, false AS typispreferred, "
6250 "typdelim, typbyval, typalign, typstorage, "
6251 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6252 "FROM pg_catalog.pg_type "
6253 "WHERE oid = '%u'::pg_catalog.oid",
6254 tinfo
->dobj
.catId
.oid
);
6256 else if (fout
->remoteVersion
>= 70300)
6258 appendPQExpBuffer(query
, "SELECT typlen, "
6259 "typinput, typoutput, "
6260 "'-' AS typreceive, '-' AS typsend, "
6261 "'-' AS typmodin, '-' AS typmodout, "
6262 "'-' AS typanalyze, "
6263 "typinput::pg_catalog.oid AS typinputoid, "
6264 "typoutput::pg_catalog.oid AS typoutputoid, "
6265 "0 AS typreceiveoid, 0 AS typsendoid, "
6266 "0 AS typmodinoid, 0 AS typmodoutoid, "
6267 "0 AS typanalyzeoid, "
6268 "'U' AS typcategory, false AS typispreferred, "
6269 "typdelim, typbyval, typalign, typstorage, "
6270 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6271 "FROM pg_catalog.pg_type "
6272 "WHERE oid = '%u'::pg_catalog.oid",
6273 tinfo
->dobj
.catId
.oid
);
6275 else if (fout
->remoteVersion
>= 70200)
6278 * Note: although pre-7.3 catalogs contain typreceive and typsend,
6279 * ignore them because they are not right.
6281 appendPQExpBuffer(query
, "SELECT typlen, "
6282 "typinput, typoutput, "
6283 "'-' AS typreceive, '-' AS typsend, "
6284 "'-' AS typmodin, '-' AS typmodout, "
6285 "'-' AS typanalyze, "
6286 "typinput::oid AS typinputoid, "
6287 "typoutput::oid AS typoutputoid, "
6288 "0 AS typreceiveoid, 0 AS typsendoid, "
6289 "0 AS typmodinoid, 0 AS typmodoutoid, "
6290 "0 AS typanalyzeoid, "
6291 "'U' AS typcategory, false AS typispreferred, "
6292 "typdelim, typbyval, typalign, typstorage, "
6293 "NULL AS typdefaultbin, typdefault "
6295 "WHERE oid = '%u'::oid",
6296 tinfo
->dobj
.catId
.oid
);
6298 else if (fout
->remoteVersion
>= 70100)
6301 * Ignore pre-7.2 typdefault; the field exists but has an unusable
6304 appendPQExpBuffer(query
, "SELECT typlen, "
6305 "typinput, typoutput, "
6306 "'-' AS typreceive, '-' AS typsend, "
6307 "'-' AS typmodin, '-' AS typmodout, "
6308 "'-' AS typanalyze, "
6309 "typinput::oid AS typinputoid, "
6310 "typoutput::oid AS typoutputoid, "
6311 "0 AS typreceiveoid, 0 AS typsendoid, "
6312 "0 AS typmodinoid, 0 AS typmodoutoid, "
6313 "0 AS typanalyzeoid, "
6314 "'U' AS typcategory, false AS typispreferred, "
6315 "typdelim, typbyval, typalign, typstorage, "
6316 "NULL AS typdefaultbin, NULL AS typdefault "
6318 "WHERE oid = '%u'::oid",
6319 tinfo
->dobj
.catId
.oid
);
6323 appendPQExpBuffer(query
, "SELECT typlen, "
6324 "typinput, typoutput, "
6325 "'-' AS typreceive, '-' AS typsend, "
6326 "'-' AS typmodin, '-' AS typmodout, "
6327 "'-' AS typanalyze, "
6328 "typinput::oid AS typinputoid, "
6329 "typoutput::oid AS typoutputoid, "
6330 "0 AS typreceiveoid, 0 AS typsendoid, "
6331 "0 AS typmodinoid, 0 AS typmodoutoid, "
6332 "0 AS typanalyzeoid, "
6333 "'U' AS typcategory, false AS typispreferred, "
6334 "typdelim, typbyval, typalign, "
6335 "'p'::char AS typstorage, "
6336 "NULL AS typdefaultbin, NULL AS typdefault "
6338 "WHERE oid = '%u'::oid",
6339 tinfo
->dobj
.catId
.oid
);
6342 res
= PQexec(g_conn
, query
->data
);
6343 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
6345 /* Expecting a single result only */
6346 ntups
= PQntuples(res
);
6349 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
6350 "query returned %d rows instead of one: %s\n",
6352 ntups
, query
->data
);
6356 typlen
= PQgetvalue(res
, 0, PQfnumber(res
, "typlen"));
6357 typinput
= PQgetvalue(res
, 0, PQfnumber(res
, "typinput"));
6358 typoutput
= PQgetvalue(res
, 0, PQfnumber(res
, "typoutput"));
6359 typreceive
= PQgetvalue(res
, 0, PQfnumber(res
, "typreceive"));
6360 typsend
= PQgetvalue(res
, 0, PQfnumber(res
, "typsend"));
6361 typmodin
= PQgetvalue(res
, 0, PQfnumber(res
, "typmodin"));
6362 typmodout
= PQgetvalue(res
, 0, PQfnumber(res
, "typmodout"));
6363 typanalyze
= PQgetvalue(res
, 0, PQfnumber(res
, "typanalyze"));
6364 typinputoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typinputoid")));
6365 typoutputoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typoutputoid")));
6366 typreceiveoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typreceiveoid")));
6367 typsendoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typsendoid")));
6368 typmodinoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typmodinoid")));
6369 typmodoutoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typmodoutoid")));
6370 typanalyzeoid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "typanalyzeoid")));
6371 typcategory
= PQgetvalue(res
, 0, PQfnumber(res
, "typcategory"));
6372 typispreferred
= PQgetvalue(res
, 0, PQfnumber(res
, "typispreferred"));
6373 typdelim
= PQgetvalue(res
, 0, PQfnumber(res
, "typdelim"));
6374 typbyval
= PQgetvalue(res
, 0, PQfnumber(res
, "typbyval"));
6375 typalign
= PQgetvalue(res
, 0, PQfnumber(res
, "typalign"));
6376 typstorage
= PQgetvalue(res
, 0, PQfnumber(res
, "typstorage"));
6377 if (!PQgetisnull(res
, 0, PQfnumber(res
, "typdefaultbin")))
6378 typdefault
= PQgetvalue(res
, 0, PQfnumber(res
, "typdefaultbin"));
6379 else if (!PQgetisnull(res
, 0, PQfnumber(res
, "typdefault")))
6381 typdefault
= PQgetvalue(res
, 0, PQfnumber(res
, "typdefault"));
6382 typdefault_is_literal
= true; /* it needs quotes */
6388 * DROP must be fully qualified in case same name appears in pg_catalog.
6389 * The reason we include CASCADE is that the circular dependency between
6390 * the type and its I/O functions makes it impossible to drop the type any
6393 appendPQExpBuffer(delq
, "DROP TYPE %s.",
6394 fmtId(tinfo
->dobj
.namespace->dobj
.name
));
6395 appendPQExpBuffer(delq
, "%s CASCADE;\n",
6396 fmtId(tinfo
->dobj
.name
));
6398 appendPQExpBuffer(q
,
6399 "CREATE TYPE %s (\n"
6400 " INTERNALLENGTH = %s",
6401 fmtId(tinfo
->dobj
.name
),
6402 (strcmp(typlen
, "-1") == 0) ? "variable" : typlen
);
6404 if (fout
->remoteVersion
>= 70300)
6406 /* regproc result is correctly quoted as of 7.3 */
6407 appendPQExpBuffer(q
, ",\n INPUT = %s", typinput
);
6408 appendPQExpBuffer(q
, ",\n OUTPUT = %s", typoutput
);
6409 if (OidIsValid(typreceiveoid
))
6410 appendPQExpBuffer(q
, ",\n RECEIVE = %s", typreceive
);
6411 if (OidIsValid(typsendoid
))
6412 appendPQExpBuffer(q
, ",\n SEND = %s", typsend
);
6413 if (OidIsValid(typmodinoid
))
6414 appendPQExpBuffer(q
, ",\n TYPMOD_IN = %s", typmodin
);
6415 if (OidIsValid(typmodoutoid
))
6416 appendPQExpBuffer(q
, ",\n TYPMOD_OUT = %s", typmodout
);
6417 if (OidIsValid(typanalyzeoid
))
6418 appendPQExpBuffer(q
, ",\n ANALYZE = %s", typanalyze
);
6422 /* regproc delivers an unquoted name before 7.3 */
6423 /* cannot combine these because fmtId uses static result area */
6424 appendPQExpBuffer(q
, ",\n INPUT = %s", fmtId(typinput
));
6425 appendPQExpBuffer(q
, ",\n OUTPUT = %s", fmtId(typoutput
));
6426 /* receive/send/typmodin/typmodout/analyze need not be printed */
6429 if (typdefault
!= NULL
)
6431 appendPQExpBuffer(q
, ",\n DEFAULT = ");
6432 if (typdefault_is_literal
)
6433 appendStringLiteralAH(q
, typdefault
, fout
);
6435 appendPQExpBufferStr(q
, typdefault
);
6438 if (OidIsValid(tinfo
->typelem
))
6442 /* reselect schema in case changed by function dump */
6443 selectSourceSchema(tinfo
->dobj
.namespace->dobj
.name
);
6444 elemType
= getFormattedTypeName(tinfo
->typelem
, zeroAsOpaque
);
6445 appendPQExpBuffer(q
, ",\n ELEMENT = %s", elemType
);
6449 if (strcmp(typcategory
, "U") != 0)
6451 appendPQExpBuffer(q
, ",\n CATEGORY = ");
6452 appendStringLiteralAH(q
, typcategory
, fout
);
6455 if (strcmp(typispreferred
, "t") == 0)
6456 appendPQExpBuffer(q
, ",\n PREFERRED = true");
6458 if (typdelim
&& strcmp(typdelim
, ",") != 0)
6460 appendPQExpBuffer(q
, ",\n DELIMITER = ");
6461 appendStringLiteralAH(q
, typdelim
, fout
);
6464 if (strcmp(typalign
, "c") == 0)
6465 appendPQExpBuffer(q
, ",\n ALIGNMENT = char");
6466 else if (strcmp(typalign
, "s") == 0)
6467 appendPQExpBuffer(q
, ",\n ALIGNMENT = int2");
6468 else if (strcmp(typalign
, "i") == 0)
6469 appendPQExpBuffer(q
, ",\n ALIGNMENT = int4");
6470 else if (strcmp(typalign
, "d") == 0)
6471 appendPQExpBuffer(q
, ",\n ALIGNMENT = double");
6473 if (strcmp(typstorage
, "p") == 0)
6474 appendPQExpBuffer(q
, ",\n STORAGE = plain");
6475 else if (strcmp(typstorage
, "e") == 0)
6476 appendPQExpBuffer(q
, ",\n STORAGE = external");
6477 else if (strcmp(typstorage
, "x") == 0)
6478 appendPQExpBuffer(q
, ",\n STORAGE = extended");
6479 else if (strcmp(typstorage
, "m") == 0)
6480 appendPQExpBuffer(q
, ",\n STORAGE = main");
6482 if (strcmp(typbyval
, "t") == 0)
6483 appendPQExpBuffer(q
, ",\n PASSEDBYVALUE");
6485 appendPQExpBuffer(q
, "\n);\n");
6487 ArchiveEntry(fout
, tinfo
->dobj
.catId
, tinfo
->dobj
.dumpId
,
6489 tinfo
->dobj
.namespace->dobj
.name
,
6491 tinfo
->rolname
, false,
6492 "TYPE", SECTION_PRE_DATA
,
6493 q
->data
, delq
->data
, NULL
,
6494 tinfo
->dobj
.dependencies
, tinfo
->dobj
.nDeps
,
6497 /* Dump Type Comments */
6498 resetPQExpBuffer(q
);
6500 appendPQExpBuffer(q
, "TYPE %s", fmtId(tinfo
->dobj
.name
));
6501 dumpComment(fout
, q
->data
,
6502 tinfo
->dobj
.namespace->dobj
.name
, tinfo
->rolname
,
6503 tinfo
->dobj
.catId
, 0, tinfo
->dobj
.dumpId
);
6506 destroyPQExpBuffer(q
);
6507 destroyPQExpBuffer(delq
);
6508 destroyPQExpBuffer(query
);
6513 * writes out to fout the queries to recreate a user-defined domain
6516 dumpDomain(Archive
*fout
, TypeInfo
*tinfo
)
6518 PQExpBuffer q
= createPQExpBuffer();
6519 PQExpBuffer delq
= createPQExpBuffer();
6520 PQExpBuffer query
= createPQExpBuffer();
6527 bool typdefault_is_literal
= false;
6529 /* Set proper schema search path so type references list correctly */
6530 selectSourceSchema(tinfo
->dobj
.namespace->dobj
.name
);
6532 /* Fetch domain specific details */
6533 /* We assume here that remoteVersion must be at least 70300 */
6534 appendPQExpBuffer(query
, "SELECT typnotnull, "
6535 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
6536 "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6537 "FROM pg_catalog.pg_type "
6538 "WHERE oid = '%u'::pg_catalog.oid",
6539 tinfo
->dobj
.catId
.oid
);
6541 res
= PQexec(g_conn
, query
->data
);
6542 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
6544 /* Expecting a single result only */
6545 ntups
= PQntuples(res
);
6548 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
6549 "query returned %d rows instead of one: %s\n",
6551 ntups
, query
->data
);
6555 typnotnull
= PQgetvalue(res
, 0, PQfnumber(res
, "typnotnull"));
6556 typdefn
= PQgetvalue(res
, 0, PQfnumber(res
, "typdefn"));
6557 if (!PQgetisnull(res
, 0, PQfnumber(res
, "typdefaultbin")))
6558 typdefault
= PQgetvalue(res
, 0, PQfnumber(res
, "typdefaultbin"));
6559 else if (!PQgetisnull(res
, 0, PQfnumber(res
, "typdefault")))
6561 typdefault
= PQgetvalue(res
, 0, PQfnumber(res
, "typdefault"));
6562 typdefault_is_literal
= true; /* it needs quotes */
6567 appendPQExpBuffer(q
,
6568 "CREATE DOMAIN %s AS %s",
6569 fmtId(tinfo
->dobj
.name
),
6572 if (typnotnull
[0] == 't')
6573 appendPQExpBuffer(q
, " NOT NULL");
6575 if (typdefault
!= NULL
)
6577 appendPQExpBuffer(q
, " DEFAULT ");
6578 if (typdefault_is_literal
)
6579 appendStringLiteralAH(q
, typdefault
, fout
);
6581 appendPQExpBufferStr(q
, typdefault
);
6587 * Add any CHECK constraints for the domain
6589 for (i
= 0; i
< tinfo
->nDomChecks
; i
++)
6591 ConstraintInfo
*domcheck
= &(tinfo
->domChecks
[i
]);
6593 if (!domcheck
->separate
)
6594 appendPQExpBuffer(q
, "\n\tCONSTRAINT %s %s",
6595 fmtId(domcheck
->dobj
.name
), domcheck
->condef
);
6598 appendPQExpBuffer(q
, ";\n");
6601 * DROP must be fully qualified in case same name appears in pg_catalog
6603 appendPQExpBuffer(delq
, "DROP DOMAIN %s.",
6604 fmtId(tinfo
->dobj
.namespace->dobj
.name
));
6605 appendPQExpBuffer(delq
, "%s;\n",
6606 fmtId(tinfo
->dobj
.name
));
6608 ArchiveEntry(fout
, tinfo
->dobj
.catId
, tinfo
->dobj
.dumpId
,
6610 tinfo
->dobj
.namespace->dobj
.name
,
6612 tinfo
->rolname
, false,
6613 "DOMAIN", SECTION_PRE_DATA
,
6614 q
->data
, delq
->data
, NULL
,
6615 tinfo
->dobj
.dependencies
, tinfo
->dobj
.nDeps
,
6618 /* Dump Domain Comments */
6619 resetPQExpBuffer(q
);
6621 appendPQExpBuffer(q
, "DOMAIN %s", fmtId(tinfo
->dobj
.name
));
6622 dumpComment(fout
, q
->data
,
6623 tinfo
->dobj
.namespace->dobj
.name
, tinfo
->rolname
,
6624 tinfo
->dobj
.catId
, 0, tinfo
->dobj
.dumpId
);
6626 destroyPQExpBuffer(q
);
6627 destroyPQExpBuffer(delq
);
6628 destroyPQExpBuffer(query
);
6633 * writes out to fout the queries to recreate a user-defined stand-alone
6637 dumpCompositeType(Archive
*fout
, TypeInfo
*tinfo
)
6639 PQExpBuffer q
= createPQExpBuffer();
6640 PQExpBuffer delq
= createPQExpBuffer();
6641 PQExpBuffer query
= createPQExpBuffer();
6648 /* Set proper schema search path so type references list correctly */
6649 selectSourceSchema(tinfo
->dobj
.namespace->dobj
.name
);
6651 /* Fetch type specific details */
6652 /* We assume here that remoteVersion must be at least 70300 */
6654 appendPQExpBuffer(query
, "SELECT a.attname, "
6655 "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn "
6656 "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6657 "WHERE t.oid = '%u'::pg_catalog.oid "
6658 "AND a.attrelid = t.typrelid "
6659 "AND NOT a.attisdropped "
6660 "ORDER BY a.attnum ",
6661 tinfo
->dobj
.catId
.oid
);
6663 res
= PQexec(g_conn
, query
->data
);
6664 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
6666 /* Expecting at least a single result */
6667 ntups
= PQntuples(res
);
6670 write_msg(NULL
, "query returned no rows: %s\n", query
->data
);
6674 i_attname
= PQfnumber(res
, "attname");
6675 i_atttypdefn
= PQfnumber(res
, "atttypdefn");
6677 appendPQExpBuffer(q
, "CREATE TYPE %s AS (",
6678 fmtId(tinfo
->dobj
.name
));
6680 for (i
= 0; i
< ntups
; i
++)
6685 attname
= PQgetvalue(res
, i
, i_attname
);
6686 atttypdefn
= PQgetvalue(res
, i
, i_atttypdefn
);
6688 appendPQExpBuffer(q
, "\n\t%s %s", fmtId(attname
), atttypdefn
);
6690 appendPQExpBuffer(q
, ",");
6692 appendPQExpBuffer(q
, "\n);\n");
6695 * DROP must be fully qualified in case same name appears in pg_catalog
6697 appendPQExpBuffer(delq
, "DROP TYPE %s.",
6698 fmtId(tinfo
->dobj
.namespace->dobj
.name
));
6699 appendPQExpBuffer(delq
, "%s;\n",
6700 fmtId(tinfo
->dobj
.name
));
6702 ArchiveEntry(fout
, tinfo
->dobj
.catId
, tinfo
->dobj
.dumpId
,
6704 tinfo
->dobj
.namespace->dobj
.name
,
6706 tinfo
->rolname
, false,
6707 "TYPE", SECTION_PRE_DATA
,
6708 q
->data
, delq
->data
, NULL
,
6709 tinfo
->dobj
.dependencies
, tinfo
->dobj
.nDeps
,
6713 /* Dump Type Comments */
6714 resetPQExpBuffer(q
);
6716 appendPQExpBuffer(q
, "TYPE %s", fmtId(tinfo
->dobj
.name
));
6717 dumpComment(fout
, q
->data
,
6718 tinfo
->dobj
.namespace->dobj
.name
, tinfo
->rolname
,
6719 tinfo
->dobj
.catId
, 0, tinfo
->dobj
.dumpId
);
6722 destroyPQExpBuffer(q
);
6723 destroyPQExpBuffer(delq
);
6724 destroyPQExpBuffer(query
);
6729 * writes out to fout the queries to create a shell type
6731 * We dump a shell definition in advance of the I/O functions for the type.
6734 dumpShellType(Archive
*fout
, ShellTypeInfo
*stinfo
)
6738 /* Skip if not to be dumped */
6739 if (!stinfo
->dobj
.dump
|| dataOnly
)
6742 q
= createPQExpBuffer();
6745 * Note the lack of a DROP command for the shell type; any required DROP
6746 * is driven off the base type entry, instead. This interacts with
6747 * _printTocEntry()'s use of the presence of a DROP command to decide
6748 * whether an entry needs an ALTER OWNER command. We don't want to alter
6749 * the shell type's owner immediately on creation; that should happen only
6750 * after it's filled in, otherwise the backend complains.
6753 appendPQExpBuffer(q
, "CREATE TYPE %s;\n",
6754 fmtId(stinfo
->dobj
.name
));
6756 ArchiveEntry(fout
, stinfo
->dobj
.catId
, stinfo
->dobj
.dumpId
,
6758 stinfo
->dobj
.namespace->dobj
.name
,
6760 stinfo
->baseType
->rolname
, false,
6761 "SHELL TYPE", SECTION_PRE_DATA
,
6763 stinfo
->dobj
.dependencies
, stinfo
->dobj
.nDeps
,
6766 destroyPQExpBuffer(q
);
6770 * Determine whether we want to dump definitions for procedural languages.
6771 * Since the languages themselves don't have schemas, we can't rely on
6772 * the normal schema-based selection mechanism. We choose to dump them
6773 * whenever neither --schema nor --table was given. (Before 8.1, we used
6774 * the dump flag of the PL's call handler function, but in 8.1 this will
6775 * probably always be false since call handlers are created in pg_catalog.)
6777 * For some backwards compatibility with the older behavior, we forcibly
6778 * dump a PL if its handler function (and validator if any) are in a
6779 * dumpable namespace. That case is not checked here.
6782 shouldDumpProcLangs(void)
6784 if (!include_everything
)
6786 /* And they're schema not data */
6794 * writes out to fout the queries to recreate a user-defined
6795 * procedural language
6798 dumpProcLang(Archive
*fout
, ProcLangInfo
*plang
)
6806 FuncInfo
*validatorInfo
= NULL
;
6812 * Try to find the support function(s). It is not an error if we don't
6813 * find them --- if the functions are in the pg_catalog schema, as is
6814 * standard in 8.1 and up, then we won't have loaded them. (In this case
6815 * we will emit a parameterless CREATE LANGUAGE command, which will
6816 * require PL template knowledge in the backend to reload.)
6819 funcInfo
= findFuncByOid(plang
->lanplcallfoid
);
6820 if (funcInfo
!= NULL
&& !funcInfo
->dobj
.dump
)
6821 funcInfo
= NULL
; /* treat not-dumped same as not-found */
6823 if (OidIsValid(plang
->lanvalidator
))
6825 validatorInfo
= findFuncByOid(plang
->lanvalidator
);
6826 if (validatorInfo
!= NULL
&& !validatorInfo
->dobj
.dump
)
6827 validatorInfo
= NULL
;
6831 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6832 * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
6835 useParams
= (funcInfo
!= NULL
&&
6836 (validatorInfo
!= NULL
|| !OidIsValid(plang
->lanvalidator
)));
6838 if (!useParams
&& !shouldDumpProcLangs())
6841 defqry
= createPQExpBuffer();
6842 delqry
= createPQExpBuffer();
6844 qlanname
= strdup(fmtId(plang
->dobj
.name
));
6847 * If dumping a HANDLER clause, treat the language as being in the handler
6848 * function's schema; this avoids cluttering the HANDLER clause. Otherwise
6849 * it doesn't really have a schema.
6852 lanschema
= funcInfo
->dobj
.namespace->dobj
.name
;
6856 appendPQExpBuffer(delqry
, "DROP PROCEDURAL LANGUAGE %s;\n",
6859 appendPQExpBuffer(defqry
, "CREATE %sPROCEDURAL LANGUAGE %s",
6860 (useParams
&& plang
->lanpltrusted
) ? "TRUSTED " : "",
6864 appendPQExpBuffer(defqry
, " HANDLER %s",
6865 fmtId(funcInfo
->dobj
.name
));
6866 if (OidIsValid(plang
->lanvalidator
))
6868 appendPQExpBuffer(defqry
, " VALIDATOR ");
6869 /* Cope with possibility that validator is in different schema */
6870 if (validatorInfo
->dobj
.namespace != funcInfo
->dobj
.namespace)
6871 appendPQExpBuffer(defqry
, "%s.",
6872 fmtId(validatorInfo
->dobj
.namespace->dobj
.name
));
6873 appendPQExpBuffer(defqry
, "%s",
6874 fmtId(validatorInfo
->dobj
.name
));
6877 appendPQExpBuffer(defqry
, ";\n");
6879 ArchiveEntry(fout
, plang
->dobj
.catId
, plang
->dobj
.dumpId
,
6881 lanschema
, NULL
, plang
->lanowner
,
6882 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA
,
6883 defqry
->data
, delqry
->data
, NULL
,
6884 plang
->dobj
.dependencies
, plang
->dobj
.nDeps
,
6887 /* Dump Proc Lang Comments */
6888 resetPQExpBuffer(defqry
);
6889 appendPQExpBuffer(defqry
, "LANGUAGE %s", qlanname
);
6890 dumpComment(fout
, defqry
->data
,
6892 plang
->dobj
.catId
, 0, plang
->dobj
.dumpId
);
6894 if (plang
->lanpltrusted
)
6895 dumpACL(fout
, plang
->dobj
.catId
, plang
->dobj
.dumpId
, "LANGUAGE",
6896 qlanname
, NULL
, plang
->dobj
.name
,
6898 plang
->lanowner
, plang
->lanacl
);
6902 destroyPQExpBuffer(defqry
);
6903 destroyPQExpBuffer(delqry
);
6907 * format_function_arguments: generate function name and argument list
6909 * This is used when we can rely on pg_get_function_arguments to format
6910 * the argument list.
6913 format_function_arguments(FuncInfo
*finfo
, char *funcargs
)
6917 initPQExpBuffer(&fn
);
6918 appendPQExpBuffer(&fn
, "%s(%s)", fmtId(finfo
->dobj
.name
), funcargs
);
6923 * format_function_arguments_old: generate function name and argument list
6925 * The argument type names are qualified if needed. The function name
6926 * is never qualified.
6928 * This is used only with pre-8.4 servers, so we aren't expecting to see
6929 * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
6931 * Any or all of allargtypes, argmodes, argnames may be NULL.
6934 format_function_arguments_old(FuncInfo
*finfo
, int nallargs
,
6942 initPQExpBuffer(&fn
);
6943 appendPQExpBuffer(&fn
, "%s(", fmtId(finfo
->dobj
.name
));
6944 for (j
= 0; j
< nallargs
; j
++)
6948 const char *argmode
;
6949 const char *argname
;
6951 typid
= allargtypes
? atooid(allargtypes
[j
]) : finfo
->argtypes
[j
];
6952 typname
= getFormattedTypeName(typid
, zeroAsOpaque
);
6956 switch (argmodes
[j
][0])
6961 case PROARGMODE_OUT
:
6964 case PROARGMODE_INOUT
:
6968 write_msg(NULL
, "WARNING: bogus value in proargmodes array\n");
6976 argname
= argnames
? argnames
[j
] : (char *) NULL
;
6977 if (argname
&& argname
[0] == '\0')
6980 appendPQExpBuffer(&fn
, "%s%s%s%s%s",
6981 (j
> 0) ? ", " : "",
6983 argname
? fmtId(argname
) : "",
6988 appendPQExpBuffer(&fn
, ")");
6993 * format_function_signature: generate function name and argument list
6995 * This is like format_function_arguments_old except that only a minimal
6996 * list of input argument types is generated; this is sufficient to
6997 * reference the function, but not to define it.
6999 * If honor_quotes is false then the function name is never quoted.
7000 * This is appropriate for use in TOC tags, but not in SQL commands.
7003 format_function_signature(FuncInfo
*finfo
, bool honor_quotes
)
7008 initPQExpBuffer(&fn
);
7010 appendPQExpBuffer(&fn
, "%s(", fmtId(finfo
->dobj
.name
));
7012 appendPQExpBuffer(&fn
, "%s(", finfo
->dobj
.name
);
7013 for (j
= 0; j
< finfo
->nargs
; j
++)
7017 typname
= getFormattedTypeName(finfo
->argtypes
[j
], zeroAsOpaque
);
7019 appendPQExpBuffer(&fn
, "%s%s",
7020 (j
> 0) ? ", " : "",
7024 appendPQExpBuffer(&fn
, ")");
7031 * dump out one function
7034 dumpFunc(Archive
*fout
, FuncInfo
*finfo
)
7041 char *funcsig
; /* identity signature */
7042 char *funcfullsig
; /* full signature */
7051 char *proallargtypes
;
7064 char **allargtypes
= NULL
;
7065 char **argmodes
= NULL
;
7066 char **argnames
= NULL
;
7067 char **configitems
= NULL
;
7068 int nconfigitems
= 0;
7071 /* Skip if not to be dumped */
7072 if (!finfo
->dobj
.dump
|| dataOnly
)
7075 query
= createPQExpBuffer();
7076 q
= createPQExpBuffer();
7077 delqry
= createPQExpBuffer();
7078 asPart
= createPQExpBuffer();
7080 /* Set proper schema search path so type references list correctly */
7081 selectSourceSchema(finfo
->dobj
.namespace->dobj
.name
);
7083 /* Fetch function-specific details */
7084 if (g_fout
->remoteVersion
>= 80400)
7087 * In 8.4 and up we rely on pg_get_function_arguments and
7088 * pg_get_function_result instead of examining proallargtypes etc.
7090 appendPQExpBuffer(query
,
7091 "SELECT proretset, prosrc, probin, "
7092 "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
7093 "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
7094 "pg_catalog.pg_get_function_result(oid) AS funcresult, "
7095 "proiswindow, provolatile, proisstrict, prosecdef, "
7096 "proconfig, procost, prorows, "
7097 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7098 "FROM pg_catalog.pg_proc "
7099 "WHERE oid = '%u'::pg_catalog.oid",
7100 finfo
->dobj
.catId
.oid
);
7102 else if (g_fout
->remoteVersion
>= 80300)
7104 appendPQExpBuffer(query
,
7105 "SELECT proretset, prosrc, probin, "
7106 "proallargtypes, proargmodes, proargnames, "
7107 "false AS proiswindow, "
7108 "provolatile, proisstrict, prosecdef, "
7109 "proconfig, procost, prorows, "
7110 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7111 "FROM pg_catalog.pg_proc "
7112 "WHERE oid = '%u'::pg_catalog.oid",
7113 finfo
->dobj
.catId
.oid
);
7115 else if (g_fout
->remoteVersion
>= 80100)
7117 appendPQExpBuffer(query
,
7118 "SELECT proretset, prosrc, probin, "
7119 "proallargtypes, proargmodes, proargnames, "
7120 "false AS proiswindow, "
7121 "provolatile, proisstrict, prosecdef, "
7122 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7123 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7124 "FROM pg_catalog.pg_proc "
7125 "WHERE oid = '%u'::pg_catalog.oid",
7126 finfo
->dobj
.catId
.oid
);
7128 else if (g_fout
->remoteVersion
>= 80000)
7130 appendPQExpBuffer(query
,
7131 "SELECT proretset, prosrc, probin, "
7132 "null AS proallargtypes, "
7133 "null AS proargmodes, "
7135 "false AS proiswindow, "
7136 "provolatile, proisstrict, prosecdef, "
7137 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7138 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7139 "FROM pg_catalog.pg_proc "
7140 "WHERE oid = '%u'::pg_catalog.oid",
7141 finfo
->dobj
.catId
.oid
);
7143 else if (g_fout
->remoteVersion
>= 70300)
7145 appendPQExpBuffer(query
,
7146 "SELECT proretset, prosrc, probin, "
7147 "null AS proallargtypes, "
7148 "null AS proargmodes, "
7149 "null AS proargnames, "
7150 "false AS proiswindow, "
7151 "provolatile, proisstrict, prosecdef, "
7152 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7153 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7154 "FROM pg_catalog.pg_proc "
7155 "WHERE oid = '%u'::pg_catalog.oid",
7156 finfo
->dobj
.catId
.oid
);
7158 else if (g_fout
->remoteVersion
>= 70100)
7160 appendPQExpBuffer(query
,
7161 "SELECT proretset, prosrc, probin, "
7162 "null AS proallargtypes, "
7163 "null AS proargmodes, "
7164 "null AS proargnames, "
7165 "false AS proiswindow, "
7166 "case when proiscachable then 'i' else 'v' end AS provolatile, "
7168 "false AS prosecdef, "
7169 "null AS proconfig, 0 AS procost, 0 AS prorows, "
7170 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7172 "WHERE oid = '%u'::oid",
7173 finfo
->dobj
.catId
.oid
);
7177 appendPQExpBuffer(query
,
7178 "SELECT proretset, prosrc, probin, "
7179 "null AS proallargtypes, "
7180 "null AS proargmodes, "
7181 "null AS proargnames, "
7182 "false AS proiswindow, "
7183 "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
7184 "false AS proisstrict, "
7185 "false AS prosecdef, "
7186 "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
7187 "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7189 "WHERE oid = '%u'::oid",
7190 finfo
->dobj
.catId
.oid
);
7193 res
= PQexec(g_conn
, query
->data
);
7194 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
7196 /* Expecting a single result only */
7197 ntups
= PQntuples(res
);
7200 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
7201 "query returned %d rows instead of one: %s\n",
7203 ntups
, query
->data
);
7207 proretset
= PQgetvalue(res
, 0, PQfnumber(res
, "proretset"));
7208 prosrc
= PQgetvalue(res
, 0, PQfnumber(res
, "prosrc"));
7209 probin
= PQgetvalue(res
, 0, PQfnumber(res
, "probin"));
7210 if (g_fout
->remoteVersion
>= 80400)
7212 funcargs
= PQgetvalue(res
, 0, PQfnumber(res
, "funcargs"));
7213 funciargs
= PQgetvalue(res
, 0, PQfnumber(res
, "funciargs"));
7214 funcresult
= PQgetvalue(res
, 0, PQfnumber(res
, "funcresult"));
7215 proallargtypes
= proargmodes
= proargnames
= NULL
;
7219 proallargtypes
= PQgetvalue(res
, 0, PQfnumber(res
, "proallargtypes"));
7220 proargmodes
= PQgetvalue(res
, 0, PQfnumber(res
, "proargmodes"));
7221 proargnames
= PQgetvalue(res
, 0, PQfnumber(res
, "proargnames"));
7222 funcargs
= funciargs
= funcresult
= NULL
;
7224 proiswindow
= PQgetvalue(res
, 0, PQfnumber(res
, "proiswindow"));
7225 provolatile
= PQgetvalue(res
, 0, PQfnumber(res
, "provolatile"));
7226 proisstrict
= PQgetvalue(res
, 0, PQfnumber(res
, "proisstrict"));
7227 prosecdef
= PQgetvalue(res
, 0, PQfnumber(res
, "prosecdef"));
7228 proconfig
= PQgetvalue(res
, 0, PQfnumber(res
, "proconfig"));
7229 procost
= PQgetvalue(res
, 0, PQfnumber(res
, "procost"));
7230 prorows
= PQgetvalue(res
, 0, PQfnumber(res
, "prorows"));
7231 lanname
= PQgetvalue(res
, 0, PQfnumber(res
, "lanname"));
7234 * See backend/commands/functioncmds.c for details of how the 'AS' clause
7235 * is used. In 8.4 and up, an unused probin is NULL (here ""); previous
7236 * versions would set it to "-". There are no known cases in which prosrc
7237 * is unused, so the tests below for "-" are probably useless.
7239 if (probin
[0] != '\0' && strcmp(probin
, "-") != 0)
7241 appendPQExpBuffer(asPart
, "AS ");
7242 appendStringLiteralAH(asPart
, probin
, fout
);
7243 if (strcmp(prosrc
, "-") != 0)
7245 appendPQExpBuffer(asPart
, ", ");
7248 * where we have bin, use dollar quoting if allowed and src
7249 * contains quote or backslash; else use regular quoting.
7251 if (disable_dollar_quoting
||
7252 (strchr(prosrc
, '\'') == NULL
&& strchr(prosrc
, '\\') == NULL
))
7253 appendStringLiteralAH(asPart
, prosrc
, fout
);
7255 appendStringLiteralDQ(asPart
, prosrc
, NULL
);
7260 if (strcmp(prosrc
, "-") != 0)
7262 appendPQExpBuffer(asPart
, "AS ");
7263 /* with no bin, dollar quote src unconditionally if allowed */
7264 if (disable_dollar_quoting
)
7265 appendStringLiteralAH(asPart
, prosrc
, fout
);
7267 appendStringLiteralDQ(asPart
, prosrc
, NULL
);
7271 nallargs
= finfo
->nargs
; /* unless we learn different from allargs */
7273 if (proallargtypes
&& *proallargtypes
)
7277 if (!parsePGArray(proallargtypes
, &allargtypes
, &nitems
) ||
7278 nitems
< finfo
->nargs
)
7280 write_msg(NULL
, "WARNING: could not parse proallargtypes array\n");
7289 if (proargmodes
&& *proargmodes
)
7293 if (!parsePGArray(proargmodes
, &argmodes
, &nitems
) ||
7296 write_msg(NULL
, "WARNING: could not parse proargmodes array\n");
7303 if (proargnames
&& *proargnames
)
7307 if (!parsePGArray(proargnames
, &argnames
, &nitems
) ||
7310 write_msg(NULL
, "WARNING: could not parse proargnames array\n");
7317 if (proconfig
&& *proconfig
)
7319 if (!parsePGArray(proconfig
, &configitems
, &nconfigitems
))
7321 write_msg(NULL
, "WARNING: could not parse proconfig array\n");
7331 /* 8.4 or later; we rely on server-side code for most of the work */
7332 funcfullsig
= format_function_arguments(finfo
, funcargs
);
7333 funcsig
= format_function_arguments(finfo
, funciargs
);
7337 /* pre-8.4, do it ourselves */
7338 funcsig
= format_function_arguments_old(finfo
, nallargs
, allargtypes
,
7339 argmodes
, argnames
);
7340 funcfullsig
= funcsig
;
7343 funcsig_tag
= format_function_signature(finfo
, false);
7346 * DROP must be fully qualified in case same name appears in pg_catalog
7348 appendPQExpBuffer(delqry
, "DROP FUNCTION %s.%s;\n",
7349 fmtId(finfo
->dobj
.namespace->dobj
.name
),
7352 appendPQExpBuffer(q
, "CREATE FUNCTION %s ", funcfullsig
);
7354 appendPQExpBuffer(q
, "RETURNS %s", funcresult
);
7357 rettypename
= getFormattedTypeName(finfo
->prorettype
, zeroAsOpaque
);
7358 appendPQExpBuffer(q
, "RETURNS %s%s",
7359 (proretset
[0] == 't') ? "SETOF " : "",
7364 appendPQExpBuffer(q
, "\n LANGUAGE %s", fmtId(lanname
));
7366 if (proiswindow
[0] == 't')
7367 appendPQExpBuffer(q
, " WINDOW");
7369 if (provolatile
[0] != PROVOLATILE_VOLATILE
)
7371 if (provolatile
[0] == PROVOLATILE_IMMUTABLE
)
7372 appendPQExpBuffer(q
, " IMMUTABLE");
7373 else if (provolatile
[0] == PROVOLATILE_STABLE
)
7374 appendPQExpBuffer(q
, " STABLE");
7375 else if (provolatile
[0] != PROVOLATILE_VOLATILE
)
7377 write_msg(NULL
, "unrecognized provolatile value for function \"%s\"\n",
7383 if (proisstrict
[0] == 't')
7384 appendPQExpBuffer(q
, " STRICT");
7386 if (prosecdef
[0] == 't')
7387 appendPQExpBuffer(q
, " SECURITY DEFINER");
7390 * COST and ROWS are emitted only if present and not default, so as not to
7391 * break backwards-compatibility of the dump without need. Keep this code
7392 * in sync with the defaults in functioncmds.c.
7394 if (strcmp(procost
, "0") != 0)
7396 if (strcmp(lanname
, "internal") == 0 || strcmp(lanname
, "c") == 0)
7398 /* default cost is 1 */
7399 if (strcmp(procost
, "1") != 0)
7400 appendPQExpBuffer(q
, " COST %s", procost
);
7404 /* default cost is 100 */
7405 if (strcmp(procost
, "100") != 0)
7406 appendPQExpBuffer(q
, " COST %s", procost
);
7409 if (proretset
[0] == 't' &&
7410 strcmp(prorows
, "0") != 0 && strcmp(prorows
, "1000") != 0)
7411 appendPQExpBuffer(q
, " ROWS %s", prorows
);
7413 for (i
= 0; i
< nconfigitems
; i
++)
7415 /* we feel free to scribble on configitems[] here */
7416 char *configitem
= configitems
[i
];
7419 pos
= strchr(configitem
, '=');
7423 appendPQExpBuffer(q
, "\n SET %s TO ", fmtId(configitem
));
7426 * Some GUC variable names are 'LIST' type and hence must not be
7429 if (pg_strcasecmp(configitem
, "DateStyle") == 0
7430 || pg_strcasecmp(configitem
, "search_path") == 0)
7431 appendPQExpBuffer(q
, "%s", pos
);
7433 appendStringLiteralAH(q
, pos
, fout
);
7436 appendPQExpBuffer(q
, "\n %s;\n", asPart
->data
);
7438 ArchiveEntry(fout
, finfo
->dobj
.catId
, finfo
->dobj
.dumpId
,
7440 finfo
->dobj
.namespace->dobj
.name
,
7442 finfo
->rolname
, false,
7443 "FUNCTION", SECTION_PRE_DATA
,
7444 q
->data
, delqry
->data
, NULL
,
7445 finfo
->dobj
.dependencies
, finfo
->dobj
.nDeps
,
7448 /* Dump Function Comments */
7449 resetPQExpBuffer(q
);
7450 appendPQExpBuffer(q
, "FUNCTION %s", funcsig
);
7451 dumpComment(fout
, q
->data
,
7452 finfo
->dobj
.namespace->dobj
.name
, finfo
->rolname
,
7453 finfo
->dobj
.catId
, 0, finfo
->dobj
.dumpId
);
7455 dumpACL(fout
, finfo
->dobj
.catId
, finfo
->dobj
.dumpId
, "FUNCTION",
7456 funcsig
, NULL
, funcsig_tag
,
7457 finfo
->dobj
.namespace->dobj
.name
,
7458 finfo
->rolname
, finfo
->proacl
);
7462 destroyPQExpBuffer(query
);
7463 destroyPQExpBuffer(q
);
7464 destroyPQExpBuffer(delqry
);
7465 destroyPQExpBuffer(asPart
);
7480 * Dump a user-defined cast
7483 dumpCast(Archive
*fout
, CastInfo
*cast
)
7487 PQExpBuffer castsig
;
7488 FuncInfo
*funcInfo
= NULL
;
7489 TypeInfo
*sourceInfo
;
7490 TypeInfo
*targetInfo
;
7495 if (OidIsValid(cast
->castfunc
))
7497 funcInfo
= findFuncByOid(cast
->castfunc
);
7498 if (funcInfo
== NULL
)
7503 * As per discussion we dump casts if one or more of the underlying
7504 * objects (the conversion function and the two data types) are not
7505 * builtin AND if all of the non-builtin objects are included in the dump.
7506 * Builtin meaning, the namespace name does not start with "pg_".
7508 sourceInfo
= findTypeByOid(cast
->castsource
);
7509 targetInfo
= findTypeByOid(cast
->casttarget
);
7511 if (sourceInfo
== NULL
|| targetInfo
== NULL
)
7515 * Skip this cast if all objects are from pg_
7517 if ((funcInfo
== NULL
||
7518 strncmp(funcInfo
->dobj
.namespace->dobj
.name
, "pg_", 3) == 0) &&
7519 strncmp(sourceInfo
->dobj
.namespace->dobj
.name
, "pg_", 3) == 0 &&
7520 strncmp(targetInfo
->dobj
.namespace->dobj
.name
, "pg_", 3) == 0)
7524 * Skip cast if function isn't from pg_ and is not to be dumped.
7527 strncmp(funcInfo
->dobj
.namespace->dobj
.name
, "pg_", 3) != 0 &&
7528 !funcInfo
->dobj
.dump
)
7532 * Same for the source type
7534 if (strncmp(sourceInfo
->dobj
.namespace->dobj
.name
, "pg_", 3) != 0 &&
7535 !sourceInfo
->dobj
.dump
)
7539 * and the target type.
7541 if (strncmp(targetInfo
->dobj
.namespace->dobj
.name
, "pg_", 3) != 0 &&
7542 !targetInfo
->dobj
.dump
)
7545 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7546 selectSourceSchema("pg_catalog");
7548 defqry
= createPQExpBuffer();
7549 delqry
= createPQExpBuffer();
7550 castsig
= createPQExpBuffer();
7552 appendPQExpBuffer(delqry
, "DROP CAST (%s AS %s);\n",
7553 getFormattedTypeName(cast
->castsource
, zeroAsNone
),
7554 getFormattedTypeName(cast
->casttarget
, zeroAsNone
));
7556 appendPQExpBuffer(defqry
, "CREATE CAST (%s AS %s) ",
7557 getFormattedTypeName(cast
->castsource
, zeroAsNone
),
7558 getFormattedTypeName(cast
->casttarget
, zeroAsNone
));
7560 switch (cast
->castmethod
)
7562 case COERCION_METHOD_BINARY
:
7563 appendPQExpBuffer(defqry
, "WITHOUT FUNCTION");
7565 case COERCION_METHOD_INOUT
:
7566 appendPQExpBuffer(defqry
, "WITH INOUT");
7568 case COERCION_METHOD_FUNCTION
:
7571 * Always qualify the function name, in case it is not in
7572 * pg_catalog schema (format_function_signature won't qualify it).
7574 appendPQExpBuffer(defqry
, "WITH FUNCTION %s.",
7575 fmtId(funcInfo
->dobj
.namespace->dobj
.name
));
7576 appendPQExpBuffer(defqry
, "%s",
7577 format_function_signature(funcInfo
, true));
7580 write_msg(NULL
, "WARNING: bogus value in pg_cast.castmethod field\n");
7583 if (cast
->castcontext
== 'a')
7584 appendPQExpBuffer(defqry
, " AS ASSIGNMENT");
7585 else if (cast
->castcontext
== 'i')
7586 appendPQExpBuffer(defqry
, " AS IMPLICIT");
7587 appendPQExpBuffer(defqry
, ";\n");
7589 appendPQExpBuffer(castsig
, "CAST (%s AS %s)",
7590 getFormattedTypeName(cast
->castsource
, zeroAsNone
),
7591 getFormattedTypeName(cast
->casttarget
, zeroAsNone
));
7593 ArchiveEntry(fout
, cast
->dobj
.catId
, cast
->dobj
.dumpId
,
7595 "pg_catalog", NULL
, "",
7596 false, "CAST", SECTION_PRE_DATA
,
7597 defqry
->data
, delqry
->data
, NULL
,
7598 cast
->dobj
.dependencies
, cast
->dobj
.nDeps
,
7601 /* Dump Cast Comments */
7602 resetPQExpBuffer(defqry
);
7603 appendPQExpBuffer(defqry
, "CAST (%s AS %s)",
7604 getFormattedTypeName(cast
->castsource
, zeroAsNone
),
7605 getFormattedTypeName(cast
->casttarget
, zeroAsNone
));
7606 dumpComment(fout
, defqry
->data
,
7608 cast
->dobj
.catId
, 0, cast
->dobj
.dumpId
);
7610 destroyPQExpBuffer(defqry
);
7611 destroyPQExpBuffer(delqry
);
7612 destroyPQExpBuffer(castsig
);
7617 * write out a single operator definition
7620 dumpOpr(Archive
*fout
, OprInfo
*oprinfo
)
7626 PQExpBuffer details
;
7651 /* Skip if not to be dumped */
7652 if (!oprinfo
->dobj
.dump
|| dataOnly
)
7656 * some operators are invalid because they were the result of user
7657 * defining operators before commutators exist
7659 if (!OidIsValid(oprinfo
->oprcode
))
7662 query
= createPQExpBuffer();
7663 q
= createPQExpBuffer();
7664 delq
= createPQExpBuffer();
7665 oprid
= createPQExpBuffer();
7666 details
= createPQExpBuffer();
7668 /* Make sure we are in proper schema so regoperator works correctly */
7669 selectSourceSchema(oprinfo
->dobj
.namespace->dobj
.name
);
7671 if (g_fout
->remoteVersion
>= 80300)
7673 appendPQExpBuffer(query
, "SELECT oprkind, "
7674 "oprcode::pg_catalog.regprocedure, "
7675 "oprleft::pg_catalog.regtype, "
7676 "oprright::pg_catalog.regtype, "
7677 "oprcom::pg_catalog.regoperator, "
7678 "oprnegate::pg_catalog.regoperator, "
7679 "oprrest::pg_catalog.regprocedure, "
7680 "oprjoin::pg_catalog.regprocedure, "
7681 "oprcanmerge, oprcanhash "
7682 "FROM pg_catalog.pg_operator "
7683 "WHERE oid = '%u'::pg_catalog.oid",
7684 oprinfo
->dobj
.catId
.oid
);
7686 else if (g_fout
->remoteVersion
>= 70300)
7688 appendPQExpBuffer(query
, "SELECT oprkind, "
7689 "oprcode::pg_catalog.regprocedure, "
7690 "oprleft::pg_catalog.regtype, "
7691 "oprright::pg_catalog.regtype, "
7692 "oprcom::pg_catalog.regoperator, "
7693 "oprnegate::pg_catalog.regoperator, "
7694 "oprrest::pg_catalog.regprocedure, "
7695 "oprjoin::pg_catalog.regprocedure, "
7696 "(oprlsortop != 0) AS oprcanmerge, "
7698 "FROM pg_catalog.pg_operator "
7699 "WHERE oid = '%u'::pg_catalog.oid",
7700 oprinfo
->dobj
.catId
.oid
);
7702 else if (g_fout
->remoteVersion
>= 70100)
7704 appendPQExpBuffer(query
, "SELECT oprkind, oprcode, "
7705 "CASE WHEN oprleft = 0 THEN '-' "
7706 "ELSE format_type(oprleft, NULL) END AS oprleft, "
7707 "CASE WHEN oprright = 0 THEN '-' "
7708 "ELSE format_type(oprright, NULL) END AS oprright, "
7709 "oprcom, oprnegate, oprrest, oprjoin, "
7710 "(oprlsortop != 0) AS oprcanmerge, "
7713 "WHERE oid = '%u'::oid",
7714 oprinfo
->dobj
.catId
.oid
);
7718 appendPQExpBuffer(query
, "SELECT oprkind, oprcode, "
7719 "CASE WHEN oprleft = 0 THEN '-'::name "
7720 "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
7721 "CASE WHEN oprright = 0 THEN '-'::name "
7722 "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
7723 "oprcom, oprnegate, oprrest, oprjoin, "
7724 "(oprlsortop != 0) AS oprcanmerge, "
7727 "WHERE oid = '%u'::oid",
7728 oprinfo
->dobj
.catId
.oid
);
7731 res
= PQexec(g_conn
, query
->data
);
7732 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
7734 /* Expecting a single result only */
7735 ntups
= PQntuples(res
);
7738 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
7739 "query returned %d rows instead of one: %s\n",
7741 ntups
, query
->data
);
7745 i_oprkind
= PQfnumber(res
, "oprkind");
7746 i_oprcode
= PQfnumber(res
, "oprcode");
7747 i_oprleft
= PQfnumber(res
, "oprleft");
7748 i_oprright
= PQfnumber(res
, "oprright");
7749 i_oprcom
= PQfnumber(res
, "oprcom");
7750 i_oprnegate
= PQfnumber(res
, "oprnegate");
7751 i_oprrest
= PQfnumber(res
, "oprrest");
7752 i_oprjoin
= PQfnumber(res
, "oprjoin");
7753 i_oprcanmerge
= PQfnumber(res
, "oprcanmerge");
7754 i_oprcanhash
= PQfnumber(res
, "oprcanhash");
7756 oprkind
= PQgetvalue(res
, 0, i_oprkind
);
7757 oprcode
= PQgetvalue(res
, 0, i_oprcode
);
7758 oprleft
= PQgetvalue(res
, 0, i_oprleft
);
7759 oprright
= PQgetvalue(res
, 0, i_oprright
);
7760 oprcom
= PQgetvalue(res
, 0, i_oprcom
);
7761 oprnegate
= PQgetvalue(res
, 0, i_oprnegate
);
7762 oprrest
= PQgetvalue(res
, 0, i_oprrest
);
7763 oprjoin
= PQgetvalue(res
, 0, i_oprjoin
);
7764 oprcanmerge
= PQgetvalue(res
, 0, i_oprcanmerge
);
7765 oprcanhash
= PQgetvalue(res
, 0, i_oprcanhash
);
7767 appendPQExpBuffer(details
, " PROCEDURE = %s",
7768 convertRegProcReference(oprcode
));
7770 appendPQExpBuffer(oprid
, "%s (",
7771 oprinfo
->dobj
.name
);
7774 * right unary means there's a left arg and left unary means there's a
7777 if (strcmp(oprkind
, "r") == 0 ||
7778 strcmp(oprkind
, "b") == 0)
7780 if (g_fout
->remoteVersion
>= 70100)
7783 name
= fmtId(oprleft
);
7784 appendPQExpBuffer(details
, ",\n LEFTARG = %s", name
);
7785 appendPQExpBuffer(oprid
, "%s", name
);
7788 appendPQExpBuffer(oprid
, "NONE");
7790 if (strcmp(oprkind
, "l") == 0 ||
7791 strcmp(oprkind
, "b") == 0)
7793 if (g_fout
->remoteVersion
>= 70100)
7796 name
= fmtId(oprright
);
7797 appendPQExpBuffer(details
, ",\n RIGHTARG = %s", name
);
7798 appendPQExpBuffer(oprid
, ", %s)", name
);
7801 appendPQExpBuffer(oprid
, ", NONE)");
7803 name
= convertOperatorReference(oprcom
);
7805 appendPQExpBuffer(details
, ",\n COMMUTATOR = %s", name
);
7807 name
= convertOperatorReference(oprnegate
);
7809 appendPQExpBuffer(details
, ",\n NEGATOR = %s", name
);
7811 if (strcmp(oprcanmerge
, "t") == 0)
7812 appendPQExpBuffer(details
, ",\n MERGES");
7814 if (strcmp(oprcanhash
, "t") == 0)
7815 appendPQExpBuffer(details
, ",\n HASHES");
7817 name
= convertRegProcReference(oprrest
);
7819 appendPQExpBuffer(details
, ",\n RESTRICT = %s", name
);
7821 name
= convertRegProcReference(oprjoin
);
7823 appendPQExpBuffer(details
, ",\n JOIN = %s", name
);
7826 * DROP must be fully qualified in case same name appears in pg_catalog
7828 appendPQExpBuffer(delq
, "DROP OPERATOR %s.%s;\n",
7829 fmtId(oprinfo
->dobj
.namespace->dobj
.name
),
7832 appendPQExpBuffer(q
, "CREATE OPERATOR %s (\n%s\n);\n",
7833 oprinfo
->dobj
.name
, details
->data
);
7835 ArchiveEntry(fout
, oprinfo
->dobj
.catId
, oprinfo
->dobj
.dumpId
,
7837 oprinfo
->dobj
.namespace->dobj
.name
,
7840 false, "OPERATOR", SECTION_PRE_DATA
,
7841 q
->data
, delq
->data
, NULL
,
7842 oprinfo
->dobj
.dependencies
, oprinfo
->dobj
.nDeps
,
7845 /* Dump Operator Comments */
7846 resetPQExpBuffer(q
);
7847 appendPQExpBuffer(q
, "OPERATOR %s", oprid
->data
);
7848 dumpComment(fout
, q
->data
,
7849 oprinfo
->dobj
.namespace->dobj
.name
, oprinfo
->rolname
,
7850 oprinfo
->dobj
.catId
, 0, oprinfo
->dobj
.dumpId
);
7854 destroyPQExpBuffer(query
);
7855 destroyPQExpBuffer(q
);
7856 destroyPQExpBuffer(delq
);
7857 destroyPQExpBuffer(oprid
);
7858 destroyPQExpBuffer(details
);
7862 * Convert a function reference obtained from pg_operator
7864 * Returns what to print, or NULL if function references is InvalidOid
7866 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
7867 * argument-types part. In prior versions, the input is a REGPROC display.
7870 convertRegProcReference(const char *proc
)
7872 /* In all cases "-" means a null reference */
7873 if (strcmp(proc
, "-") == 0)
7876 if (g_fout
->remoteVersion
>= 70300)
7882 name
= strdup(proc
);
7883 /* find non-double-quoted left paren */
7885 for (paren
= name
; *paren
; paren
++)
7887 if (*paren
== '(' && !inquote
)
7898 /* REGPROC before 7.3 does not quote its result */
7903 * Convert an operator cross-reference obtained from pg_operator
7905 * Returns what to print, or NULL to print nothing
7907 * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
7908 * argument-types part, and add OPERATOR() decoration if the name is
7909 * schema-qualified. In older versions, the input is just a numeric OID,
7910 * which we search our operator list for.
7913 convertOperatorReference(const char *opr
)
7917 /* In all cases "0" means a null reference */
7918 if (strcmp(opr
, "0") == 0)
7921 if (g_fout
->remoteVersion
>= 70300)
7930 /* find non-double-quoted left paren, and check for non-quoted dot */
7933 for (ptr
= name
; *ptr
; ptr
++)
7937 else if (*ptr
== '.' && !inquote
)
7939 else if (*ptr
== '(' && !inquote
)
7945 /* If not schema-qualified, don't need to add OPERATOR() */
7948 oname
= malloc(strlen(name
) + 11);
7949 sprintf(oname
, "OPERATOR(%s)", name
);
7954 oprInfo
= findOprByOid(atooid(opr
));
7955 if (oprInfo
== NULL
)
7957 write_msg(NULL
, "WARNING: could not find operator with OID %s\n",
7961 return oprInfo
->dobj
.name
;
7965 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
7967 * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
7968 * argument lists of these functions are predetermined. Note that the
7969 * caller should ensure we are in the proper schema, because the results
7970 * are search path dependent!
7973 convertTSFunction(Oid funcOid
)
7980 snprintf(query
, sizeof(query
),
7981 "SELECT '%u'::pg_catalog.regproc", funcOid
);
7982 res
= PQexec(g_conn
, query
);
7983 check_sql_result(res
, g_conn
, query
, PGRES_TUPLES_OK
);
7985 ntups
= PQntuples(res
);
7988 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
7989 "query returned %d rows instead of one: %s\n",
7995 result
= strdup(PQgetvalue(res
, 0, 0));
8005 * write out a single operator class definition
8008 dumpOpclass(Archive
*fout
, OpclassInfo
*opcinfo
)
8040 /* Skip if not to be dumped */
8041 if (!opcinfo
->dobj
.dump
|| dataOnly
)
8045 * XXX currently we do not implement dumping of operator classes from
8046 * pre-7.3 databases. This could be done but it seems not worth the
8049 if (g_fout
->remoteVersion
< 70300)
8052 query
= createPQExpBuffer();
8053 q
= createPQExpBuffer();
8054 delq
= createPQExpBuffer();
8056 /* Make sure we are in proper schema so regoperator works correctly */
8057 selectSourceSchema(opcinfo
->dobj
.namespace->dobj
.name
);
8059 /* Get additional fields from the pg_opclass row */
8060 if (g_fout
->remoteVersion
>= 80300)
8062 appendPQExpBuffer(query
, "SELECT opcintype::pg_catalog.regtype, "
8063 "opckeytype::pg_catalog.regtype, "
8065 "opfname AS opcfamily, "
8066 "nspname AS opcfamilynsp, "
8067 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
8068 "FROM pg_catalog.pg_opclass c "
8069 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
8070 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
8071 "WHERE c.oid = '%u'::pg_catalog.oid",
8072 opcinfo
->dobj
.catId
.oid
);
8076 appendPQExpBuffer(query
, "SELECT opcintype::pg_catalog.regtype, "
8077 "opckeytype::pg_catalog.regtype, "
8079 "NULL AS opcfamily, "
8080 "NULL AS opcfamilynsp, "
8081 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
8082 "FROM pg_catalog.pg_opclass "
8083 "WHERE oid = '%u'::pg_catalog.oid",
8084 opcinfo
->dobj
.catId
.oid
);
8087 res
= PQexec(g_conn
, query
->data
);
8088 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8090 /* Expecting a single result only */
8091 ntups
= PQntuples(res
);
8094 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
8095 "query returned %d rows instead of one: %s\n",
8097 ntups
, query
->data
);
8101 i_opcintype
= PQfnumber(res
, "opcintype");
8102 i_opckeytype
= PQfnumber(res
, "opckeytype");
8103 i_opcdefault
= PQfnumber(res
, "opcdefault");
8104 i_opcfamily
= PQfnumber(res
, "opcfamily");
8105 i_opcfamilynsp
= PQfnumber(res
, "opcfamilynsp");
8106 i_amname
= PQfnumber(res
, "amname");
8108 opcintype
= PQgetvalue(res
, 0, i_opcintype
);
8109 opckeytype
= PQgetvalue(res
, 0, i_opckeytype
);
8110 opcdefault
= PQgetvalue(res
, 0, i_opcdefault
);
8111 opcfamily
= PQgetvalue(res
, 0, i_opcfamily
);
8112 opcfamilynsp
= PQgetvalue(res
, 0, i_opcfamilynsp
);
8113 /* amname will still be needed after we PQclear res */
8114 amname
= strdup(PQgetvalue(res
, 0, i_amname
));
8117 * DROP must be fully qualified in case same name appears in pg_catalog
8119 appendPQExpBuffer(delq
, "DROP OPERATOR CLASS %s",
8120 fmtId(opcinfo
->dobj
.namespace->dobj
.name
));
8121 appendPQExpBuffer(delq
, ".%s",
8122 fmtId(opcinfo
->dobj
.name
));
8123 appendPQExpBuffer(delq
, " USING %s;\n",
8126 /* Build the fixed portion of the CREATE command */
8127 appendPQExpBuffer(q
, "CREATE OPERATOR CLASS %s\n ",
8128 fmtId(opcinfo
->dobj
.name
));
8129 if (strcmp(opcdefault
, "t") == 0)
8130 appendPQExpBuffer(q
, "DEFAULT ");
8131 appendPQExpBuffer(q
, "FOR TYPE %s USING %s",
8134 if (strlen(opcfamily
) > 0 &&
8135 (strcmp(opcfamily
, opcinfo
->dobj
.name
) != 0 ||
8136 strcmp(opcfamilynsp
, opcinfo
->dobj
.namespace->dobj
.name
) != 0))
8138 appendPQExpBuffer(q
, " FAMILY ");
8139 if (strcmp(opcfamilynsp
, opcinfo
->dobj
.namespace->dobj
.name
) != 0)
8140 appendPQExpBuffer(q
, "%s.", fmtId(opcfamilynsp
));
8141 appendPQExpBuffer(q
, "%s", fmtId(opcfamily
));
8143 appendPQExpBuffer(q
, " AS\n ");
8147 if (strcmp(opckeytype
, "-") != 0)
8149 appendPQExpBuffer(q
, "STORAGE %s",
8157 * Now fetch and print the OPERATOR entries (pg_amop rows).
8159 resetPQExpBuffer(query
);
8161 if (g_fout
->remoteVersion
>= 80400)
8164 * Print only those opfamily members that are tied to the opclass by
8165 * pg_depend entries.
8167 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8168 * an older server's opclass in which it is used. This is to avoid
8169 * hard-to-detect breakage if a newer pg_dump is used to dump from an
8170 * older server and then reload into that old version. This can go
8171 * away once 8.3 is so old as to not be of interest to anyone.
8173 appendPQExpBuffer(query
, "SELECT amopstrategy, false AS amopreqcheck, "
8174 "amopopr::pg_catalog.regoperator "
8175 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8176 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8177 "AND refobjid = '%u'::pg_catalog.oid "
8178 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8179 "AND objid = ao.oid "
8180 "ORDER BY amopstrategy",
8181 opcinfo
->dobj
.catId
.oid
);
8183 else if (g_fout
->remoteVersion
>= 80300)
8186 * Print only those opfamily members that are tied to the opclass by
8187 * pg_depend entries.
8189 appendPQExpBuffer(query
, "SELECT amopstrategy, amopreqcheck, "
8190 "amopopr::pg_catalog.regoperator "
8191 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8192 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8193 "AND refobjid = '%u'::pg_catalog.oid "
8194 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8195 "AND objid = ao.oid "
8196 "ORDER BY amopstrategy",
8197 opcinfo
->dobj
.catId
.oid
);
8201 appendPQExpBuffer(query
, "SELECT amopstrategy, amopreqcheck, "
8202 "amopopr::pg_catalog.regoperator "
8203 "FROM pg_catalog.pg_amop "
8204 "WHERE amopclaid = '%u'::pg_catalog.oid "
8205 "ORDER BY amopstrategy",
8206 opcinfo
->dobj
.catId
.oid
);
8209 res
= PQexec(g_conn
, query
->data
);
8210 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8212 ntups
= PQntuples(res
);
8214 i_amopstrategy
= PQfnumber(res
, "amopstrategy");
8215 i_amopreqcheck
= PQfnumber(res
, "amopreqcheck");
8216 i_amopopr
= PQfnumber(res
, "amopopr");
8218 for (i
= 0; i
< ntups
; i
++)
8220 amopstrategy
= PQgetvalue(res
, i
, i_amopstrategy
);
8221 amopreqcheck
= PQgetvalue(res
, i
, i_amopreqcheck
);
8222 amopopr
= PQgetvalue(res
, i
, i_amopopr
);
8225 appendPQExpBuffer(q
, " ,\n ");
8227 appendPQExpBuffer(q
, "OPERATOR %s %s",
8228 amopstrategy
, amopopr
);
8229 if (strcmp(amopreqcheck
, "t") == 0)
8230 appendPQExpBuffer(q
, " RECHECK");
8238 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8240 resetPQExpBuffer(query
);
8242 if (g_fout
->remoteVersion
>= 80300)
8245 * Print only those opfamily members that are tied to the opclass by
8246 * pg_depend entries.
8248 appendPQExpBuffer(query
, "SELECT amprocnum, "
8249 "amproc::pg_catalog.regprocedure "
8250 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8251 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8252 "AND refobjid = '%u'::pg_catalog.oid "
8253 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8254 "AND objid = ap.oid "
8255 "ORDER BY amprocnum",
8256 opcinfo
->dobj
.catId
.oid
);
8260 appendPQExpBuffer(query
, "SELECT amprocnum, "
8261 "amproc::pg_catalog.regprocedure "
8262 "FROM pg_catalog.pg_amproc "
8263 "WHERE amopclaid = '%u'::pg_catalog.oid "
8264 "ORDER BY amprocnum",
8265 opcinfo
->dobj
.catId
.oid
);
8268 res
= PQexec(g_conn
, query
->data
);
8269 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8271 ntups
= PQntuples(res
);
8273 i_amprocnum
= PQfnumber(res
, "amprocnum");
8274 i_amproc
= PQfnumber(res
, "amproc");
8276 for (i
= 0; i
< ntups
; i
++)
8278 amprocnum
= PQgetvalue(res
, i
, i_amprocnum
);
8279 amproc
= PQgetvalue(res
, i
, i_amproc
);
8282 appendPQExpBuffer(q
, " ,\n ");
8284 appendPQExpBuffer(q
, "FUNCTION %s %s",
8292 appendPQExpBuffer(q
, ";\n");
8294 ArchiveEntry(fout
, opcinfo
->dobj
.catId
, opcinfo
->dobj
.dumpId
,
8296 opcinfo
->dobj
.namespace->dobj
.name
,
8299 false, "OPERATOR CLASS", SECTION_PRE_DATA
,
8300 q
->data
, delq
->data
, NULL
,
8301 opcinfo
->dobj
.dependencies
, opcinfo
->dobj
.nDeps
,
8304 /* Dump Operator Class Comments */
8305 resetPQExpBuffer(q
);
8306 appendPQExpBuffer(q
, "OPERATOR CLASS %s",
8307 fmtId(opcinfo
->dobj
.name
));
8308 appendPQExpBuffer(q
, " USING %s",
8310 dumpComment(fout
, q
->data
,
8311 NULL
, opcinfo
->rolname
,
8312 opcinfo
->dobj
.catId
, 0, opcinfo
->dobj
.dumpId
);
8315 destroyPQExpBuffer(query
);
8316 destroyPQExpBuffer(q
);
8317 destroyPQExpBuffer(delq
);
8322 * write out a single operator family definition
8325 dumpOpfamily(Archive
*fout
, OpfamilyInfo
*opfinfo
)
8332 PGresult
*res_procs
;
8340 int i_amproclefttype
;
8341 int i_amprocrighttype
;
8348 char *amproclefttype
;
8349 char *amprocrighttype
;
8353 /* Skip if not to be dumped */
8354 if (!opfinfo
->dobj
.dump
|| dataOnly
)
8358 * We want to dump the opfamily only if (1) it contains "loose" operators
8359 * or functions, or (2) it contains an opclass with a different name or
8360 * owner. Otherwise it's sufficient to let it be created during creation
8361 * of the contained opclass, and not dumping it improves portability of
8362 * the dump. Since we have to fetch the loose operators/funcs anyway, do
8366 query
= createPQExpBuffer();
8367 q
= createPQExpBuffer();
8368 delq
= createPQExpBuffer();
8370 /* Make sure we are in proper schema so regoperator works correctly */
8371 selectSourceSchema(opfinfo
->dobj
.namespace->dobj
.name
);
8374 * Fetch only those opfamily members that are tied directly to the
8375 * opfamily by pg_depend entries.
8377 if (g_fout
->remoteVersion
>= 80400)
8380 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8381 * an older server's opclass in which it is used. This is to avoid
8382 * hard-to-detect breakage if a newer pg_dump is used to dump from an
8383 * older server and then reload into that old version. This can go
8384 * away once 8.3 is so old as to not be of interest to anyone.
8386 appendPQExpBuffer(query
, "SELECT amopstrategy, false AS amopreqcheck, "
8387 "amopopr::pg_catalog.regoperator "
8388 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8389 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8390 "AND refobjid = '%u'::pg_catalog.oid "
8391 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8392 "AND objid = ao.oid "
8393 "ORDER BY amopstrategy",
8394 opfinfo
->dobj
.catId
.oid
);
8398 appendPQExpBuffer(query
, "SELECT amopstrategy, amopreqcheck, "
8399 "amopopr::pg_catalog.regoperator "
8400 "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8401 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8402 "AND refobjid = '%u'::pg_catalog.oid "
8403 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8404 "AND objid = ao.oid "
8405 "ORDER BY amopstrategy",
8406 opfinfo
->dobj
.catId
.oid
);
8409 res_ops
= PQexec(g_conn
, query
->data
);
8410 check_sql_result(res_ops
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8412 resetPQExpBuffer(query
);
8414 appendPQExpBuffer(query
, "SELECT amprocnum, "
8415 "amproc::pg_catalog.regprocedure, "
8416 "amproclefttype::pg_catalog.regtype, "
8417 "amprocrighttype::pg_catalog.regtype "
8418 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8419 "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8420 "AND refobjid = '%u'::pg_catalog.oid "
8421 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8422 "AND objid = ap.oid "
8423 "ORDER BY amprocnum",
8424 opfinfo
->dobj
.catId
.oid
);
8426 res_procs
= PQexec(g_conn
, query
->data
);
8427 check_sql_result(res_procs
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8429 if (PQntuples(res_ops
) == 0 && PQntuples(res_procs
) == 0)
8431 /* No loose members, so check contained opclasses */
8432 resetPQExpBuffer(query
);
8434 appendPQExpBuffer(query
, "SELECT 1 "
8435 "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8436 "WHERE f.oid = '%u'::pg_catalog.oid "
8437 "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8438 "AND refobjid = f.oid "
8439 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8440 "AND objid = c.oid "
8441 "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8443 opfinfo
->dobj
.catId
.oid
);
8445 res
= PQexec(g_conn
, query
->data
);
8446 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8448 if (PQntuples(res
) == 0)
8450 /* no need to dump it, so bail out */
8454 destroyPQExpBuffer(query
);
8455 destroyPQExpBuffer(q
);
8456 destroyPQExpBuffer(delq
);
8463 /* Get additional fields from the pg_opfamily row */
8464 resetPQExpBuffer(query
);
8466 appendPQExpBuffer(query
, "SELECT "
8467 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8468 "FROM pg_catalog.pg_opfamily "
8469 "WHERE oid = '%u'::pg_catalog.oid",
8470 opfinfo
->dobj
.catId
.oid
);
8472 res
= PQexec(g_conn
, query
->data
);
8473 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8475 /* Expecting a single result only */
8476 ntups
= PQntuples(res
);
8479 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
8480 "query returned %d rows instead of one: %s\n",
8482 ntups
, query
->data
);
8486 i_amname
= PQfnumber(res
, "amname");
8488 /* amname will still be needed after we PQclear res */
8489 amname
= strdup(PQgetvalue(res
, 0, i_amname
));
8492 * DROP must be fully qualified in case same name appears in pg_catalog
8494 appendPQExpBuffer(delq
, "DROP OPERATOR FAMILY %s",
8495 fmtId(opfinfo
->dobj
.namespace->dobj
.name
));
8496 appendPQExpBuffer(delq
, ".%s",
8497 fmtId(opfinfo
->dobj
.name
));
8498 appendPQExpBuffer(delq
, " USING %s;\n",
8501 /* Build the fixed portion of the CREATE command */
8502 appendPQExpBuffer(q
, "CREATE OPERATOR FAMILY %s",
8503 fmtId(opfinfo
->dobj
.name
));
8504 appendPQExpBuffer(q
, " USING %s;\n",
8509 /* Do we need an ALTER to add loose members? */
8510 if (PQntuples(res_ops
) > 0 || PQntuples(res_procs
) > 0)
8512 appendPQExpBuffer(q
, "ALTER OPERATOR FAMILY %s",
8513 fmtId(opfinfo
->dobj
.name
));
8514 appendPQExpBuffer(q
, " USING %s ADD\n ",
8520 * Now fetch and print the OPERATOR entries (pg_amop rows).
8522 ntups
= PQntuples(res_ops
);
8524 i_amopstrategy
= PQfnumber(res_ops
, "amopstrategy");
8525 i_amopreqcheck
= PQfnumber(res_ops
, "amopreqcheck");
8526 i_amopopr
= PQfnumber(res_ops
, "amopopr");
8528 for (i
= 0; i
< ntups
; i
++)
8530 amopstrategy
= PQgetvalue(res_ops
, i
, i_amopstrategy
);
8531 amopreqcheck
= PQgetvalue(res_ops
, i
, i_amopreqcheck
);
8532 amopopr
= PQgetvalue(res_ops
, i
, i_amopopr
);
8535 appendPQExpBuffer(q
, " ,\n ");
8537 appendPQExpBuffer(q
, "OPERATOR %s %s",
8538 amopstrategy
, amopopr
);
8539 if (strcmp(amopreqcheck
, "t") == 0)
8540 appendPQExpBuffer(q
, " RECHECK");
8546 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8548 ntups
= PQntuples(res_procs
);
8550 i_amprocnum
= PQfnumber(res_procs
, "amprocnum");
8551 i_amproc
= PQfnumber(res_procs
, "amproc");
8552 i_amproclefttype
= PQfnumber(res_procs
, "amproclefttype");
8553 i_amprocrighttype
= PQfnumber(res_procs
, "amprocrighttype");
8555 for (i
= 0; i
< ntups
; i
++)
8557 amprocnum
= PQgetvalue(res_procs
, i
, i_amprocnum
);
8558 amproc
= PQgetvalue(res_procs
, i
, i_amproc
);
8559 amproclefttype
= PQgetvalue(res_procs
, i
, i_amproclefttype
);
8560 amprocrighttype
= PQgetvalue(res_procs
, i
, i_amprocrighttype
);
8563 appendPQExpBuffer(q
, " ,\n ");
8565 appendPQExpBuffer(q
, "FUNCTION %s (%s, %s) %s",
8566 amprocnum
, amproclefttype
, amprocrighttype
,
8572 appendPQExpBuffer(q
, ";\n");
8575 ArchiveEntry(fout
, opfinfo
->dobj
.catId
, opfinfo
->dobj
.dumpId
,
8577 opfinfo
->dobj
.namespace->dobj
.name
,
8580 false, "OPERATOR FAMILY", SECTION_PRE_DATA
,
8581 q
->data
, delq
->data
, NULL
,
8582 opfinfo
->dobj
.dependencies
, opfinfo
->dobj
.nDeps
,
8585 /* Dump Operator Family Comments */
8586 resetPQExpBuffer(q
);
8587 appendPQExpBuffer(q
, "OPERATOR FAMILY %s",
8588 fmtId(opfinfo
->dobj
.name
));
8589 appendPQExpBuffer(q
, " USING %s",
8591 dumpComment(fout
, q
->data
,
8592 NULL
, opfinfo
->rolname
,
8593 opfinfo
->dobj
.catId
, 0, opfinfo
->dobj
.dumpId
);
8598 destroyPQExpBuffer(query
);
8599 destroyPQExpBuffer(q
);
8600 destroyPQExpBuffer(delq
);
8605 * write out a single conversion definition
8608 dumpConversion(Archive
*fout
, ConvInfo
*convinfo
)
8613 PQExpBuffer details
;
8617 int i_conforencoding
;
8618 int i_contoencoding
;
8621 const char *conname
;
8622 const char *conforencoding
;
8623 const char *contoencoding
;
8624 const char *conproc
;
8627 /* Skip if not to be dumped */
8628 if (!convinfo
->dobj
.dump
|| dataOnly
)
8631 query
= createPQExpBuffer();
8632 q
= createPQExpBuffer();
8633 delq
= createPQExpBuffer();
8634 details
= createPQExpBuffer();
8636 /* Make sure we are in proper schema */
8637 selectSourceSchema(convinfo
->dobj
.namespace->dobj
.name
);
8639 /* Get conversion-specific details */
8640 appendPQExpBuffer(query
, "SELECT conname, "
8641 "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
8642 "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
8643 "conproc, condefault "
8644 "FROM pg_catalog.pg_conversion c "
8645 "WHERE c.oid = '%u'::pg_catalog.oid",
8646 convinfo
->dobj
.catId
.oid
);
8648 res
= PQexec(g_conn
, query
->data
);
8649 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8651 /* Expecting a single result only */
8652 ntups
= PQntuples(res
);
8655 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
8656 "query returned %d rows instead of one: %s\n",
8658 ntups
, query
->data
);
8662 i_conname
= PQfnumber(res
, "conname");
8663 i_conforencoding
= PQfnumber(res
, "conforencoding");
8664 i_contoencoding
= PQfnumber(res
, "contoencoding");
8665 i_conproc
= PQfnumber(res
, "conproc");
8666 i_condefault
= PQfnumber(res
, "condefault");
8668 conname
= PQgetvalue(res
, 0, i_conname
);
8669 conforencoding
= PQgetvalue(res
, 0, i_conforencoding
);
8670 contoencoding
= PQgetvalue(res
, 0, i_contoencoding
);
8671 conproc
= PQgetvalue(res
, 0, i_conproc
);
8672 condefault
= (PQgetvalue(res
, 0, i_condefault
)[0] == 't');
8675 * DROP must be fully qualified in case same name appears in pg_catalog
8677 appendPQExpBuffer(delq
, "DROP CONVERSION %s",
8678 fmtId(convinfo
->dobj
.namespace->dobj
.name
));
8679 appendPQExpBuffer(delq
, ".%s;\n",
8680 fmtId(convinfo
->dobj
.name
));
8682 appendPQExpBuffer(q
, "CREATE %sCONVERSION %s FOR ",
8683 (condefault
) ? "DEFAULT " : "",
8684 fmtId(convinfo
->dobj
.name
));
8685 appendStringLiteralAH(q
, conforencoding
, fout
);
8686 appendPQExpBuffer(q
, " TO ");
8687 appendStringLiteralAH(q
, contoencoding
, fout
);
8688 /* regproc is automatically quoted in 7.3 and above */
8689 appendPQExpBuffer(q
, " FROM %s;\n", conproc
);
8691 ArchiveEntry(fout
, convinfo
->dobj
.catId
, convinfo
->dobj
.dumpId
,
8692 convinfo
->dobj
.name
,
8693 convinfo
->dobj
.namespace->dobj
.name
,
8696 false, "CONVERSION", SECTION_PRE_DATA
,
8697 q
->data
, delq
->data
, NULL
,
8698 convinfo
->dobj
.dependencies
, convinfo
->dobj
.nDeps
,
8701 /* Dump Conversion Comments */
8702 resetPQExpBuffer(q
);
8703 appendPQExpBuffer(q
, "CONVERSION %s", fmtId(convinfo
->dobj
.name
));
8704 dumpComment(fout
, q
->data
,
8705 convinfo
->dobj
.namespace->dobj
.name
, convinfo
->rolname
,
8706 convinfo
->dobj
.catId
, 0, convinfo
->dobj
.dumpId
);
8710 destroyPQExpBuffer(query
);
8711 destroyPQExpBuffer(q
);
8712 destroyPQExpBuffer(delq
);
8713 destroyPQExpBuffer(details
);
8717 * format_aggregate_signature: generate aggregate name and argument list
8719 * The argument type names are qualified if needed. The aggregate name
8720 * is never qualified.
8723 format_aggregate_signature(AggInfo
*agginfo
, Archive
*fout
, bool honor_quotes
)
8725 PQExpBufferData buf
;
8728 initPQExpBuffer(&buf
);
8730 appendPQExpBuffer(&buf
, "%s",
8731 fmtId(agginfo
->aggfn
.dobj
.name
));
8733 appendPQExpBuffer(&buf
, "%s", agginfo
->aggfn
.dobj
.name
);
8735 if (agginfo
->aggfn
.nargs
== 0)
8736 appendPQExpBuffer(&buf
, "(*)");
8739 appendPQExpBuffer(&buf
, "(");
8740 for (j
= 0; j
< agginfo
->aggfn
.nargs
; j
++)
8744 typname
= getFormattedTypeName(agginfo
->aggfn
.argtypes
[j
], zeroAsOpaque
);
8746 appendPQExpBuffer(&buf
, "%s%s",
8747 (j
> 0) ? ", " : "",
8751 appendPQExpBuffer(&buf
, ")");
8758 * write out a single aggregate definition
8761 dumpAgg(Archive
*fout
, AggInfo
*agginfo
)
8766 PQExpBuffer details
;
8777 const char *aggtransfn
;
8778 const char *aggfinalfn
;
8779 const char *aggsortop
;
8780 const char *aggtranstype
;
8781 const char *agginitval
;
8784 /* Skip if not to be dumped */
8785 if (!agginfo
->aggfn
.dobj
.dump
|| dataOnly
)
8788 query
= createPQExpBuffer();
8789 q
= createPQExpBuffer();
8790 delq
= createPQExpBuffer();
8791 details
= createPQExpBuffer();
8793 /* Make sure we are in proper schema */
8794 selectSourceSchema(agginfo
->aggfn
.dobj
.namespace->dobj
.name
);
8796 /* Get aggregate-specific details */
8797 if (g_fout
->remoteVersion
>= 80100)
8799 appendPQExpBuffer(query
, "SELECT aggtransfn, "
8800 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8801 "aggsortop::pg_catalog.regoperator, "
8803 "'t'::boolean AS convertok "
8804 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8805 "WHERE a.aggfnoid = p.oid "
8806 "AND p.oid = '%u'::pg_catalog.oid",
8807 agginfo
->aggfn
.dobj
.catId
.oid
);
8809 else if (g_fout
->remoteVersion
>= 70300)
8811 appendPQExpBuffer(query
, "SELECT aggtransfn, "
8812 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8815 "'t'::boolean AS convertok "
8816 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8817 "WHERE a.aggfnoid = p.oid "
8818 "AND p.oid = '%u'::pg_catalog.oid",
8819 agginfo
->aggfn
.dobj
.catId
.oid
);
8821 else if (g_fout
->remoteVersion
>= 70100)
8823 appendPQExpBuffer(query
, "SELECT aggtransfn, aggfinalfn, "
8824 "format_type(aggtranstype, NULL) AS aggtranstype, "
8827 "'t'::boolean AS convertok "
8828 "FROM pg_aggregate "
8829 "WHERE oid = '%u'::oid",
8830 agginfo
->aggfn
.dobj
.catId
.oid
);
8834 appendPQExpBuffer(query
, "SELECT aggtransfn1 AS aggtransfn, "
8836 "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
8838 "agginitval1 AS agginitval, "
8839 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
8840 "FROM pg_aggregate "
8841 "WHERE oid = '%u'::oid",
8842 agginfo
->aggfn
.dobj
.catId
.oid
);
8845 res
= PQexec(g_conn
, query
->data
);
8846 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
8848 /* Expecting a single result only */
8849 ntups
= PQntuples(res
);
8852 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
8853 "query returned %d rows instead of one: %s\n",
8855 ntups
, query
->data
);
8859 i_aggtransfn
= PQfnumber(res
, "aggtransfn");
8860 i_aggfinalfn
= PQfnumber(res
, "aggfinalfn");
8861 i_aggsortop
= PQfnumber(res
, "aggsortop");
8862 i_aggtranstype
= PQfnumber(res
, "aggtranstype");
8863 i_agginitval
= PQfnumber(res
, "agginitval");
8864 i_convertok
= PQfnumber(res
, "convertok");
8866 aggtransfn
= PQgetvalue(res
, 0, i_aggtransfn
);
8867 aggfinalfn
= PQgetvalue(res
, 0, i_aggfinalfn
);
8868 aggsortop
= PQgetvalue(res
, 0, i_aggsortop
);
8869 aggtranstype
= PQgetvalue(res
, 0, i_aggtranstype
);
8870 agginitval
= PQgetvalue(res
, 0, i_agginitval
);
8871 convertok
= (PQgetvalue(res
, 0, i_convertok
)[0] == 't');
8873 aggsig
= format_aggregate_signature(agginfo
, fout
, true);
8874 aggsig_tag
= format_aggregate_signature(agginfo
, fout
, false);
8878 write_msg(NULL
, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8883 if (g_fout
->remoteVersion
>= 70300)
8885 /* If using 7.3's regproc or regtype, data is already quoted */
8886 appendPQExpBuffer(details
, " SFUNC = %s,\n STYPE = %s",
8890 else if (g_fout
->remoteVersion
>= 70100)
8892 /* format_type quotes, regproc does not */
8893 appendPQExpBuffer(details
, " SFUNC = %s,\n STYPE = %s",
8899 /* need quotes all around */
8900 appendPQExpBuffer(details
, " SFUNC = %s,\n",
8902 appendPQExpBuffer(details
, " STYPE = %s",
8903 fmtId(aggtranstype
));
8906 if (!PQgetisnull(res
, 0, i_agginitval
))
8908 appendPQExpBuffer(details
, ",\n INITCOND = ");
8909 appendStringLiteralAH(details
, agginitval
, fout
);
8912 if (strcmp(aggfinalfn
, "-") != 0)
8914 appendPQExpBuffer(details
, ",\n FINALFUNC = %s",
8918 aggsortop
= convertOperatorReference(aggsortop
);
8921 appendPQExpBuffer(details
, ",\n SORTOP = %s",
8926 * DROP must be fully qualified in case same name appears in pg_catalog
8928 appendPQExpBuffer(delq
, "DROP AGGREGATE %s.%s;\n",
8929 fmtId(agginfo
->aggfn
.dobj
.namespace->dobj
.name
),
8932 appendPQExpBuffer(q
, "CREATE AGGREGATE %s (\n%s\n);\n",
8933 aggsig
, details
->data
);
8935 ArchiveEntry(fout
, agginfo
->aggfn
.dobj
.catId
, agginfo
->aggfn
.dobj
.dumpId
,
8937 agginfo
->aggfn
.dobj
.namespace->dobj
.name
,
8939 agginfo
->aggfn
.rolname
,
8940 false, "AGGREGATE", SECTION_PRE_DATA
,
8941 q
->data
, delq
->data
, NULL
,
8942 agginfo
->aggfn
.dobj
.dependencies
, agginfo
->aggfn
.dobj
.nDeps
,
8945 /* Dump Aggregate Comments */
8946 resetPQExpBuffer(q
);
8947 appendPQExpBuffer(q
, "AGGREGATE %s", aggsig
);
8948 dumpComment(fout
, q
->data
,
8949 agginfo
->aggfn
.dobj
.namespace->dobj
.name
, agginfo
->aggfn
.rolname
,
8950 agginfo
->aggfn
.dobj
.catId
, 0, agginfo
->aggfn
.dobj
.dumpId
);
8953 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
8954 * command look like a function's GRANT; in particular this affects the
8955 * syntax for zero-argument aggregates.
8960 aggsig
= format_function_signature(&agginfo
->aggfn
, true);
8961 aggsig_tag
= format_function_signature(&agginfo
->aggfn
, false);
8963 dumpACL(fout
, agginfo
->aggfn
.dobj
.catId
, agginfo
->aggfn
.dobj
.dumpId
,
8965 aggsig
, NULL
, aggsig_tag
,
8966 agginfo
->aggfn
.dobj
.namespace->dobj
.name
,
8967 agginfo
->aggfn
.rolname
, agginfo
->aggfn
.proacl
);
8974 destroyPQExpBuffer(query
);
8975 destroyPQExpBuffer(q
);
8976 destroyPQExpBuffer(delq
);
8977 destroyPQExpBuffer(details
);
8982 * write out a single text search parser
8985 dumpTSParser(Archive
*fout
, TSParserInfo
*prsinfo
)
8990 /* Skip if not to be dumped */
8991 if (!prsinfo
->dobj
.dump
|| dataOnly
)
8994 q
= createPQExpBuffer();
8995 delq
= createPQExpBuffer();
8997 /* Make sure we are in proper schema */
8998 selectSourceSchema(prsinfo
->dobj
.namespace->dobj
.name
);
9000 appendPQExpBuffer(q
, "CREATE TEXT SEARCH PARSER %s (\n",
9001 fmtId(prsinfo
->dobj
.name
));
9003 appendPQExpBuffer(q
, " START = %s,\n",
9004 convertTSFunction(prsinfo
->prsstart
));
9005 appendPQExpBuffer(q
, " GETTOKEN = %s,\n",
9006 convertTSFunction(prsinfo
->prstoken
));
9007 appendPQExpBuffer(q
, " END = %s,\n",
9008 convertTSFunction(prsinfo
->prsend
));
9009 if (prsinfo
->prsheadline
!= InvalidOid
)
9010 appendPQExpBuffer(q
, " HEADLINE = %s,\n",
9011 convertTSFunction(prsinfo
->prsheadline
));
9012 appendPQExpBuffer(q
, " LEXTYPES = %s );\n",
9013 convertTSFunction(prsinfo
->prslextype
));
9016 * DROP must be fully qualified in case same name appears in pg_catalog
9018 appendPQExpBuffer(delq
, "DROP TEXT SEARCH PARSER %s",
9019 fmtId(prsinfo
->dobj
.namespace->dobj
.name
));
9020 appendPQExpBuffer(delq
, ".%s;\n",
9021 fmtId(prsinfo
->dobj
.name
));
9023 ArchiveEntry(fout
, prsinfo
->dobj
.catId
, prsinfo
->dobj
.dumpId
,
9025 prsinfo
->dobj
.namespace->dobj
.name
,
9028 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA
,
9029 q
->data
, delq
->data
, NULL
,
9030 prsinfo
->dobj
.dependencies
, prsinfo
->dobj
.nDeps
,
9033 /* Dump Parser Comments */
9034 resetPQExpBuffer(q
);
9035 appendPQExpBuffer(q
, "TEXT SEARCH PARSER %s",
9036 fmtId(prsinfo
->dobj
.name
));
9037 dumpComment(fout
, q
->data
,
9039 prsinfo
->dobj
.catId
, 0, prsinfo
->dobj
.dumpId
);
9041 destroyPQExpBuffer(q
);
9042 destroyPQExpBuffer(delq
);
9047 * write out a single text search dictionary
9050 dumpTSDictionary(Archive
*fout
, TSDictInfo
*dictinfo
)
9060 /* Skip if not to be dumped */
9061 if (!dictinfo
->dobj
.dump
|| dataOnly
)
9064 q
= createPQExpBuffer();
9065 delq
= createPQExpBuffer();
9066 query
= createPQExpBuffer();
9068 /* Fetch name and namespace of the dictionary's template */
9069 selectSourceSchema("pg_catalog");
9070 appendPQExpBuffer(query
, "SELECT nspname, tmplname "
9071 "FROM pg_ts_template p, pg_namespace n "
9072 "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
9073 dictinfo
->dicttemplate
);
9074 res
= PQexec(g_conn
, query
->data
);
9075 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9076 ntups
= PQntuples(res
);
9079 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
9080 "query returned %d rows instead of one: %s\n",
9082 ntups
, query
->data
);
9085 nspname
= PQgetvalue(res
, 0, 0);
9086 tmplname
= PQgetvalue(res
, 0, 1);
9088 /* Make sure we are in proper schema */
9089 selectSourceSchema(dictinfo
->dobj
.namespace->dobj
.name
);
9091 appendPQExpBuffer(q
, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9092 fmtId(dictinfo
->dobj
.name
));
9094 appendPQExpBuffer(q
, " TEMPLATE = ");
9095 if (strcmp(nspname
, dictinfo
->dobj
.namespace->dobj
.name
) != 0)
9096 appendPQExpBuffer(q
, "%s.", fmtId(nspname
));
9097 appendPQExpBuffer(q
, "%s", fmtId(tmplname
));
9101 /* the dictinitoption can be dumped straight into the command */
9102 if (dictinfo
->dictinitoption
)
9103 appendPQExpBuffer(q
, ",\n %s", dictinfo
->dictinitoption
);
9105 appendPQExpBuffer(q
, " );\n");
9108 * DROP must be fully qualified in case same name appears in pg_catalog
9110 appendPQExpBuffer(delq
, "DROP TEXT SEARCH DICTIONARY %s",
9111 fmtId(dictinfo
->dobj
.namespace->dobj
.name
));
9112 appendPQExpBuffer(delq
, ".%s;\n",
9113 fmtId(dictinfo
->dobj
.name
));
9115 ArchiveEntry(fout
, dictinfo
->dobj
.catId
, dictinfo
->dobj
.dumpId
,
9116 dictinfo
->dobj
.name
,
9117 dictinfo
->dobj
.namespace->dobj
.name
,
9120 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA
,
9121 q
->data
, delq
->data
, NULL
,
9122 dictinfo
->dobj
.dependencies
, dictinfo
->dobj
.nDeps
,
9125 /* Dump Dictionary Comments */
9126 resetPQExpBuffer(q
);
9127 appendPQExpBuffer(q
, "TEXT SEARCH DICTIONARY %s",
9128 fmtId(dictinfo
->dobj
.name
));
9129 dumpComment(fout
, q
->data
,
9130 NULL
, dictinfo
->rolname
,
9131 dictinfo
->dobj
.catId
, 0, dictinfo
->dobj
.dumpId
);
9133 destroyPQExpBuffer(q
);
9134 destroyPQExpBuffer(delq
);
9135 destroyPQExpBuffer(query
);
9140 * write out a single text search template
9143 dumpTSTemplate(Archive
*fout
, TSTemplateInfo
*tmplinfo
)
9148 /* Skip if not to be dumped */
9149 if (!tmplinfo
->dobj
.dump
|| dataOnly
)
9152 q
= createPQExpBuffer();
9153 delq
= createPQExpBuffer();
9155 /* Make sure we are in proper schema */
9156 selectSourceSchema(tmplinfo
->dobj
.namespace->dobj
.name
);
9158 appendPQExpBuffer(q
, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9159 fmtId(tmplinfo
->dobj
.name
));
9161 if (tmplinfo
->tmplinit
!= InvalidOid
)
9162 appendPQExpBuffer(q
, " INIT = %s,\n",
9163 convertTSFunction(tmplinfo
->tmplinit
));
9164 appendPQExpBuffer(q
, " LEXIZE = %s );\n",
9165 convertTSFunction(tmplinfo
->tmpllexize
));
9168 * DROP must be fully qualified in case same name appears in pg_catalog
9170 appendPQExpBuffer(delq
, "DROP TEXT SEARCH TEMPLATE %s",
9171 fmtId(tmplinfo
->dobj
.namespace->dobj
.name
));
9172 appendPQExpBuffer(delq
, ".%s;\n",
9173 fmtId(tmplinfo
->dobj
.name
));
9175 ArchiveEntry(fout
, tmplinfo
->dobj
.catId
, tmplinfo
->dobj
.dumpId
,
9176 tmplinfo
->dobj
.name
,
9177 tmplinfo
->dobj
.namespace->dobj
.name
,
9180 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA
,
9181 q
->data
, delq
->data
, NULL
,
9182 tmplinfo
->dobj
.dependencies
, tmplinfo
->dobj
.nDeps
,
9185 /* Dump Template Comments */
9186 resetPQExpBuffer(q
);
9187 appendPQExpBuffer(q
, "TEXT SEARCH TEMPLATE %s",
9188 fmtId(tmplinfo
->dobj
.name
));
9189 dumpComment(fout
, q
->data
,
9191 tmplinfo
->dobj
.catId
, 0, tmplinfo
->dobj
.dumpId
);
9193 destroyPQExpBuffer(q
);
9194 destroyPQExpBuffer(delq
);
9199 * write out a single text search configuration
9202 dumpTSConfig(Archive
*fout
, TSConfigInfo
*cfginfo
)
9215 /* Skip if not to be dumped */
9216 if (!cfginfo
->dobj
.dump
|| dataOnly
)
9219 q
= createPQExpBuffer();
9220 delq
= createPQExpBuffer();
9221 query
= createPQExpBuffer();
9223 /* Fetch name and namespace of the config's parser */
9224 selectSourceSchema("pg_catalog");
9225 appendPQExpBuffer(query
, "SELECT nspname, prsname "
9226 "FROM pg_ts_parser p, pg_namespace n "
9227 "WHERE p.oid = '%u' AND n.oid = prsnamespace",
9228 cfginfo
->cfgparser
);
9229 res
= PQexec(g_conn
, query
->data
);
9230 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9231 ntups
= PQntuples(res
);
9234 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
9235 "query returned %d rows instead of one: %s\n",
9237 ntups
, query
->data
);
9240 nspname
= PQgetvalue(res
, 0, 0);
9241 prsname
= PQgetvalue(res
, 0, 1);
9243 /* Make sure we are in proper schema */
9244 selectSourceSchema(cfginfo
->dobj
.namespace->dobj
.name
);
9246 appendPQExpBuffer(q
, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9247 fmtId(cfginfo
->dobj
.name
));
9249 appendPQExpBuffer(q
, " PARSER = ");
9250 if (strcmp(nspname
, cfginfo
->dobj
.namespace->dobj
.name
) != 0)
9251 appendPQExpBuffer(q
, "%s.", fmtId(nspname
));
9252 appendPQExpBuffer(q
, "%s );\n", fmtId(prsname
));
9256 resetPQExpBuffer(query
);
9257 appendPQExpBuffer(query
,
9259 " ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
9260 " WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
9261 " m.mapdict::pg_catalog.regdictionary AS dictname \n"
9262 "FROM pg_catalog.pg_ts_config_map AS m \n"
9263 "WHERE m.mapcfg = '%u' \n"
9264 "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
9265 cfginfo
->cfgparser
, cfginfo
->dobj
.catId
.oid
);
9267 res
= PQexec(g_conn
, query
->data
);
9268 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9269 ntups
= PQntuples(res
);
9271 i_tokenname
= PQfnumber(res
, "tokenname");
9272 i_dictname
= PQfnumber(res
, "dictname");
9274 for (i
= 0; i
< ntups
; i
++)
9276 char *tokenname
= PQgetvalue(res
, i
, i_tokenname
);
9277 char *dictname
= PQgetvalue(res
, i
, i_dictname
);
9280 strcmp(tokenname
, PQgetvalue(res
, i
- 1, i_tokenname
)) != 0)
9282 /* starting a new token type, so start a new command */
9284 appendPQExpBuffer(q
, ";\n");
9285 appendPQExpBuffer(q
, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
9286 fmtId(cfginfo
->dobj
.name
));
9287 /* tokenname needs quoting, dictname does NOT */
9288 appendPQExpBuffer(q
, " ADD MAPPING FOR %s WITH %s",
9289 fmtId(tokenname
), dictname
);
9292 appendPQExpBuffer(q
, ", %s", dictname
);
9296 appendPQExpBuffer(q
, ";\n");
9301 * DROP must be fully qualified in case same name appears in pg_catalog
9303 appendPQExpBuffer(delq
, "DROP TEXT SEARCH CONFIGURATION %s",
9304 fmtId(cfginfo
->dobj
.namespace->dobj
.name
));
9305 appendPQExpBuffer(delq
, ".%s;\n",
9306 fmtId(cfginfo
->dobj
.name
));
9308 ArchiveEntry(fout
, cfginfo
->dobj
.catId
, cfginfo
->dobj
.dumpId
,
9310 cfginfo
->dobj
.namespace->dobj
.name
,
9313 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA
,
9314 q
->data
, delq
->data
, NULL
,
9315 cfginfo
->dobj
.dependencies
, cfginfo
->dobj
.nDeps
,
9318 /* Dump Configuration Comments */
9319 resetPQExpBuffer(q
);
9320 appendPQExpBuffer(q
, "TEXT SEARCH CONFIGURATION %s",
9321 fmtId(cfginfo
->dobj
.name
));
9322 dumpComment(fout
, q
->data
,
9323 NULL
, cfginfo
->rolname
,
9324 cfginfo
->dobj
.catId
, 0, cfginfo
->dobj
.dumpId
);
9326 destroyPQExpBuffer(q
);
9327 destroyPQExpBuffer(delq
);
9328 destroyPQExpBuffer(query
);
9332 * dumpForeignDataWrapper
9333 * write out a single foreign-data wrapper definition
9336 dumpForeignDataWrapper(Archive
*fout
, FdwInfo
*fdwinfo
)
9342 /* Skip if not to be dumped */
9343 if (!fdwinfo
->dobj
.dump
|| dataOnly
)
9346 q
= createPQExpBuffer();
9347 delq
= createPQExpBuffer();
9349 appendPQExpBuffer(q
, "CREATE FOREIGN DATA WRAPPER %s",
9350 fmtId(fdwinfo
->dobj
.name
));
9352 if (fdwinfo
->fdwvalidator
&& strcmp(fdwinfo
->fdwvalidator
, "-") != 0)
9353 appendPQExpBuffer(q
, " VALIDATOR %s",
9354 fdwinfo
->fdwvalidator
);
9356 if (fdwinfo
->fdwoptions
&& strlen(fdwinfo
->fdwoptions
) > 0)
9357 appendPQExpBuffer(q
, " OPTIONS (%s)", fdwinfo
->fdwoptions
);
9359 appendPQExpBuffer(q
, ";\n");
9361 appendPQExpBuffer(delq
, "DROP FOREIGN DATA WRAPPER %s;\n",
9362 fmtId(fdwinfo
->dobj
.name
));
9364 ArchiveEntry(fout
, fdwinfo
->dobj
.catId
, fdwinfo
->dobj
.dumpId
,
9369 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA
,
9370 q
->data
, delq
->data
, NULL
,
9371 fdwinfo
->dobj
.dependencies
, fdwinfo
->dobj
.nDeps
,
9374 /* Handle the ACL */
9375 namecopy
= strdup(fmtId(fdwinfo
->dobj
.name
));
9376 dumpACL(fout
, fdwinfo
->dobj
.catId
, fdwinfo
->dobj
.dumpId
,
9377 "FOREIGN DATA WRAPPER",
9378 namecopy
, NULL
, fdwinfo
->dobj
.name
,
9379 NULL
, fdwinfo
->rolname
,
9383 destroyPQExpBuffer(q
);
9384 destroyPQExpBuffer(delq
);
9389 * write out a foreign server definition
9392 dumpForeignServer(Archive
*fout
, ForeignServerInfo
*srvinfo
)
9402 /* Skip if not to be dumped */
9403 if (!srvinfo
->dobj
.dump
|| dataOnly
)
9406 q
= createPQExpBuffer();
9407 delq
= createPQExpBuffer();
9408 query
= createPQExpBuffer();
9410 /* look up the foreign-data wrapper */
9411 appendPQExpBuffer(query
, "SELECT fdwname "
9412 "FROM pg_foreign_data_wrapper w "
9413 "WHERE w.oid = '%u'",
9415 res
= PQexec(g_conn
, query
->data
);
9416 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9417 ntups
= PQntuples(res
);
9420 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
9421 "query returned %d rows instead of one: %s\n",
9423 ntups
, query
->data
);
9426 fdwname
= PQgetvalue(res
, 0, 0);
9428 appendPQExpBuffer(q
, "CREATE SERVER %s", fmtId(srvinfo
->dobj
.name
));
9429 if (srvinfo
->srvtype
&& strlen(srvinfo
->srvtype
) > 0)
9431 appendPQExpBuffer(q
, " TYPE ");
9432 appendStringLiteralAH(q
, srvinfo
->srvtype
, fout
);
9434 if (srvinfo
->srvversion
&& strlen(srvinfo
->srvversion
) > 0)
9436 appendPQExpBuffer(q
, " VERSION ");
9437 appendStringLiteralAH(q
, srvinfo
->srvversion
, fout
);
9440 appendPQExpBuffer(q
, " FOREIGN DATA WRAPPER ");
9441 appendPQExpBuffer(q
, "%s", fmtId(fdwname
));
9443 if (srvinfo
->srvoptions
&& strlen(srvinfo
->srvoptions
) > 0)
9444 appendPQExpBuffer(q
, " OPTIONS (%s)", srvinfo
->srvoptions
);
9446 appendPQExpBuffer(q
, ";\n");
9448 appendPQExpBuffer(delq
, "DROP SERVER %s;\n",
9449 fmtId(srvinfo
->dobj
.name
));
9451 ArchiveEntry(fout
, srvinfo
->dobj
.catId
, srvinfo
->dobj
.dumpId
,
9456 false, "SERVER", SECTION_PRE_DATA
,
9457 q
->data
, delq
->data
, NULL
,
9458 srvinfo
->dobj
.dependencies
, srvinfo
->dobj
.nDeps
,
9461 /* Handle the ACL */
9462 namecopy
= strdup(fmtId(srvinfo
->dobj
.name
));
9463 dumpACL(fout
, srvinfo
->dobj
.catId
, srvinfo
->dobj
.dumpId
,
9465 namecopy
, NULL
, srvinfo
->dobj
.name
,
9466 NULL
, srvinfo
->rolname
,
9470 /* Dump user mappings */
9471 resetPQExpBuffer(q
);
9472 appendPQExpBuffer(q
, "SERVER %s", fmtId(srvinfo
->dobj
.name
));
9473 dumpUserMappings(fout
, q
->data
,
9474 srvinfo
->dobj
.name
, NULL
,
9476 srvinfo
->dobj
.catId
, srvinfo
->dobj
.dumpId
);
9478 destroyPQExpBuffer(q
);
9479 destroyPQExpBuffer(delq
);
9485 * This routine is used to dump any user mappings associated with the
9486 * server handed to this routine. Should be called after ArchiveEntry()
9490 dumpUserMappings(Archive
*fout
, const char *target
,
9491 const char *servername
, const char *namespace,
9493 CatalogId catalogId
, DumpId dumpId
)
9505 q
= createPQExpBuffer();
9506 tag
= createPQExpBuffer();
9507 delq
= createPQExpBuffer();
9508 query
= createPQExpBuffer();
9510 appendPQExpBuffer(query
,
9511 "SELECT (%s umuser) AS umuser, "
9512 "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
9513 "FROM pg_user_mapping "
9514 "WHERE umserver=%u",
9518 res
= PQexec(g_conn
, query
->data
);
9519 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9521 ntups
= PQntuples(res
);
9522 i_umuser
= PQfnumber(res
, "umuser");
9523 i_umoptions
= PQfnumber(res
, "umoptions");
9525 for (i
= 0; i
< ntups
; i
++)
9530 umuser
= PQgetvalue(res
, i
, i_umuser
);
9531 umoptions
= PQgetvalue(res
, i
, i_umoptions
);
9533 resetPQExpBuffer(q
);
9534 appendPQExpBuffer(q
, "CREATE USER MAPPING FOR %s", fmtId(umuser
));
9535 appendPQExpBuffer(q
, " SERVER %s", fmtId(servername
));
9537 if (umoptions
&& strlen(umoptions
) > 0)
9538 appendPQExpBuffer(q
, " OPTIONS (%s)", umoptions
);
9540 appendPQExpBuffer(q
, ";\n");
9542 resetPQExpBuffer(delq
);
9543 appendPQExpBuffer(delq
, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser
), fmtId(servername
));
9545 resetPQExpBuffer(tag
);
9546 appendPQExpBuffer(tag
, "USER MAPPING %s %s", fmtId(umuser
), target
);
9548 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
9553 "USER MAPPING", SECTION_PRE_DATA
,
9554 q
->data
, delq
->data
, NULL
,
9561 destroyPQExpBuffer(query
);
9562 destroyPQExpBuffer(delq
);
9563 destroyPQExpBuffer(q
);
9567 * Write out grant/revoke information
9569 * 'objCatId' is the catalog ID of the underlying object.
9570 * 'objDumpId' is the dump ID of the underlying object.
9571 * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
9572 * 'name' is the formatted name of the object. Must be quoted etc. already.
9573 * 'subname' is the formatted name of the sub-object, if any. Must be quoted.
9574 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
9575 * 'nspname' is the namespace the object is in (NULL if none).
9576 * 'owner' is the owner, NULL if there is no owner (for languages).
9577 * 'acls' is the string read out of the fooacl system catalog field;
9578 * it will be parsed here.
9582 dumpACL(Archive
*fout
, CatalogId objCatId
, DumpId objDumpId
,
9583 const char *type
, const char *name
, const char *subname
,
9584 const char *tag
, const char *nspname
, const char *owner
,
9589 /* Do nothing if ACL dump is not enabled */
9590 if (dataOnly
|| aclsSkip
)
9593 sql
= createPQExpBuffer();
9595 if (!buildACLCommands(name
, subname
, type
, acls
, owner
, fout
->remoteVersion
, sql
))
9597 write_msg(NULL
, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
9603 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
9607 false, "ACL", SECTION_NONE
,
9608 sql
->data
, "", NULL
,
9612 destroyPQExpBuffer(sql
);
9617 * write out to fout the declarations (not data) of a user-defined table
9620 dumpTable(Archive
*fout
, TableInfo
*tbinfo
)
9622 if (tbinfo
->dobj
.dump
)
9626 if (tbinfo
->relkind
== RELKIND_SEQUENCE
)
9627 dumpSequence(fout
, tbinfo
);
9629 dumpTableSchema(fout
, tbinfo
);
9631 /* Handle the ACL here */
9632 namecopy
= strdup(fmtId(tbinfo
->dobj
.name
));
9633 dumpACL(fout
, tbinfo
->dobj
.catId
, tbinfo
->dobj
.dumpId
,
9634 (tbinfo
->relkind
== RELKIND_SEQUENCE
) ? "SEQUENCE" : "TABLE",
9635 namecopy
, NULL
, tbinfo
->dobj
.name
,
9636 tbinfo
->dobj
.namespace->dobj
.name
, tbinfo
->rolname
,
9640 * Handle column ACLs, if any. Note: we pull these with a separate
9641 * query rather than trying to fetch them during getTableAttrs, so
9642 * that we won't miss ACLs on system columns.
9644 if (g_fout
->remoteVersion
>= 80400)
9646 PQExpBuffer query
= createPQExpBuffer();
9650 appendPQExpBuffer(query
,
9651 "SELECT attname, attacl FROM pg_catalog.pg_attribute "
9652 "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
9654 tbinfo
->dobj
.catId
.oid
);
9655 res
= PQexec(g_conn
, query
->data
);
9656 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9658 for (i
= 0; i
< PQntuples(res
); i
++)
9660 char *attname
= PQgetvalue(res
, i
, 0);
9661 char *attacl
= PQgetvalue(res
, i
, 1);
9665 attnamecopy
= strdup(fmtId(attname
));
9666 acltag
= malloc(strlen(tbinfo
->dobj
.name
) + strlen(attname
) + 2);
9667 sprintf(acltag
, "%s.%s", tbinfo
->dobj
.name
, attname
);
9668 /* Column's GRANT type is always TABLE */
9669 dumpACL(fout
, tbinfo
->dobj
.catId
, tbinfo
->dobj
.dumpId
, "TABLE",
9670 namecopy
, attnamecopy
, acltag
,
9671 tbinfo
->dobj
.namespace->dobj
.name
, tbinfo
->rolname
,
9677 destroyPQExpBuffer(query
);
9686 * write the declaration (not data) of one user-defined table or view
9689 dumpTableSchema(Archive
*fout
, TableInfo
*tbinfo
)
9691 PQExpBuffer query
= createPQExpBuffer();
9692 PQExpBuffer q
= createPQExpBuffer();
9693 PQExpBuffer delq
= createPQExpBuffer();
9696 TableInfo
**parents
;
9697 int actual_atts
; /* number of attrs in this CREATE statment */
9703 /* Make sure we are in proper schema */
9704 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
9706 /* Is it a table or a view? */
9707 if (tbinfo
->relkind
== RELKIND_VIEW
)
9711 reltypename
= "VIEW";
9713 /* Fetch the view definition */
9714 if (g_fout
->remoteVersion
>= 70300)
9716 /* Beginning in 7.3, viewname is not unique; rely on OID */
9717 appendPQExpBuffer(query
,
9718 "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
9719 tbinfo
->dobj
.catId
.oid
);
9723 appendPQExpBuffer(query
, "SELECT definition AS viewdef "
9724 "FROM pg_views WHERE viewname = ");
9725 appendStringLiteralAH(query
, tbinfo
->dobj
.name
, fout
);
9726 appendPQExpBuffer(query
, ";");
9729 res
= PQexec(g_conn
, query
->data
);
9730 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
9732 if (PQntuples(res
) != 1)
9734 if (PQntuples(res
) < 1)
9735 write_msg(NULL
, "query to obtain definition of view \"%s\" returned no data\n",
9738 write_msg(NULL
, "query to obtain definition of view \"%s\" returned more than one definition\n",
9743 viewdef
= PQgetvalue(res
, 0, 0);
9745 if (strlen(viewdef
) == 0)
9747 write_msg(NULL
, "definition of view \"%s\" appears to be empty (length zero)\n",
9753 * DROP must be fully qualified in case same name appears in
9756 appendPQExpBuffer(delq
, "DROP VIEW %s.",
9757 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
9758 appendPQExpBuffer(delq
, "%s;\n",
9759 fmtId(tbinfo
->dobj
.name
));
9761 appendPQExpBuffer(q
, "CREATE VIEW %s AS\n %s\n",
9762 fmtId(tbinfo
->dobj
.name
), viewdef
);
9768 reltypename
= "TABLE";
9769 numParents
= tbinfo
->numParents
;
9770 parents
= tbinfo
->parents
;
9773 * DROP must be fully qualified in case same name appears in
9776 appendPQExpBuffer(delq
, "DROP TABLE %s.",
9777 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
9778 appendPQExpBuffer(delq
, "%s;\n",
9779 fmtId(tbinfo
->dobj
.name
));
9781 appendPQExpBuffer(q
, "CREATE TABLE %s (",
9782 fmtId(tbinfo
->dobj
.name
));
9784 for (j
= 0; j
< tbinfo
->numatts
; j
++)
9786 /* Is this one of the table's own attrs, and not dropped ? */
9787 if (!tbinfo
->inhAttrs
[j
] &&
9788 (!tbinfo
->attisdropped
[j
] || binary_upgrade
))
9790 /* Format properly if not first attr */
9791 if (actual_atts
> 0)
9792 appendPQExpBuffer(q
, ",");
9793 appendPQExpBuffer(q
, "\n ");
9795 /* Attribute name */
9796 appendPQExpBuffer(q
, "%s ",
9797 fmtId(tbinfo
->attnames
[j
]));
9799 /* Attribute type */
9800 if (g_fout
->remoteVersion
>= 70100)
9802 appendPQExpBuffer(q
, "%s",
9803 tbinfo
->atttypnames
[j
]);
9807 /* If no format_type, fake it */
9808 appendPQExpBuffer(q
, "%s",
9809 myFormatType(tbinfo
->atttypnames
[j
],
9810 tbinfo
->atttypmod
[j
]));
9814 * Default value --- suppress if inherited or to be printed
9817 if (tbinfo
->attrdefs
[j
] != NULL
&&
9818 !tbinfo
->inhAttrDef
[j
] &&
9819 !tbinfo
->attrdefs
[j
]->separate
)
9820 appendPQExpBuffer(q
, " DEFAULT %s",
9821 tbinfo
->attrdefs
[j
]->adef_expr
);
9824 * Not Null constraint --- suppress if inherited
9826 if (tbinfo
->notnull
[j
] && !tbinfo
->inhNotNull
[j
])
9827 appendPQExpBuffer(q
, " NOT NULL");
9834 * Add non-inherited CHECK constraints, if any.
9836 for (j
= 0; j
< tbinfo
->ncheck
; j
++)
9838 ConstraintInfo
*constr
= &(tbinfo
->checkexprs
[j
]);
9840 if (constr
->separate
|| !constr
->conislocal
)
9843 if (actual_atts
> 0)
9844 appendPQExpBuffer(q
, ",\n ");
9846 appendPQExpBuffer(q
, "CONSTRAINT %s ",
9847 fmtId(constr
->dobj
.name
));
9848 appendPQExpBuffer(q
, "%s", constr
->condef
);
9853 appendPQExpBuffer(q
, "\n)");
9857 appendPQExpBuffer(q
, "\nINHERITS (");
9858 for (k
= 0; k
< numParents
; k
++)
9860 TableInfo
*parentRel
= parents
[k
];
9863 appendPQExpBuffer(q
, ", ");
9864 if (parentRel
->dobj
.namespace != tbinfo
->dobj
.namespace)
9865 appendPQExpBuffer(q
, "%s.",
9866 fmtId(parentRel
->dobj
.namespace->dobj
.name
));
9867 appendPQExpBuffer(q
, "%s",
9868 fmtId(parentRel
->dobj
.name
));
9870 appendPQExpBuffer(q
, ")");
9873 if ((tbinfo
->reloptions
&& strlen(tbinfo
->reloptions
) > 0) ||
9874 (tbinfo
->toast_reloptions
&& strlen(tbinfo
->toast_reloptions
) > 0))
9876 bool addcomma
= false;
9878 appendPQExpBuffer(q
, "\nWITH (");
9879 if (tbinfo
->reloptions
&& strlen(tbinfo
->reloptions
) > 0)
9882 appendPQExpBuffer(q
, "%s", tbinfo
->reloptions
);
9884 if (tbinfo
->toast_reloptions
&& strlen(tbinfo
->toast_reloptions
) > 0)
9886 appendPQExpBuffer(q
, "%s%s", addcomma
? ", " : "",
9887 tbinfo
->toast_reloptions
);
9889 appendPQExpBuffer(q
, ")");
9892 appendPQExpBuffer(q
, ";\n");
9895 * For binary-compatible heap files, we create dropped columns above
9896 * and drop them here.
9900 for (j
= 0; j
< tbinfo
->numatts
; j
++)
9902 if (tbinfo
->attisdropped
[j
])
9904 appendPQExpBuffer(q
, "ALTER TABLE ONLY %s ",
9905 fmtId(tbinfo
->dobj
.name
));
9906 appendPQExpBuffer(q
, "DROP COLUMN %s;\n",
9907 fmtId(tbinfo
->attnames
[j
]));
9910 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
9911 * so we have to set pg_attribute.attlen and
9912 * pg_attribute.attalign values because that is what is
9913 * used to skip over dropped columns in the heap tuples.
9914 * We have atttypmod, but it seems impossible to know the
9915 * correct data type that will yield pg_attribute values
9916 * that match the old installation. See comment in
9917 * backend/catalog/heap.c::RemoveAttributeById()
9919 appendPQExpBuffer(q
, "\n-- For binary upgrade, recreate dropped column's length and alignment.\n");
9920 appendPQExpBuffer(q
, "UPDATE pg_attribute\n"
9923 "WHERE attname = '%s'\n"
9924 " AND attrelid = \n"
9928 " WHERE relnamespace = "
9929 "(SELECT oid FROM pg_namespace "
9930 "WHERE nspname = CURRENT_SCHEMA)\n"
9933 tbinfo
->attalign
[j
],
9934 tbinfo
->attnames
[j
]);
9935 appendStringLiteralAH(q
, tbinfo
->dobj
.name
, fout
);
9936 appendPQExpBuffer(q
, "\n );\n");
9939 appendPQExpBuffer(q
, "\n-- For binary upgrade, set relfrozenxid.\n");
9940 appendPQExpBuffer(q
, "UPDATE pg_class\n"
9941 "SET relfrozenxid = '%u'\n"
9944 appendStringLiteralAH(q
, tbinfo
->dobj
.name
, fout
);
9945 appendPQExpBuffer(q
, "\n AND relnamespace = "
9946 "(SELECT oid FROM pg_namespace "
9947 "WHERE nspname = CURRENT_SCHEMA);\n");
9950 /* Loop dumping statistics and storage statements */
9951 for (j
= 0; j
< tbinfo
->numatts
; j
++)
9954 * Dump per-column statistics information. We only issue an ALTER
9955 * TABLE statement if the attstattarget entry for this column is
9956 * non-negative (i.e. it's not the default value)
9958 if (tbinfo
->attstattarget
[j
] >= 0 &&
9959 !tbinfo
->attisdropped
[j
])
9961 appendPQExpBuffer(q
, "ALTER TABLE ONLY %s ",
9962 fmtId(tbinfo
->dobj
.name
));
9963 appendPQExpBuffer(q
, "ALTER COLUMN %s ",
9964 fmtId(tbinfo
->attnames
[j
]));
9965 appendPQExpBuffer(q
, "SET STATISTICS %d;\n",
9966 tbinfo
->attstattarget
[j
]);
9970 * Dump per-column storage information. The statement is only
9971 * dumped if the storage has been changed from the type's default.
9973 if (!tbinfo
->attisdropped
[j
] && tbinfo
->attstorage
[j
] != tbinfo
->typstorage
[j
])
9975 switch (tbinfo
->attstorage
[j
])
9981 storage
= "EXTERNAL";
9987 storage
= "EXTENDED";
9994 * Only dump the statement if it's a storage type we recognize
9996 if (storage
!= NULL
)
9998 appendPQExpBuffer(q
, "ALTER TABLE ONLY %s ",
9999 fmtId(tbinfo
->dobj
.name
));
10000 appendPQExpBuffer(q
, "ALTER COLUMN %s ",
10001 fmtId(tbinfo
->attnames
[j
]));
10002 appendPQExpBuffer(q
, "SET STORAGE %s;\n",
10009 ArchiveEntry(fout
, tbinfo
->dobj
.catId
, tbinfo
->dobj
.dumpId
,
10011 tbinfo
->dobj
.namespace->dobj
.name
,
10012 (tbinfo
->relkind
== RELKIND_VIEW
) ? NULL
: tbinfo
->reltablespace
,
10014 (strcmp(reltypename
, "TABLE") == 0) ? tbinfo
->hasoids
: false,
10015 reltypename
, SECTION_PRE_DATA
,
10016 q
->data
, delq
->data
, NULL
,
10017 tbinfo
->dobj
.dependencies
, tbinfo
->dobj
.nDeps
,
10020 /* Dump Table Comments */
10021 dumpTableComment(fout
, tbinfo
, reltypename
);
10023 /* Dump comments on inlined table constraints */
10024 for (j
= 0; j
< tbinfo
->ncheck
; j
++)
10026 ConstraintInfo
*constr
= &(tbinfo
->checkexprs
[j
]);
10028 if (constr
->separate
|| !constr
->conislocal
)
10031 dumpTableConstraintComment(fout
, constr
);
10034 destroyPQExpBuffer(query
);
10035 destroyPQExpBuffer(q
);
10036 destroyPQExpBuffer(delq
);
10040 * dumpAttrDef --- dump an attribute's default-value declaration
10043 dumpAttrDef(Archive
*fout
, AttrDefInfo
*adinfo
)
10045 TableInfo
*tbinfo
= adinfo
->adtable
;
10046 int adnum
= adinfo
->adnum
;
10050 /* Only print it if "separate" mode is selected */
10051 if (!tbinfo
->dobj
.dump
|| !adinfo
->separate
|| dataOnly
)
10054 /* Don't print inherited defaults, either */
10055 if (tbinfo
->inhAttrDef
[adnum
- 1])
10058 q
= createPQExpBuffer();
10059 delq
= createPQExpBuffer();
10061 appendPQExpBuffer(q
, "ALTER TABLE %s ",
10062 fmtId(tbinfo
->dobj
.name
));
10063 appendPQExpBuffer(q
, "ALTER COLUMN %s SET DEFAULT %s;\n",
10064 fmtId(tbinfo
->attnames
[adnum
- 1]),
10065 adinfo
->adef_expr
);
10068 * DROP must be fully qualified in case same name appears in pg_catalog
10070 appendPQExpBuffer(delq
, "ALTER TABLE %s.",
10071 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10072 appendPQExpBuffer(delq
, "%s ",
10073 fmtId(tbinfo
->dobj
.name
));
10074 appendPQExpBuffer(delq
, "ALTER COLUMN %s DROP DEFAULT;\n",
10075 fmtId(tbinfo
->attnames
[adnum
- 1]));
10077 ArchiveEntry(fout
, adinfo
->dobj
.catId
, adinfo
->dobj
.dumpId
,
10078 tbinfo
->attnames
[adnum
- 1],
10079 tbinfo
->dobj
.namespace->dobj
.name
,
10082 false, "DEFAULT", SECTION_PRE_DATA
,
10083 q
->data
, delq
->data
, NULL
,
10084 adinfo
->dobj
.dependencies
, adinfo
->dobj
.nDeps
,
10087 destroyPQExpBuffer(q
);
10088 destroyPQExpBuffer(delq
);
10092 * getAttrName: extract the correct name for an attribute
10094 * The array tblInfo->attnames[] only provides names of user attributes;
10095 * if a system attribute number is supplied, we have to fake it.
10096 * We also do a little bit of bounds checking for safety's sake.
10098 static const char *
10099 getAttrName(int attrnum
, TableInfo
*tblInfo
)
10101 if (attrnum
> 0 && attrnum
<= tblInfo
->numatts
)
10102 return tblInfo
->attnames
[attrnum
- 1];
10105 case SelfItemPointerAttributeNumber
:
10107 case ObjectIdAttributeNumber
:
10109 case MinTransactionIdAttributeNumber
:
10111 case MinCommandIdAttributeNumber
:
10113 case MaxTransactionIdAttributeNumber
:
10115 case MaxCommandIdAttributeNumber
:
10117 case TableOidAttributeNumber
:
10120 write_msg(NULL
, "invalid column number %d for table \"%s\"\n",
10121 attrnum
, tblInfo
->dobj
.name
);
10123 return NULL
; /* keep compiler quiet */
10128 * write out to fout a user-defined index
10131 dumpIndex(Archive
*fout
, IndxInfo
*indxinfo
)
10133 TableInfo
*tbinfo
= indxinfo
->indextable
;
10140 q
= createPQExpBuffer();
10141 delq
= createPQExpBuffer();
10144 * If there's an associated constraint, don't dump the index per se, but
10145 * do dump any comment for it. (This is safe because dependency ordering
10146 * will have ensured the constraint is emitted first.)
10148 if (indxinfo
->indexconstraint
== 0)
10150 /* Plain secondary index */
10151 appendPQExpBuffer(q
, "%s;\n", indxinfo
->indexdef
);
10153 /* If the index is clustered, we need to record that. */
10154 if (indxinfo
->indisclustered
)
10156 appendPQExpBuffer(q
, "\nALTER TABLE %s CLUSTER",
10157 fmtId(tbinfo
->dobj
.name
));
10158 appendPQExpBuffer(q
, " ON %s;\n",
10159 fmtId(indxinfo
->dobj
.name
));
10163 * DROP must be fully qualified in case same name appears in
10166 appendPQExpBuffer(delq
, "DROP INDEX %s.",
10167 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10168 appendPQExpBuffer(delq
, "%s;\n",
10169 fmtId(indxinfo
->dobj
.name
));
10171 ArchiveEntry(fout
, indxinfo
->dobj
.catId
, indxinfo
->dobj
.dumpId
,
10172 indxinfo
->dobj
.name
,
10173 tbinfo
->dobj
.namespace->dobj
.name
,
10174 indxinfo
->tablespace
,
10175 tbinfo
->rolname
, false,
10176 "INDEX", SECTION_POST_DATA
,
10177 q
->data
, delq
->data
, NULL
,
10178 indxinfo
->dobj
.dependencies
, indxinfo
->dobj
.nDeps
,
10182 /* Dump Index Comments */
10183 resetPQExpBuffer(q
);
10184 appendPQExpBuffer(q
, "INDEX %s",
10185 fmtId(indxinfo
->dobj
.name
));
10186 dumpComment(fout
, q
->data
,
10187 tbinfo
->dobj
.namespace->dobj
.name
,
10189 indxinfo
->dobj
.catId
, 0, indxinfo
->dobj
.dumpId
);
10191 destroyPQExpBuffer(q
);
10192 destroyPQExpBuffer(delq
);
10197 * write out to fout a user-defined constraint
10200 dumpConstraint(Archive
*fout
, ConstraintInfo
*coninfo
)
10202 TableInfo
*tbinfo
= coninfo
->contable
;
10206 /* Skip if not to be dumped */
10207 if (!coninfo
->dobj
.dump
|| dataOnly
)
10210 q
= createPQExpBuffer();
10211 delq
= createPQExpBuffer();
10213 if (coninfo
->contype
== 'p' || coninfo
->contype
== 'u')
10215 /* Index-related constraint */
10216 IndxInfo
*indxinfo
;
10219 indxinfo
= (IndxInfo
*) findObjectByDumpId(coninfo
->conindex
);
10221 if (indxinfo
== NULL
)
10223 write_msg(NULL
, "missing index for constraint \"%s\"\n",
10224 coninfo
->dobj
.name
);
10228 appendPQExpBuffer(q
, "ALTER TABLE ONLY %s\n",
10229 fmtId(tbinfo
->dobj
.name
));
10230 appendPQExpBuffer(q
, " ADD CONSTRAINT %s %s (",
10231 fmtId(coninfo
->dobj
.name
),
10232 coninfo
->contype
== 'p' ? "PRIMARY KEY" : "UNIQUE");
10234 for (k
= 0; k
< indxinfo
->indnkeys
; k
++)
10236 int indkey
= (int) indxinfo
->indkeys
[k
];
10237 const char *attname
;
10239 if (indkey
== InvalidAttrNumber
)
10241 attname
= getAttrName(indkey
, tbinfo
);
10243 appendPQExpBuffer(q
, "%s%s",
10244 (k
== 0) ? "" : ", ",
10248 appendPQExpBuffer(q
, ")");
10250 if (indxinfo
->options
&& strlen(indxinfo
->options
) > 0)
10251 appendPQExpBuffer(q
, " WITH (%s)", indxinfo
->options
);
10253 appendPQExpBuffer(q
, ";\n");
10255 /* If the index is clustered, we need to record that. */
10256 if (indxinfo
->indisclustered
)
10258 appendPQExpBuffer(q
, "\nALTER TABLE %s CLUSTER",
10259 fmtId(tbinfo
->dobj
.name
));
10260 appendPQExpBuffer(q
, " ON %s;\n",
10261 fmtId(indxinfo
->dobj
.name
));
10265 * DROP must be fully qualified in case same name appears in
10268 appendPQExpBuffer(delq
, "ALTER TABLE ONLY %s.",
10269 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10270 appendPQExpBuffer(delq
, "%s ",
10271 fmtId(tbinfo
->dobj
.name
));
10272 appendPQExpBuffer(delq
, "DROP CONSTRAINT %s;\n",
10273 fmtId(coninfo
->dobj
.name
));
10275 ArchiveEntry(fout
, coninfo
->dobj
.catId
, coninfo
->dobj
.dumpId
,
10276 coninfo
->dobj
.name
,
10277 tbinfo
->dobj
.namespace->dobj
.name
,
10278 indxinfo
->tablespace
,
10279 tbinfo
->rolname
, false,
10280 "CONSTRAINT", SECTION_POST_DATA
,
10281 q
->data
, delq
->data
, NULL
,
10282 coninfo
->dobj
.dependencies
, coninfo
->dobj
.nDeps
,
10285 else if (coninfo
->contype
== 'f')
10288 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10289 * current table data is not processed
10291 appendPQExpBuffer(q
, "ALTER TABLE ONLY %s\n",
10292 fmtId(tbinfo
->dobj
.name
));
10293 appendPQExpBuffer(q
, " ADD CONSTRAINT %s %s;\n",
10294 fmtId(coninfo
->dobj
.name
),
10298 * DROP must be fully qualified in case same name appears in
10301 appendPQExpBuffer(delq
, "ALTER TABLE ONLY %s.",
10302 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10303 appendPQExpBuffer(delq
, "%s ",
10304 fmtId(tbinfo
->dobj
.name
));
10305 appendPQExpBuffer(delq
, "DROP CONSTRAINT %s;\n",
10306 fmtId(coninfo
->dobj
.name
));
10308 ArchiveEntry(fout
, coninfo
->dobj
.catId
, coninfo
->dobj
.dumpId
,
10309 coninfo
->dobj
.name
,
10310 tbinfo
->dobj
.namespace->dobj
.name
,
10312 tbinfo
->rolname
, false,
10313 "FK CONSTRAINT", SECTION_POST_DATA
,
10314 q
->data
, delq
->data
, NULL
,
10315 coninfo
->dobj
.dependencies
, coninfo
->dobj
.nDeps
,
10318 else if (coninfo
->contype
== 'c' && tbinfo
)
10320 /* CHECK constraint on a table */
10322 /* Ignore if not to be dumped separately */
10323 if (coninfo
->separate
)
10325 /* not ONLY since we want it to propagate to children */
10326 appendPQExpBuffer(q
, "ALTER TABLE %s\n",
10327 fmtId(tbinfo
->dobj
.name
));
10328 appendPQExpBuffer(q
, " ADD CONSTRAINT %s %s;\n",
10329 fmtId(coninfo
->dobj
.name
),
10333 * DROP must be fully qualified in case same name appears in
10336 appendPQExpBuffer(delq
, "ALTER TABLE %s.",
10337 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10338 appendPQExpBuffer(delq
, "%s ",
10339 fmtId(tbinfo
->dobj
.name
));
10340 appendPQExpBuffer(delq
, "DROP CONSTRAINT %s;\n",
10341 fmtId(coninfo
->dobj
.name
));
10343 ArchiveEntry(fout
, coninfo
->dobj
.catId
, coninfo
->dobj
.dumpId
,
10344 coninfo
->dobj
.name
,
10345 tbinfo
->dobj
.namespace->dobj
.name
,
10347 tbinfo
->rolname
, false,
10348 "CHECK CONSTRAINT", SECTION_POST_DATA
,
10349 q
->data
, delq
->data
, NULL
,
10350 coninfo
->dobj
.dependencies
, coninfo
->dobj
.nDeps
,
10354 else if (coninfo
->contype
== 'c' && tbinfo
== NULL
)
10356 /* CHECK constraint on a domain */
10357 TypeInfo
*tinfo
= coninfo
->condomain
;
10359 /* Ignore if not to be dumped separately */
10360 if (coninfo
->separate
)
10362 appendPQExpBuffer(q
, "ALTER DOMAIN %s\n",
10363 fmtId(tinfo
->dobj
.name
));
10364 appendPQExpBuffer(q
, " ADD CONSTRAINT %s %s;\n",
10365 fmtId(coninfo
->dobj
.name
),
10369 * DROP must be fully qualified in case same name appears in
10372 appendPQExpBuffer(delq
, "ALTER DOMAIN %s.",
10373 fmtId(tinfo
->dobj
.namespace->dobj
.name
));
10374 appendPQExpBuffer(delq
, "%s ",
10375 fmtId(tinfo
->dobj
.name
));
10376 appendPQExpBuffer(delq
, "DROP CONSTRAINT %s;\n",
10377 fmtId(coninfo
->dobj
.name
));
10379 ArchiveEntry(fout
, coninfo
->dobj
.catId
, coninfo
->dobj
.dumpId
,
10380 coninfo
->dobj
.name
,
10381 tinfo
->dobj
.namespace->dobj
.name
,
10383 tinfo
->rolname
, false,
10384 "CHECK CONSTRAINT", SECTION_POST_DATA
,
10385 q
->data
, delq
->data
, NULL
,
10386 coninfo
->dobj
.dependencies
, coninfo
->dobj
.nDeps
,
10392 write_msg(NULL
, "unrecognized constraint type: %c\n", coninfo
->contype
);
10396 /* Dump Constraint Comments --- only works for table constraints */
10397 if (tbinfo
&& coninfo
->separate
)
10398 dumpTableConstraintComment(fout
, coninfo
);
10400 destroyPQExpBuffer(q
);
10401 destroyPQExpBuffer(delq
);
10405 * dumpTableConstraintComment --- dump a constraint's comment if any
10407 * This is split out because we need the function in two different places
10408 * depending on whether the constraint is dumped as part of CREATE TABLE
10409 * or as a separate ALTER command.
10412 dumpTableConstraintComment(Archive
*fout
, ConstraintInfo
*coninfo
)
10414 TableInfo
*tbinfo
= coninfo
->contable
;
10415 PQExpBuffer q
= createPQExpBuffer();
10417 appendPQExpBuffer(q
, "CONSTRAINT %s ",
10418 fmtId(coninfo
->dobj
.name
));
10419 appendPQExpBuffer(q
, "ON %s",
10420 fmtId(tbinfo
->dobj
.name
));
10421 dumpComment(fout
, q
->data
,
10422 tbinfo
->dobj
.namespace->dobj
.name
,
10424 coninfo
->dobj
.catId
, 0,
10425 coninfo
->separate
? coninfo
->dobj
.dumpId
: tbinfo
->dobj
.dumpId
);
10427 destroyPQExpBuffer(q
);
10431 * findLastBuiltInOid -
10432 * find the last built in oid
10434 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
10435 * pg_database entry for the current database
10438 findLastBuiltinOid_V71(const char *dbname
)
10443 PQExpBuffer query
= createPQExpBuffer();
10445 resetPQExpBuffer(query
);
10446 appendPQExpBuffer(query
, "SELECT datlastsysoid from pg_database where datname = ");
10447 appendStringLiteralAH(query
, dbname
, g_fout
);
10449 res
= PQexec(g_conn
, query
->data
);
10450 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
10452 ntups
= PQntuples(res
);
10455 write_msg(NULL
, "missing pg_database entry for this database\n");
10460 write_msg(NULL
, "found more than one pg_database entry for this database\n");
10463 last_oid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "datlastsysoid")));
10465 destroyPQExpBuffer(query
);
10470 * findLastBuiltInOid -
10471 * find the last built in oid
10473 * For 7.0, we do this by assuming that the last thing that initdb does is to
10474 * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
10475 * initdb won't be changing anymore, it'll do.
10478 findLastBuiltinOid_V70(void)
10484 res
= PQexec(g_conn
,
10485 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
10486 check_sql_result(res
, g_conn
,
10487 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
10489 ntups
= PQntuples(res
);
10492 write_msg(NULL
, "could not find entry for pg_indexes in pg_class\n");
10497 write_msg(NULL
, "found more than one entry for pg_indexes in pg_class\n");
10500 last_oid
= atooid(PQgetvalue(res
, 0, PQfnumber(res
, "oid")));
10506 dumpSequence(Archive
*fout
, TableInfo
*tbinfo
)
10519 PQExpBuffer query
= createPQExpBuffer();
10520 PQExpBuffer delqry
= createPQExpBuffer();
10522 /* Make sure we are in proper schema */
10523 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
10525 snprintf(bufm
, sizeof(bufm
), INT64_FORMAT
, SEQ_MINVALUE
);
10526 snprintf(bufx
, sizeof(bufx
), INT64_FORMAT
, SEQ_MAXVALUE
);
10528 if (g_fout
->remoteVersion
>= 80400)
10530 appendPQExpBuffer(query
,
10531 "SELECT sequence_name, "
10532 "start_value, last_value, increment_by, "
10533 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10534 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10536 "END AS max_value, "
10537 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10538 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10540 "END AS min_value, "
10541 "cache_value, is_cycled, is_called from %s",
10543 fmtId(tbinfo
->dobj
.name
));
10547 appendPQExpBuffer(query
,
10548 "SELECT sequence_name, "
10549 "0 AS start_value, last_value, increment_by, "
10550 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10551 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10553 "END AS max_value, "
10554 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10555 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
10557 "END AS min_value, "
10558 "cache_value, is_cycled, is_called from %s",
10560 fmtId(tbinfo
->dobj
.name
));
10563 res
= PQexec(g_conn
, query
->data
);
10564 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
10566 if (PQntuples(res
) != 1)
10568 write_msg(NULL
, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
10569 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
10571 tbinfo
->dobj
.name
, PQntuples(res
));
10575 /* Disable this check: it fails if sequence has been renamed */
10577 if (strcmp(PQgetvalue(res
, 0, 0), tbinfo
->dobj
.name
) != 0)
10579 write_msg(NULL
, "query to get data of sequence \"%s\" returned name \"%s\"\n",
10580 tbinfo
->dobj
.name
, PQgetvalue(res
, 0, 0));
10585 startv
= PQgetvalue(res
, 0, 1);
10586 last
= PQgetvalue(res
, 0, 2);
10587 incby
= PQgetvalue(res
, 0, 3);
10588 if (!PQgetisnull(res
, 0, 4))
10589 maxv
= PQgetvalue(res
, 0, 4);
10590 if (!PQgetisnull(res
, 0, 5))
10591 minv
= PQgetvalue(res
, 0, 5);
10592 cache
= PQgetvalue(res
, 0, 6);
10593 cycled
= (strcmp(PQgetvalue(res
, 0, 7), "t") == 0);
10594 called
= (strcmp(PQgetvalue(res
, 0, 8), "t") == 0);
10597 * The logic we use for restoring sequences is as follows:
10599 * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
10600 * last_val for start if called is false, else use min_val for start_val).
10601 * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
10602 * BY command for it.
10604 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
10608 resetPQExpBuffer(delqry
);
10611 * DROP must be fully qualified in case same name appears in
10614 appendPQExpBuffer(delqry
, "DROP SEQUENCE %s.",
10615 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10616 appendPQExpBuffer(delqry
, "%s;\n",
10617 fmtId(tbinfo
->dobj
.name
));
10619 resetPQExpBuffer(query
);
10620 appendPQExpBuffer(query
,
10621 "CREATE SEQUENCE %s\n",
10622 fmtId(tbinfo
->dobj
.name
));
10624 if (g_fout
->remoteVersion
>= 80400)
10625 appendPQExpBuffer(query
, " START WITH %s\n", startv
);
10629 * Versions before 8.4 did not remember the true start value. If
10630 * is_called is false then the sequence has never been incremented
10631 * so we can use last_val. Otherwise punt and let it default.
10634 appendPQExpBuffer(query
, " START WITH %s\n", last
);
10637 appendPQExpBuffer(query
, " INCREMENT BY %s\n", incby
);
10640 appendPQExpBuffer(query
, " MAXVALUE %s\n", maxv
);
10642 appendPQExpBuffer(query
, " NO MAXVALUE\n");
10645 appendPQExpBuffer(query
, " MINVALUE %s\n", minv
);
10647 appendPQExpBuffer(query
, " NO MINVALUE\n");
10649 appendPQExpBuffer(query
,
10651 cache
, (cycled
? "\n CYCLE" : ""));
10653 appendPQExpBuffer(query
, ";\n");
10655 ArchiveEntry(fout
, tbinfo
->dobj
.catId
, tbinfo
->dobj
.dumpId
,
10657 tbinfo
->dobj
.namespace->dobj
.name
,
10660 false, "SEQUENCE", SECTION_PRE_DATA
,
10661 query
->data
, delqry
->data
, NULL
,
10662 tbinfo
->dobj
.dependencies
, tbinfo
->dobj
.nDeps
,
10666 * If the sequence is owned by a table column, emit the ALTER for it
10667 * as a separate TOC entry immediately following the sequence's own
10668 * entry. It's OK to do this rather than using full sorting logic,
10669 * because the dependency that tells us it's owned will have forced
10670 * the table to be created first. We can't just include the ALTER in
10671 * the TOC entry because it will fail if we haven't reassigned the
10672 * sequence owner to match the table's owner.
10674 * We need not schema-qualify the table reference because both
10675 * sequence and table must be in the same schema.
10677 if (OidIsValid(tbinfo
->owning_tab
))
10679 TableInfo
*owning_tab
= findTableByOid(tbinfo
->owning_tab
);
10681 if (owning_tab
&& owning_tab
->dobj
.dump
)
10683 resetPQExpBuffer(query
);
10684 appendPQExpBuffer(query
, "ALTER SEQUENCE %s",
10685 fmtId(tbinfo
->dobj
.name
));
10686 appendPQExpBuffer(query
, " OWNED BY %s",
10687 fmtId(owning_tab
->dobj
.name
));
10688 appendPQExpBuffer(query
, ".%s;\n",
10689 fmtId(owning_tab
->attnames
[tbinfo
->owning_col
- 1]));
10691 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
10693 tbinfo
->dobj
.namespace->dobj
.name
,
10696 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA
,
10697 query
->data
, "", NULL
,
10698 &(tbinfo
->dobj
.dumpId
), 1,
10703 /* Dump Sequence Comments */
10704 resetPQExpBuffer(query
);
10705 appendPQExpBuffer(query
, "SEQUENCE %s", fmtId(tbinfo
->dobj
.name
));
10706 dumpComment(fout
, query
->data
,
10707 tbinfo
->dobj
.namespace->dobj
.name
, tbinfo
->rolname
,
10708 tbinfo
->dobj
.catId
, 0, tbinfo
->dobj
.dumpId
);
10713 resetPQExpBuffer(query
);
10714 appendPQExpBuffer(query
, "SELECT pg_catalog.setval(");
10715 appendStringLiteralAH(query
, fmtId(tbinfo
->dobj
.name
), fout
);
10716 appendPQExpBuffer(query
, ", %s, %s);\n",
10717 last
, (called
? "true" : "false"));
10719 ArchiveEntry(fout
, nilCatalogId
, createDumpId(),
10721 tbinfo
->dobj
.namespace->dobj
.name
,
10724 false, "SEQUENCE SET", SECTION_PRE_DATA
,
10725 query
->data
, "", NULL
,
10726 &(tbinfo
->dobj
.dumpId
), 1,
10732 destroyPQExpBuffer(query
);
10733 destroyPQExpBuffer(delqry
);
10737 dumpTrigger(Archive
*fout
, TriggerInfo
*tginfo
)
10739 TableInfo
*tbinfo
= tginfo
->tgtable
;
10741 PQExpBuffer delqry
;
10748 query
= createPQExpBuffer();
10749 delqry
= createPQExpBuffer();
10752 * DROP must be fully qualified in case same name appears in pg_catalog
10754 appendPQExpBuffer(delqry
, "DROP TRIGGER %s ",
10755 fmtId(tginfo
->dobj
.name
));
10756 appendPQExpBuffer(delqry
, "ON %s.",
10757 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
10758 appendPQExpBuffer(delqry
, "%s;\n",
10759 fmtId(tbinfo
->dobj
.name
));
10761 if (tginfo
->tgisconstraint
)
10763 appendPQExpBuffer(query
, "CREATE CONSTRAINT TRIGGER ");
10764 appendPQExpBufferStr(query
, fmtId(tginfo
->tgconstrname
));
10768 appendPQExpBuffer(query
, "CREATE TRIGGER ");
10769 appendPQExpBufferStr(query
, fmtId(tginfo
->dobj
.name
));
10771 appendPQExpBuffer(query
, "\n ");
10775 if (TRIGGER_FOR_BEFORE(tginfo
->tgtype
))
10776 appendPQExpBuffer(query
, "BEFORE");
10778 appendPQExpBuffer(query
, "AFTER");
10779 if (TRIGGER_FOR_INSERT(tginfo
->tgtype
))
10781 appendPQExpBuffer(query
, " INSERT");
10784 if (TRIGGER_FOR_DELETE(tginfo
->tgtype
))
10787 appendPQExpBuffer(query
, " OR DELETE");
10789 appendPQExpBuffer(query
, " DELETE");
10792 if (TRIGGER_FOR_UPDATE(tginfo
->tgtype
))
10795 appendPQExpBuffer(query
, " OR UPDATE");
10797 appendPQExpBuffer(query
, " UPDATE");
10799 if (TRIGGER_FOR_TRUNCATE(tginfo
->tgtype
))
10802 appendPQExpBuffer(query
, " OR TRUNCATE");
10804 appendPQExpBuffer(query
, " TRUNCATE");
10806 appendPQExpBuffer(query
, " ON %s\n",
10807 fmtId(tbinfo
->dobj
.name
));
10809 if (tginfo
->tgisconstraint
)
10811 if (OidIsValid(tginfo
->tgconstrrelid
))
10813 /* If we are using regclass, name is already quoted */
10814 if (g_fout
->remoteVersion
>= 70300)
10815 appendPQExpBuffer(query
, " FROM %s\n ",
10816 tginfo
->tgconstrrelname
);
10818 appendPQExpBuffer(query
, " FROM %s\n ",
10819 fmtId(tginfo
->tgconstrrelname
));
10821 if (!tginfo
->tgdeferrable
)
10822 appendPQExpBuffer(query
, "NOT ");
10823 appendPQExpBuffer(query
, "DEFERRABLE INITIALLY ");
10824 if (tginfo
->tginitdeferred
)
10825 appendPQExpBuffer(query
, "DEFERRED\n");
10827 appendPQExpBuffer(query
, "IMMEDIATE\n");
10830 if (TRIGGER_FOR_ROW(tginfo
->tgtype
))
10831 appendPQExpBuffer(query
, " FOR EACH ROW\n ");
10833 appendPQExpBuffer(query
, " FOR EACH STATEMENT\n ");
10835 /* In 7.3, result of regproc is already quoted */
10836 if (g_fout
->remoteVersion
>= 70300)
10837 appendPQExpBuffer(query
, "EXECUTE PROCEDURE %s(",
10840 appendPQExpBuffer(query
, "EXECUTE PROCEDURE %s(",
10841 fmtId(tginfo
->tgfname
));
10843 p
= tginfo
->tgargs
;
10844 for (findx
= 0; findx
< tginfo
->tgnargs
; findx
++)
10848 /* Set 'p' to end of arg string. marked by '\000' */
10851 p
= strchr(p
, '\\');
10854 write_msg(NULL
, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10857 tbinfo
->dobj
.name
);
10861 if (*p
== '\\') /* is it '\\'? */
10866 if (p
[0] == '0' && p
[1] == '0' && p
[2] == '0') /* is it '\000'? */
10871 appendPQExpBufferChar(query
, '\'');
10875 appendPQExpBufferChar(query
, '\'');
10878 * bytea unconditionally doubles backslashes, so we suppress the
10879 * doubling for standard_conforming_strings.
10881 if (fout
->std_strings
&& *s
== '\\' && s
[1] == '\\')
10883 appendPQExpBufferChar(query
, *s
++);
10885 appendPQExpBufferChar(query
, '\'');
10886 appendPQExpBuffer(query
,
10887 (findx
< tginfo
->tgnargs
- 1) ? ", " : "");
10890 appendPQExpBuffer(query
, ");\n");
10892 if (tginfo
->tgenabled
!= 't' && tginfo
->tgenabled
!= 'O')
10894 appendPQExpBuffer(query
, "\nALTER TABLE %s ",
10895 fmtId(tbinfo
->dobj
.name
));
10896 switch (tginfo
->tgenabled
)
10900 appendPQExpBuffer(query
, "DISABLE");
10903 appendPQExpBuffer(query
, "ENABLE ALWAYS");
10906 appendPQExpBuffer(query
, "ENABLE REPLICA");
10909 appendPQExpBuffer(query
, "ENABLE");
10912 appendPQExpBuffer(query
, " TRIGGER %s;\n",
10913 fmtId(tginfo
->dobj
.name
));
10916 ArchiveEntry(fout
, tginfo
->dobj
.catId
, tginfo
->dobj
.dumpId
,
10918 tbinfo
->dobj
.namespace->dobj
.name
,
10920 tbinfo
->rolname
, false,
10921 "TRIGGER", SECTION_POST_DATA
,
10922 query
->data
, delqry
->data
, NULL
,
10923 tginfo
->dobj
.dependencies
, tginfo
->dobj
.nDeps
,
10926 resetPQExpBuffer(query
);
10927 appendPQExpBuffer(query
, "TRIGGER %s ",
10928 fmtId(tginfo
->dobj
.name
));
10929 appendPQExpBuffer(query
, "ON %s",
10930 fmtId(tbinfo
->dobj
.name
));
10932 dumpComment(fout
, query
->data
,
10933 tbinfo
->dobj
.namespace->dobj
.name
, tbinfo
->rolname
,
10934 tginfo
->dobj
.catId
, 0, tginfo
->dobj
.dumpId
);
10936 destroyPQExpBuffer(query
);
10937 destroyPQExpBuffer(delqry
);
10945 dumpRule(Archive
*fout
, RuleInfo
*rinfo
)
10947 TableInfo
*tbinfo
= rinfo
->ruletable
;
10950 PQExpBuffer delcmd
;
10953 /* Skip if not to be dumped */
10954 if (!rinfo
->dobj
.dump
|| dataOnly
)
10958 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
10959 * we do not want to dump it as a separate object.
10961 if (!rinfo
->separate
)
10965 * Make sure we are in proper schema.
10967 selectSourceSchema(tbinfo
->dobj
.namespace->dobj
.name
);
10969 query
= createPQExpBuffer();
10970 cmd
= createPQExpBuffer();
10971 delcmd
= createPQExpBuffer();
10973 if (g_fout
->remoteVersion
>= 70300)
10975 appendPQExpBuffer(query
,
10976 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
10977 rinfo
->dobj
.catId
.oid
);
10981 /* Rule name was unique before 7.3 ... */
10982 appendPQExpBuffer(query
,
10983 "SELECT pg_get_ruledef('%s') AS definition",
10987 res
= PQexec(g_conn
, query
->data
);
10988 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
10990 if (PQntuples(res
) != 1)
10992 write_msg(NULL
, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
10993 rinfo
->dobj
.name
, tbinfo
->dobj
.name
);
10997 printfPQExpBuffer(cmd
, "%s\n", PQgetvalue(res
, 0, 0));
11000 * Add the command to alter the rules replication firing semantics if it
11001 * differs from the default.
11003 if (rinfo
->ev_enabled
!= 'O')
11005 appendPQExpBuffer(cmd
, "ALTER TABLE %s.",
11006 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
11007 appendPQExpBuffer(cmd
, "%s ",
11008 fmtId(tbinfo
->dobj
.name
));
11009 switch (rinfo
->ev_enabled
)
11012 appendPQExpBuffer(cmd
, "ENABLE ALWAYS RULE %s;\n",
11013 fmtId(rinfo
->dobj
.name
));
11016 appendPQExpBuffer(cmd
, "ENABLE REPLICA RULE %s;\n",
11017 fmtId(rinfo
->dobj
.name
));
11020 appendPQExpBuffer(cmd
, "DISABLE RULE %s;\n",
11021 fmtId(rinfo
->dobj
.name
));
11027 * DROP must be fully qualified in case same name appears in pg_catalog
11029 appendPQExpBuffer(delcmd
, "DROP RULE %s ",
11030 fmtId(rinfo
->dobj
.name
));
11031 appendPQExpBuffer(delcmd
, "ON %s.",
11032 fmtId(tbinfo
->dobj
.namespace->dobj
.name
));
11033 appendPQExpBuffer(delcmd
, "%s;\n",
11034 fmtId(tbinfo
->dobj
.name
));
11036 ArchiveEntry(fout
, rinfo
->dobj
.catId
, rinfo
->dobj
.dumpId
,
11038 tbinfo
->dobj
.namespace->dobj
.name
,
11040 tbinfo
->rolname
, false,
11041 "RULE", SECTION_POST_DATA
,
11042 cmd
->data
, delcmd
->data
, NULL
,
11043 rinfo
->dobj
.dependencies
, rinfo
->dobj
.nDeps
,
11046 /* Dump rule comments */
11047 resetPQExpBuffer(query
);
11048 appendPQExpBuffer(query
, "RULE %s",
11049 fmtId(rinfo
->dobj
.name
));
11050 appendPQExpBuffer(query
, " ON %s",
11051 fmtId(tbinfo
->dobj
.name
));
11052 dumpComment(fout
, query
->data
,
11053 tbinfo
->dobj
.namespace->dobj
.name
,
11055 rinfo
->dobj
.catId
, 0, rinfo
->dobj
.dumpId
);
11059 destroyPQExpBuffer(query
);
11060 destroyPQExpBuffer(cmd
);
11061 destroyPQExpBuffer(delcmd
);
11065 * getDependencies --- obtain available dependency data
11068 getDependencies(void)
11079 DumpableObject
*dobj
,
11082 /* No dependency info available before 7.3 */
11083 if (g_fout
->remoteVersion
< 70300)
11087 write_msg(NULL
, "reading dependency data\n");
11089 /* Make sure we are in proper schema */
11090 selectSourceSchema("pg_catalog");
11092 query
= createPQExpBuffer();
11094 appendPQExpBuffer(query
, "SELECT "
11095 "classid, objid, refclassid, refobjid, deptype "
11097 "WHERE deptype != 'p' "
11100 res
= PQexec(g_conn
, query
->data
);
11101 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
11103 ntups
= PQntuples(res
);
11105 i_classid
= PQfnumber(res
, "classid");
11106 i_objid
= PQfnumber(res
, "objid");
11107 i_refclassid
= PQfnumber(res
, "refclassid");
11108 i_refobjid
= PQfnumber(res
, "refobjid");
11109 i_deptype
= PQfnumber(res
, "deptype");
11112 * Since we ordered the SELECT by referencing ID, we can expect that
11113 * multiple entries for the same object will appear together; this saves
11118 for (i
= 0; i
< ntups
; i
++)
11121 CatalogId refobjId
;
11124 objId
.tableoid
= atooid(PQgetvalue(res
, i
, i_classid
));
11125 objId
.oid
= atooid(PQgetvalue(res
, i
, i_objid
));
11126 refobjId
.tableoid
= atooid(PQgetvalue(res
, i
, i_refclassid
));
11127 refobjId
.oid
= atooid(PQgetvalue(res
, i
, i_refobjid
));
11128 deptype
= *(PQgetvalue(res
, i
, i_deptype
));
11130 if (dobj
== NULL
||
11131 dobj
->catId
.tableoid
!= objId
.tableoid
||
11132 dobj
->catId
.oid
!= objId
.oid
)
11133 dobj
= findObjectByCatalogId(objId
);
11136 * Failure to find objects mentioned in pg_depend is not unexpected,
11137 * since for example we don't collect info about TOAST tables.
11142 fprintf(stderr
, "no referencing object %u %u\n",
11143 objId
.tableoid
, objId
.oid
);
11148 refdobj
= findObjectByCatalogId(refobjId
);
11150 if (refdobj
== NULL
)
11153 fprintf(stderr
, "no referenced object %u %u\n",
11154 refobjId
.tableoid
, refobjId
.oid
);
11160 * Ordinarily, table rowtypes have implicit dependencies on their
11161 * tables. However, for a composite type the implicit dependency goes
11162 * the other way in pg_depend; which is the right thing for DROP but
11163 * it doesn't produce the dependency ordering we need. So in that one
11164 * case, we reverse the direction of the dependency.
11166 if (deptype
== 'i' &&
11167 dobj
->objType
== DO_TABLE
&&
11168 refdobj
->objType
== DO_TYPE
)
11169 addObjectDependency(refdobj
, dobj
->dumpId
);
11172 addObjectDependency(dobj
, refdobj
->dumpId
);
11177 destroyPQExpBuffer(query
);
11182 * selectSourceSchema - make the specified schema the active search path
11183 * in the source database.
11185 * NB: pg_catalog is explicitly searched after the specified schema;
11186 * so user names are only qualified if they are cross-schema references,
11187 * and system names are only qualified if they conflict with a user name
11188 * in the current schema.
11190 * Whenever the selected schema is not pg_catalog, be careful to qualify
11191 * references to system catalogs and types in our emitted commands!
11194 selectSourceSchema(const char *schemaName
)
11196 static char *curSchemaName
= NULL
;
11199 /* Not relevant if fetching from pre-7.3 DB */
11200 if (g_fout
->remoteVersion
< 70300)
11202 /* Ignore null schema names */
11203 if (schemaName
== NULL
|| *schemaName
== '\0')
11205 /* Optimize away repeated selection of same schema */
11206 if (curSchemaName
&& strcmp(curSchemaName
, schemaName
) == 0)
11209 query
= createPQExpBuffer();
11210 appendPQExpBuffer(query
, "SET search_path = %s",
11211 fmtId(schemaName
));
11212 if (strcmp(schemaName
, "pg_catalog") != 0)
11213 appendPQExpBuffer(query
, ", pg_catalog");
11215 do_sql_command(g_conn
, query
->data
);
11217 destroyPQExpBuffer(query
);
11219 free(curSchemaName
);
11220 curSchemaName
= strdup(schemaName
);
11224 * getFormattedTypeName - retrieve a nicely-formatted type name for the
11227 * NB: in 7.3 and up the result may depend on the currently-selected
11228 * schema; this is why we don't try to cache the names.
11231 getFormattedTypeName(Oid oid
, OidOptions opts
)
11240 if ((opts
& zeroAsOpaque
) != 0)
11241 return strdup(g_opaque_type
);
11242 else if ((opts
& zeroAsAny
) != 0)
11243 return strdup("'any'");
11244 else if ((opts
& zeroAsStar
) != 0)
11245 return strdup("*");
11246 else if ((opts
& zeroAsNone
) != 0)
11247 return strdup("NONE");
11250 query
= createPQExpBuffer();
11251 if (g_fout
->remoteVersion
>= 70300)
11253 appendPQExpBuffer(query
, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11256 else if (g_fout
->remoteVersion
>= 70100)
11258 appendPQExpBuffer(query
, "SELECT format_type('%u'::oid, NULL)",
11263 appendPQExpBuffer(query
, "SELECT typname "
11265 "WHERE oid = '%u'::oid",
11269 res
= PQexec(g_conn
, query
->data
);
11270 check_sql_result(res
, g_conn
, query
->data
, PGRES_TUPLES_OK
);
11272 /* Expecting a single result only */
11273 ntups
= PQntuples(res
);
11276 write_msg(NULL
, ngettext("query returned %d row instead of one: %s\n",
11277 "query returned %d rows instead of one: %s\n",
11279 ntups
, query
->data
);
11283 if (g_fout
->remoteVersion
>= 70100)
11285 /* already quoted */
11286 result
= strdup(PQgetvalue(res
, 0, 0));
11290 /* may need to quote it */
11291 result
= strdup(fmtId(PQgetvalue(res
, 0, 0)));
11295 destroyPQExpBuffer(query
);
11301 * myFormatType --- local implementation of format_type for use with 7.0.
11304 myFormatType(const char *typname
, int32 typmod
)
11307 bool isarray
= false;
11308 PQExpBuffer buf
= createPQExpBuffer();
11310 /* Handle array types */
11311 if (typname
[0] == '_')
11317 /* Show lengths on bpchar and varchar */
11318 if (!strcmp(typname
, "bpchar"))
11320 int len
= (typmod
- VARHDRSZ
);
11322 appendPQExpBuffer(buf
, "character");
11324 appendPQExpBuffer(buf
, "(%d)",
11325 typmod
- VARHDRSZ
);
11327 else if (!strcmp(typname
, "varchar"))
11329 appendPQExpBuffer(buf
, "character varying");
11331 appendPQExpBuffer(buf
, "(%d)",
11332 typmod
- VARHDRSZ
);
11334 else if (!strcmp(typname
, "numeric"))
11336 appendPQExpBuffer(buf
, "numeric");
11343 tmp_typmod
= typmod
- VARHDRSZ
;
11344 precision
= (tmp_typmod
>> 16) & 0xffff;
11345 scale
= tmp_typmod
& 0xffff;
11346 appendPQExpBuffer(buf
, "(%d,%d)",
11352 * char is an internal single-byte data type; Let's make sure we force it
11353 * through with quotes. - thomas 1998-12-13
11355 else if (strcmp(typname
, "char") == 0)
11356 appendPQExpBuffer(buf
, "\"char\"");
11358 appendPQExpBuffer(buf
, "%s", fmtId(typname
));
11360 /* Append array qualifier for array types */
11362 appendPQExpBuffer(buf
, "[]");
11364 result
= strdup(buf
->data
);
11365 destroyPQExpBuffer(buf
);
11371 * fmtQualifiedId - convert a qualified name to the proper format for
11372 * the source database.
11374 * Like fmtId, use the result before calling again.
11376 static const char *
11377 fmtQualifiedId(const char *schema
, const char *id
)
11379 static PQExpBuffer id_return
= NULL
;
11381 if (id_return
) /* first time through? */
11382 resetPQExpBuffer(id_return
);
11384 id_return
= createPQExpBuffer();
11386 /* Suppress schema name if fetching from pre-7.3 DB */
11387 if (g_fout
->remoteVersion
>= 70300 && schema
&& *schema
)
11389 appendPQExpBuffer(id_return
, "%s.",
11392 appendPQExpBuffer(id_return
, "%s",
11395 return id_return
->data
;
11399 * Return a column list clause for the given relation.
11401 * Special case: if there are no undropped columns in the relation, return
11402 * "", not an invalid "()" column list.
11404 static const char *
11405 fmtCopyColumnList(const TableInfo
*ti
)
11407 static PQExpBuffer q
= NULL
;
11408 int numatts
= ti
->numatts
;
11409 char **attnames
= ti
->attnames
;
11410 bool *attisdropped
= ti
->attisdropped
;
11414 if (q
) /* first time through? */
11415 resetPQExpBuffer(q
);
11417 q
= createPQExpBuffer();
11419 appendPQExpBuffer(q
, "(");
11421 for (i
= 0; i
< numatts
; i
++)
11423 if (attisdropped
[i
])
11426 appendPQExpBuffer(q
, ", ");
11427 appendPQExpBuffer(q
, "%s", fmtId(attnames
[i
]));
11432 return ""; /* no undropped columns */
11434 appendPQExpBuffer(q
, ")");
11439 * Convenience subroutine to execute a SQL command and check for
11440 * COMMAND_OK status.
11443 do_sql_command(PGconn
*conn
, const char *query
)
11447 res
= PQexec(conn
, query
);
11448 check_sql_result(res
, conn
, query
, PGRES_COMMAND_OK
);
11453 * Convenience subroutine to verify a SQL command succeeded,
11454 * and exit with a useful error message if not.
11457 check_sql_result(PGresult
*res
, PGconn
*conn
, const char *query
,
11458 ExecStatusType expected
)
11462 if (res
&& PQresultStatus(res
) == expected
)
11465 write_msg(NULL
, "SQL command failed\n");
11467 err
= PQresultErrorMessage(res
);
11469 err
= PQerrorMessage(conn
);
11470 write_msg(NULL
, "Error message from server: %s", err
);
11471 write_msg(NULL
, "The command was: %s\n", query
);