X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fbin%2Fpg_dump%2Fpg_dump.c;h=c4602fd0bce09d66263521a24c0dd1d09d714372;hb=6563e9e2e8b15350e4cb99b86f2f7dec54722155;hp=ba15398c5fb195481899c0647d8b7b6602d51902;hpb=56f9ff72b23983699e5d5172a442699f4c34721b;p=pg-rex%2Fsyncrep.git diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index ba15398c5f..c4602fd0bc 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -4,7 +4,7 @@ * pg_dump is a utility for dumping out a postgres database * into a script file. * - * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * pg_dump will read the system catalogs in a database and dump out a @@ -12,20 +12,14 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.475 2007/11/08 10:37:54 petere Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.495 2008/07/16 16:55:23 tgl Exp $ * *------------------------------------------------------------------------- */ -/* - * Although this is not a backend module, we must include postgres.h anyway - * so that we can include a bunch of backend include files. pg_dump has - * never pretended to be very independent of the backend anyhow ... - */ -#include "postgres.h" +#include "postgres_fe.h" #include - #include #ifdef ENABLE_NLS #include @@ -40,12 +34,12 @@ int optreset; #endif -#include "access/htup.h" +#include "access/attnum.h" +#include "access/sysattr.h" #include "catalog/pg_class.h" #include "catalog/pg_proc.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" -#include "commands/sequence.h" #include "libpq/libpq-fs.h" #include "pg_backup_archiver.h" @@ -90,15 +84,15 @@ static Oid g_last_builtin_oid; /* value of the last builtin oid */ * The string lists record the patterns given by command-line switches, * which we then convert to lists of OIDs of matching objects. */ -static SimpleStringList schema_include_patterns = { NULL, NULL }; -static SimpleOidList schema_include_oids = { NULL, NULL }; -static SimpleStringList schema_exclude_patterns = { NULL, NULL }; -static SimpleOidList schema_exclude_oids = { NULL, NULL }; +static SimpleStringList schema_include_patterns = {NULL, NULL}; +static SimpleOidList schema_include_oids = {NULL, NULL}; +static SimpleStringList schema_exclude_patterns = {NULL, NULL}; +static SimpleOidList schema_exclude_oids = {NULL, NULL}; -static SimpleStringList table_include_patterns = { NULL, NULL }; -static SimpleOidList table_include_oids = { NULL, NULL }; -static SimpleStringList table_exclude_patterns = { NULL, NULL }; -static SimpleOidList table_exclude_oids = { NULL, NULL }; +static SimpleStringList table_include_patterns = {NULL, NULL}; +static SimpleOidList table_include_oids = {NULL, NULL}; +static SimpleStringList table_exclude_patterns = {NULL, NULL}; +static SimpleOidList table_exclude_oids = {NULL, NULL}; /* default, if no "inclusion" switches appear, is to dump everything */ static bool include_everything = true; @@ -121,11 +115,12 @@ static int disable_dollar_quoting = 0; static void help(const char *progname); static void expand_schema_name_patterns(SimpleStringList *patterns, - SimpleOidList *oids); + SimpleOidList *oids); static void expand_table_name_patterns(SimpleStringList *patterns, - SimpleOidList *oids); + SimpleOidList *oids); static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid); static void dumpTableData(Archive *fout, TableDataInfo *tdinfo); +static void guessConstraintInheritance(TableInfo *tblinfo, int numTables); static void dumpComment(Archive *fout, const char *target, const char *namespace, const char *owner, CatalogId catalogId, int subid, DumpId dumpId); @@ -217,18 +212,20 @@ main(int argc, char **argv) int i; bool force_password = false; int compressLevel = -1; - bool ignore_version = false; int plainText = 0; int outputClean = 0; int outputCreate = 0; bool outputBlobs = false; int outputNoOwner = 0; - static int use_setsessauth = 0; - static int disable_triggers = 0; char *outputSuperuser = NULL; - + int my_version; + int optindex; RestoreOptions *ropt; + static int disable_triggers = 0; + static int outputNoTablespaces = 0; + static int use_setsessauth = 0; + static struct option long_options[] = { {"data-only", no_argument, NULL, 'a'}, {"blobs", no_argument, NULL, 'b'}, @@ -266,11 +263,11 @@ main(int argc, char **argv) */ {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1}, {"disable-triggers", no_argument, &disable_triggers, 1}, + {"no-tablespaces", no_argument, &outputNoTablespaces, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {NULL, 0, NULL, 0} }; - int optindex; set_pglocale_pgservice(argv[0], "pg_dump"); @@ -302,7 +299,7 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:uU:vWxX:Z:", + while ((c = getopt_long(argc, argv, "abcCdDE:f:F:h:in:N:oOp:RsS:t:T:U:vWxX:Z:", long_options, &optindex)) != -1) { switch (c) @@ -349,8 +346,8 @@ main(int argc, char **argv) pghost = optarg; break; - case 'i': /* ignore database version mismatch */ - ignore_version = true; + case 'i': + /* ignored, deprecated option */ break; case 'n': /* include schema(s) */ @@ -395,11 +392,6 @@ main(int argc, char **argv) simple_string_list_append(&table_exclude_patterns, optarg); break; - case 'u': - force_password = true; - username = simple_prompt("User name: ", 100, true); - break; - case 'U': username = optarg; break; @@ -422,6 +414,8 @@ main(int argc, char **argv) disable_dollar_quoting = 1; else if (strcmp(optarg, "disable-triggers") == 0) disable_triggers = 1; + else if (strcmp(optarg, "no-tablespaces") == 0) + outputNoTablespaces = 1; else if (strcmp(optarg, "use-set-session-authorization") == 0) use_setsessauth = 1; else @@ -492,8 +486,8 @@ main(int argc, char **argv) else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0) { /* - * Dump files into the current directory; for demonstration only, not - * documented. + * Dump files into the current directory; for demonstration only, not + * documented. */ g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite); } @@ -519,20 +513,26 @@ main(int argc, char **argv) /* Let the archiver know how noisy to be */ g_fout->verbose = g_verbose; - g_fout->minRemoteVersion = 70000; /* we can handle back to 7.0 */ - g_fout->maxRemoteVersion = parse_version(PG_VERSION); - if (g_fout->maxRemoteVersion < 0) + my_version = parse_version(PG_VERSION); + if (my_version < 0) { write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION); exit(1); } /* + * We allow the server to be back to 7.0, and up to any minor release + * of our own major version. (See also version check in pg_dumpall.c.) + */ + g_fout->minRemoteVersion = 70000; + g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99; + + /* * Open the database using the Archiver, so it knows about it. Errors mean * death. */ g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, - username, force_password, ignore_version); + username, force_password); /* Set the client encoding if requested */ if (dumpencoding) @@ -558,6 +558,26 @@ main(int argc, char **argv) do_sql_command(g_conn, "SET DATESTYLE = ISO"); /* + * If supported, set extra_float_digits so that we can dump float data + * exactly (given correctly implemented float I/O code, anyway) + */ + if (g_fout->remoteVersion >= 70400) + do_sql_command(g_conn, "SET extra_float_digits TO 2"); + + /* + * If synchronized scanning is supported, disable it, to prevent + * unpredictable changes in row ordering across a dump and reload. + */ + if (g_fout->remoteVersion >= 80300) + do_sql_command(g_conn, "SET synchronize_seqscans TO off"); + + /* + * Disable timeouts if supported. + */ + if (g_fout->remoteVersion >= 70300) + do_sql_command(g_conn, "SET statement_timeout = 0"); + + /* * Start serializable transaction to dump consistent data. */ do_sql_command(g_conn, "BEGIN"); @@ -572,13 +592,6 @@ main(int argc, char **argv) else username_subquery = "SELECT usename FROM pg_user WHERE usesysid ="; - /* - * If supported, set extra_float_digits so that we can dump float data - * exactly (given correctly implemented float I/O code, anyway) - */ - if (g_fout->remoteVersion >= 70400) - do_sql_command(g_conn, "SET extra_float_digits TO 2"); - /* Find the last built-in OID, if needed */ if (g_fout->remoteVersion < 70300) { @@ -633,6 +646,9 @@ main(int argc, char **argv) */ tblinfo = getSchemaData(&numTables); + if (g_fout->remoteVersion < 80400) + guessConstraintInheritance(tblinfo, numTables); + if (!schemaOnly) getTableData(tblinfo, numTables, oids); @@ -706,6 +722,7 @@ main(int argc, char **argv) ropt->superuser = outputSuperuser; ropt->create = outputCreate; ropt->noOwner = outputNoOwner; + ropt->noTablespace = outputNoTablespaces; ropt->disable_triggers = disable_triggers; ropt->use_setsessauth = use_setsessauth; ropt->dataOnly = dataOnly; @@ -738,8 +755,6 @@ help(const char *progname) printf(_("\nGeneral options:\n")); printf(_(" -f, --file=FILENAME output file name\n")); printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n")); - printf(_(" -i, --ignore-version proceed even when server version mismatches\n" - " pg_dump version\n")); printf(_(" -v, --verbose verbose mode\n")); printf(_(" -Z, --compress=0-9 compression level for compressed formats\n")); printf(_(" --help show this help, then exit\n")); @@ -766,9 +781,10 @@ help(const char *progname) printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n")); printf(_(" --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n")); printf(_(" --disable-triggers disable triggers during data-only restore\n")); + printf(_(" --no-tablespaces do not dump tablespace assignments\n")); printf(_(" --use-set-session-authorization\n" " use SESSION AUTHORIZATION commands instead of\n" - " ALTER OWNER commands to set ownership\n")); + " ALTER OWNER commands to set ownership\n")); printf(_("\nConnection options:\n")); printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); @@ -870,7 +886,7 @@ expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids) appendPQExpBuffer(query, "SELECT c.oid" "\nFROM pg_catalog.pg_class c" - "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" + "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" "\nWHERE c.relkind in ('%c', '%c', '%c')\n", RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW); processSQLNamePattern(g_conn, query, cell->val, true, false, @@ -912,6 +928,7 @@ selectDumpableNamespace(NamespaceInfo *nsinfo) nsinfo->dobj.dump = false; else nsinfo->dobj.dump = true; + /* * In any case, a namespace can be excluded by an exclusion switch */ @@ -929,14 +946,15 @@ static void selectDumpableTable(TableInfo *tbinfo) { /* - * If specific tables are being dumped, dump just those tables; - * else, dump according to the parent namespace's dump flag. + * If specific tables are being dumped, dump just those tables; else, dump + * according to the parent namespace's dump flag. */ if (table_include_oids.head != NULL) tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids, tbinfo->dobj.catId.oid); else tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump; + /* * In any case, a table can be excluded by an exclusion switch */ @@ -1081,10 +1099,10 @@ dumpTableData_copy(Archive *fout, void *dcontext) * was too tight. Finally, the following was implemented: * * If throttle is non-zero, then - * See how long since the last sleep. + * See how long since the last sleep. * Work out how long to sleep (based on ratio). - * If sleep is more than 100ms, then - * sleep + * If sleep is more than 100ms, then + * sleep * reset timer * EndIf * EndIf @@ -1370,6 +1388,81 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) /* + * guessConstraintInheritance: + * In pre-8.4 databases, we can't tell for certain which constraints + * are inherited. We assume a CHECK constraint is inherited if its name + * matches the name of any constraint in the parent. Originally this code + * tried to compare the expression texts, but that can fail for various + * reasons --- for example, if the parent and child tables are in different + * schemas, reverse-listing of function calls may produce different text + * (schema-qualified or not) depending on search path. + * + * In 8.4 and up we can rely on the conislocal field to decide which + * constraints must be dumped; much safer. + * + * This function assumes all conislocal flags were initialized to TRUE. + * It clears the flag on anything that seems to be inherited. + */ +static void +guessConstraintInheritance(TableInfo *tblinfo, int numTables) +{ + int i, + j, + k; + + for (i = 0; i < numTables; i++) + { + TableInfo *tbinfo = &(tblinfo[i]); + int numParents; + TableInfo **parents; + TableInfo *parent; + + /* Sequences and views never have parents */ + if (tbinfo->relkind == RELKIND_SEQUENCE || + tbinfo->relkind == RELKIND_VIEW) + continue; + + /* Don't bother computing anything for non-target tables, either */ + if (!tbinfo->dobj.dump) + continue; + + numParents = tbinfo->numParents; + parents = tbinfo->parents; + + if (numParents == 0) + continue; /* nothing to see here, move along */ + + /* scan for inherited CHECK constraints */ + for (j = 0; j < tbinfo->ncheck; j++) + { + ConstraintInfo *constr; + + constr = &(tbinfo->checkexprs[j]); + + for (k = 0; k < numParents; k++) + { + int l; + + parent = parents[k]; + for (l = 0; l < parent->ncheck; l++) + { + ConstraintInfo *pconstr = &(parent->checkexprs[l]); + + if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0) + { + constr->conislocal = false; + break; + } + } + if (!constr->conislocal) + break; + } + } + } +} + + +/* * dumpDatabase: * dump the database definition */ @@ -1528,6 +1621,7 @@ dumpDatabase(Archive *AH) if (comment && strlen(comment)) { resetPQExpBuffer(dbQry); + /* Generates warning when loaded into a differently-named database.*/ appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname)); appendStringLiteralAH(dbQry, comment, AH); appendPQExpBuffer(dbQry, ";\n"); @@ -1984,10 +2078,10 @@ getTypes(int *numTypes) * * Note: as of 8.3 we can reliably detect whether a type is an * auto-generated array type by checking the element type's typarray. - * (Before that the test is capable of generating false positives.) - * We still check for name beginning with '_', though, so as to avoid - * the cost of the subselect probe for all standard types. This would - * have to be revisited if the backend ever allows renaming of array types. + * (Before that the test is capable of generating false positives.) We + * still check for name beginning with '_', though, so as to avoid the + * cost of the subselect probe for all standard types. This would have to + * be revisited if the backend ever allows renaming of array types. */ /* Make sure we are in proper schema */ @@ -3507,7 +3601,7 @@ getIndexes(TableInfo tblinfo[], int numTables) constrinfo[j].contype = contype; constrinfo[j].condef = NULL; constrinfo[j].conindex = indxinfo[j].dobj.dumpId; - constrinfo[j].coninherited = false; + constrinfo[j].conislocal = true; constrinfo[j].separate = true; indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId; @@ -3608,7 +3702,7 @@ getConstraints(TableInfo tblinfo[], int numTables) constrinfo[j].contype = 'f'; constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef)); constrinfo[j].conindex = 0; - constrinfo[j].coninherited = false; + constrinfo[j].conislocal = true; constrinfo[j].separate = true; } @@ -3691,7 +3785,7 @@ getDomainConstraints(TypeInfo *tinfo) constrinfo[i].contype = 'c'; constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc)); constrinfo[i].conindex = 0; - constrinfo[i].coninherited = false; + constrinfo[i].conislocal = true; constrinfo[i].separate = false; /* @@ -4571,10 +4665,22 @@ getTableAttrs(TableInfo *tblinfo, int numTables) tbinfo->dobj.name); resetPQExpBuffer(q); - if (g_fout->remoteVersion >= 70400) + if (g_fout->remoteVersion >= 80400) { appendPQExpBuffer(q, "SELECT tableoid, oid, conname, " - "pg_catalog.pg_get_constraintdef(oid) AS consrc " + "pg_catalog.pg_get_constraintdef(oid) AS consrc, " + "conislocal " + "FROM pg_catalog.pg_constraint " + "WHERE conrelid = '%u'::pg_catalog.oid " + " AND contype = 'c' " + "ORDER BY conname", + tbinfo->dobj.catId.oid); + } + else if (g_fout->remoteVersion >= 70400) + { + appendPQExpBuffer(q, "SELECT tableoid, oid, conname, " + "pg_catalog.pg_get_constraintdef(oid) AS consrc, " + "true as conislocal " "FROM pg_catalog.pg_constraint " "WHERE conrelid = '%u'::pg_catalog.oid " " AND contype = 'c' " @@ -4585,7 +4691,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) { /* no pg_get_constraintdef, must use consrc */ appendPQExpBuffer(q, "SELECT tableoid, oid, conname, " - "'CHECK (' || consrc || ')' AS consrc " + "'CHECK (' || consrc || ')' AS consrc, " + "true as conislocal " "FROM pg_catalog.pg_constraint " "WHERE conrelid = '%u'::pg_catalog.oid " " AND contype = 'c' " @@ -4597,7 +4704,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) /* 7.2 did not have OIDs in pg_relcheck */ appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, " "rcname AS conname, " - "'CHECK (' || rcsrc || ')' AS consrc " + "'CHECK (' || rcsrc || ')' AS consrc, " + "true as conislocal " "FROM pg_relcheck " "WHERE rcrelid = '%u'::oid " "ORDER BY rcname", @@ -4607,7 +4715,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) { appendPQExpBuffer(q, "SELECT tableoid, oid, " "rcname AS conname, " - "'CHECK (' || rcsrc || ')' AS consrc " + "'CHECK (' || rcsrc || ')' AS consrc, " + "true as conislocal " "FROM pg_relcheck " "WHERE rcrelid = '%u'::oid " "ORDER BY rcname", @@ -4619,7 +4728,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) appendPQExpBuffer(q, "SELECT " "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, " "oid, rcname AS conname, " - "'CHECK (' || rcsrc || ')' AS consrc " + "'CHECK (' || rcsrc || ')' AS consrc, " + "true as conislocal " "FROM pg_relcheck " "WHERE rcrelid = '%u'::oid " "ORDER BY rcname", @@ -4653,7 +4763,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) constrs[j].contype = 'c'; constrs[j].condef = strdup(PQgetvalue(res, j, 3)); constrs[j].conindex = 0; - constrs[j].coninherited = false; + constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't'); constrs[j].separate = false; constrs[j].dobj.dump = tbinfo->dobj.dump; @@ -4669,8 +4779,8 @@ getTableAttrs(TableInfo *tblinfo, int numTables) /* * If the constraint is inherited, this will be detected - * later. We also detect later if the constraint must be - * split out from the table definition. + * later (in pre-8.4 databases). We also detect later if the + * constraint must be split out from the table definition. */ } PQclear(res); @@ -4752,7 +4862,7 @@ getTSParsers(int *numTSParsers) AssignDumpId(&prsinfo[i].dobj); prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname)); prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)), - prsinfo[i].dobj.catId.oid); + prsinfo[i].dobj.catId.oid); prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart)); prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken)); prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend)); @@ -4833,7 +4943,7 @@ getTSDictionaries(int *numTSDicts) AssignDumpId(&dictinfo[i].dobj); dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname)); dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)), - dictinfo[i].dobj.catId.oid); + dictinfo[i].dobj.catId.oid); dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate)); if (PQgetisnull(res, i, i_dictinitoption)) @@ -4911,7 +5021,7 @@ getTSTemplates(int *numTSTemplates) AssignDumpId(&tmplinfo[i].dobj); tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname)); tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)), - tmplinfo[i].dobj.catId.oid); + tmplinfo[i].dobj.catId.oid); tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit)); tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize)); @@ -4986,7 +5096,7 @@ getTSConfigurations(int *numTSConfigs) AssignDumpId(&cfginfo[i].dobj); cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname)); cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)), - cfginfo[i].dobj.catId.oid); + cfginfo[i].dobj.catId.oid); cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser)); @@ -5506,8 +5616,9 @@ dumpEnumType(Archive *fout, TypeInfo *tinfo) PQExpBuffer delq = createPQExpBuffer(); PQExpBuffer query = createPQExpBuffer(); PGresult *res; - int num, i; - char *label; + int num, + i; + char *label; /* Set proper schema search path so regproc references list correctly */ selectSourceSchema(tinfo->dobj.namespace->dobj.name); @@ -5530,8 +5641,8 @@ dumpEnumType(Archive *fout, TypeInfo *tinfo) /* * DROP must be fully qualified in case same name appears in pg_catalog. - * CASCADE shouldn't be required here as for normal types since the - * I/O functions are generic and do not get dropped. + * CASCADE shouldn't be required here as for normal types since the I/O + * functions are generic and do not get dropped. */ appendPQExpBuffer(delq, "DROP TYPE %s.", fmtId(tinfo->dobj.namespace->dobj.name)); @@ -5543,8 +5654,8 @@ dumpEnumType(Archive *fout, TypeInfo *tinfo) { label = PQgetvalue(res, i, 0); if (i > 0) - appendPQExpBuffer(q, ",\n"); - appendPQExpBuffer(q, " "); + appendPQExpBuffer(q, ",\n"); + appendPQExpBuffer(q, " "); appendStringLiteralAH(q, label, fout); } appendPQExpBuffer(q, "\n);\n"); @@ -6324,15 +6435,18 @@ format_function_arguments(FuncInfo *finfo, int nallargs, { switch (argmodes[j][0]) { - case 'i': + case PROARGMODE_IN: argmode = ""; break; - case 'o': + case PROARGMODE_OUT: argmode = "OUT "; break; - case 'b': + case PROARGMODE_INOUT: argmode = "INOUT "; break; + case PROARGMODE_VARIADIC: + argmode = "VARIADIC "; + break; default: write_msg(NULL, "WARNING: bogus value in proargmodes array\n"); argmode = ""; @@ -6557,10 +6671,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo) lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname")); /* - * See backend/commands/define.c for details of how the 'AS' clause is - * used. + * See backend/commands/functioncmds.c for details of how the 'AS' clause + * is used. In 8.4 and up, an unused probin is NULL (here ""); previous + * versions would set it to "-". There are no known cases in which prosrc + * is unused, so the tests below for "-" are probably useless. */ - if (strcmp(probin, "-") != 0) + if (probin[0] != '\0' && strcmp(probin, "-") != 0) { appendPQExpBuffer(asPart, "AS "); appendStringLiteralAH(asPart, probin, fout); @@ -6664,14 +6780,12 @@ dumpFunc(Archive *fout, FuncInfo *finfo) rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque); appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig); - appendPQExpBuffer(q, "RETURNS %s%s\n %s\n LANGUAGE %s", + appendPQExpBuffer(q, "RETURNS %s%s", (proretset[0] == 't') ? "SETOF " : "", - rettypename, - asPart->data, - fmtId(lanname)); - + rettypename); free(rettypename); + appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname)); if (provolatile[0] != PROVOLATILE_VOLATILE) { if (provolatile[0] == PROVOLATILE_IMMUTABLE) @@ -6694,7 +6808,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) /* * COST and ROWS are emitted only if present and not default, so as not to - * break backwards-compatibility of the dump without need. Keep this code + * break backwards-compatibility of the dump without need. Keep this code * in sync with the defaults in functioncmds.c. */ if (strcmp(procost, "0") != 0) @@ -6729,7 +6843,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo) appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem)); /* - * Some GUC variable names are 'LIST' type and hence must not be quoted. + * Some GUC variable names are 'LIST' type and hence must not be + * quoted. */ if (pg_strcasecmp(configitem, "DateStyle") == 0 || pg_strcasecmp(configitem, "search_path") == 0) @@ -6738,7 +6853,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo) appendStringLiteralAH(q, pos, fout); } - appendPQExpBuffer(q, ";\n"); + appendPQExpBuffer(q, "\n %s;\n", asPart->data); ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId, funcsig_tag, @@ -7355,8 +7470,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) "nspname AS opcfamilynsp, " "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname " "FROM pg_catalog.pg_opclass c " - "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily " - "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace " + "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily " + "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace " "WHERE c.oid = '%u'::pg_catalog.oid", opcinfo->dobj.catId.oid); } @@ -7367,7 +7482,7 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) "opcdefault, " "NULL AS opcfamily, " "NULL AS opcfamilynsp, " - "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname " + "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname " "FROM pg_catalog.pg_opclass " "WHERE oid = '%u'::pg_catalog.oid", opcinfo->dobj.catId.oid); @@ -7445,18 +7560,38 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) */ resetPQExpBuffer(query); - if (g_fout->remoteVersion >= 80300) + if (g_fout->remoteVersion >= 80400) + { + /* + * Print only those opfamily members that are tied to the opclass by + * pg_depend entries. + * + * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping + * an older server's table in which it is used. Would it be better + * to silently ignore it? + */ + appendPQExpBuffer(query, "SELECT amopstrategy, false as amopreqcheck, " + "amopopr::pg_catalog.regoperator " + "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend " + "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " + "AND refobjid = '%u'::pg_catalog.oid " + "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass " + "AND objid = ao.oid " + "ORDER BY amopstrategy", + opcinfo->dobj.catId.oid); + } + else if (g_fout->remoteVersion >= 80300) { /* - * Print only those opfamily members that are tied to the opclass - * by pg_depend entries. + * Print only those opfamily members that are tied to the opclass by + * pg_depend entries. */ appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, " "amopopr::pg_catalog.regoperator " "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend " - "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " + "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " "AND refobjid = '%u'::pg_catalog.oid " - "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass " + "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass " "AND objid = ao.oid " "ORDER BY amopstrategy", opcinfo->dobj.catId.oid); @@ -7507,15 +7642,15 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo) if (g_fout->remoteVersion >= 80300) { /* - * Print only those opfamily members that are tied to the opclass - * by pg_depend entries. + * Print only those opfamily members that are tied to the opclass by + * pg_depend entries. */ appendPQExpBuffer(query, "SELECT amprocnum, " "amproc::pg_catalog.regprocedure " - "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend " - "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " + "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend " + "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " "AND refobjid = '%u'::pg_catalog.oid " - "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass " + "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass " "AND objid = ap.oid " "ORDER BY amprocnum", opcinfo->dobj.catId.oid); @@ -7623,8 +7758,8 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) * or functions, or (2) it contains an opclass with a different name or * owner. Otherwise it's sufficient to let it be created during creation * of the contained opclass, and not dumping it improves portability of - * the dump. Since we have to fetch the loose operators/funcs anyway, - * do that first. + * the dump. Since we have to fetch the loose operators/funcs anyway, do + * that first. */ query = createPQExpBuffer(); @@ -7635,18 +7770,38 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) selectSourceSchema(opfinfo->dobj.namespace->dobj.name); /* - * Fetch only those opfamily members that are tied directly to the opfamily - * by pg_depend entries. + * Fetch only those opfamily members that are tied directly to the + * opfamily by pg_depend entries. */ - appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, " + if (g_fout->remoteVersion >= 80400) + { + /* + * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping + * an older server's table in which it is used. Would it be better + * to silently ignore it? + */ + appendPQExpBuffer(query, "SELECT amopstrategy, false as amopreqcheck, " + "amopopr::pg_catalog.regoperator " + "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend " + "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " + "AND refobjid = '%u'::pg_catalog.oid " + "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass " + "AND objid = ao.oid " + "ORDER BY amopstrategy", + opfinfo->dobj.catId.oid); + } + else + { + appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, " "amopopr::pg_catalog.regoperator " "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend " - "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " + "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " "AND refobjid = '%u'::pg_catalog.oid " - "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass " + "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass " "AND objid = ao.oid " "ORDER BY amopstrategy", opfinfo->dobj.catId.oid); + } res_ops = PQexec(g_conn, query->data); check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK); @@ -7658,9 +7813,9 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) "amproclefttype::pg_catalog.regtype, " "amprocrighttype::pg_catalog.regtype " "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend " - "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " + "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " "AND refobjid = '%u'::pg_catalog.oid " - "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass " + "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass " "AND objid = ap.oid " "ORDER BY amprocnum", opfinfo->dobj.catId.oid); @@ -7676,9 +7831,9 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) appendPQExpBuffer(query, "SELECT 1 " "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend " "WHERE f.oid = '%u'::pg_catalog.oid " - "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " + "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass " "AND refobjid = f.oid " - "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " + "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass " "AND objid = c.oid " "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) " "LIMIT 1", @@ -7706,7 +7861,7 @@ dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo) resetPQExpBuffer(query); appendPQExpBuffer(query, "SELECT " - "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname " + "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname " "FROM pg_catalog.pg_opfamily " "WHERE oid = '%u'::pg_catalog.oid", opfinfo->dobj.catId.oid); @@ -8215,7 +8370,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo) * write out a single text search parser */ static void -dumpTSParser(Archive *fout, TSParserInfo * prsinfo) +dumpTSParser(Archive *fout, TSParserInfo *prsinfo) { PQExpBuffer q; PQExpBuffer delq; @@ -8279,7 +8434,7 @@ dumpTSParser(Archive *fout, TSParserInfo * prsinfo) * write out a single text search dictionary */ static void -dumpTSDictionary(Archive *fout, TSDictInfo * dictinfo) +dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo) { PQExpBuffer q; PQExpBuffer delq; @@ -8369,7 +8524,7 @@ dumpTSDictionary(Archive *fout, TSDictInfo * dictinfo) * write out a single text search template */ static void -dumpTSTemplate(Archive *fout, TSTemplateInfo * tmplinfo) +dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo) { PQExpBuffer q; PQExpBuffer delq; @@ -8427,7 +8582,7 @@ dumpTSTemplate(Archive *fout, TSTemplateInfo * tmplinfo) * write out a single text search configuration */ static void -dumpTSConfig(Archive *fout, TSConfigInfo * cfginfo) +dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo) { PQExpBuffer q; PQExpBuffer delq; @@ -8499,11 +8654,11 @@ dumpTSConfig(Archive *fout, TSConfigInfo * cfginfo) for (i = 0; i < ntups; i++) { - char *tokenname = PQgetvalue(res, i, i_tokenname); - char *dictname = PQgetvalue(res, i, i_dictname); + char *tokenname = PQgetvalue(res, i, i_tokenname); + char *dictname = PQgetvalue(res, i, i_dictname); if (i == 0 || - strcmp(tokenname, PQgetvalue(res, i-1, i_tokenname)) != 0) + strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0) { /* starting a new token type, so start a new command */ if (i > 0) @@ -8536,7 +8691,7 @@ dumpTSConfig(Archive *fout, TSConfigInfo * cfginfo) cfginfo->dobj.namespace->dobj.name, NULL, cfginfo->rolname, - false, "TEXT SEARCH CONFIGURATION", q->data, delq->data, NULL, + false, "TEXT SEARCH CONFIGURATION", q->data, delq->data, NULL, cfginfo->dobj.dependencies, cfginfo->dobj.nDeps, NULL, NULL); @@ -8783,7 +8938,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) { ConstraintInfo *constr = &(tbinfo->checkexprs[j]); - if (constr->coninherited || constr->separate) + if (constr->separate || !constr->conislocal) continue; if (actual_atts > 0) @@ -8898,7 +9053,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) { ConstraintInfo *constr = &(tbinfo->checkexprs[j]); - if (constr->coninherited || constr->separate) + if (constr->separate || !constr->conislocal) continue; dumpTableConstraintComment(fout, constr); @@ -9373,7 +9528,8 @@ static void dumpSequence(Archive *fout, TableInfo *tbinfo) { PGresult *res; - char *last, + char *startv, + *last, *incby, *maxv = NULL, *minv = NULL, @@ -9391,19 +9547,40 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE); snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE); - appendPQExpBuffer(query, - "SELECT sequence_name, last_value, increment_by, " - "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL " - " WHEN increment_by < 0 AND max_value = -1 THEN NULL " - " ELSE max_value " - "END AS max_value, " - "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL " - " WHEN increment_by < 0 AND min_value = %s THEN NULL " - " ELSE min_value " - "END AS min_value, " - "cache_value, is_cycled, is_called from %s", - bufx, bufm, - fmtId(tbinfo->dobj.name)); + if (g_fout->remoteVersion >= 80400) + { + appendPQExpBuffer(query, + "SELECT sequence_name, " + "start_value, last_value, increment_by, " + "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL " + " WHEN increment_by < 0 AND max_value = -1 THEN NULL " + " ELSE max_value " + "END AS max_value, " + "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL " + " WHEN increment_by < 0 AND min_value = %s THEN NULL " + " ELSE min_value " + "END AS min_value, " + "cache_value, is_cycled, is_called from %s", + bufx, bufm, + fmtId(tbinfo->dobj.name)); + } + else + { + appendPQExpBuffer(query, + "SELECT sequence_name, " + "0 as start_value, last_value, increment_by, " + "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL " + " WHEN increment_by < 0 AND max_value = -1 THEN NULL " + " ELSE max_value " + "END AS max_value, " + "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL " + " WHEN increment_by < 0 AND min_value = %s THEN NULL " + " ELSE min_value " + "END AS min_value, " + "cache_value, is_cycled, is_called from %s", + bufx, bufm, + fmtId(tbinfo->dobj.name)); + } res = PQexec(g_conn, query->data); check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); @@ -9425,23 +9602,24 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) } #endif - last = PQgetvalue(res, 0, 1); - incby = PQgetvalue(res, 0, 2); - if (!PQgetisnull(res, 0, 3)) - maxv = PQgetvalue(res, 0, 3); + startv = PQgetvalue(res, 0, 1); + last = PQgetvalue(res, 0, 2); + incby = PQgetvalue(res, 0, 3); if (!PQgetisnull(res, 0, 4)) - minv = PQgetvalue(res, 0, 4); - cache = PQgetvalue(res, 0, 5); - cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0); - called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0); + maxv = PQgetvalue(res, 0, 4); + if (!PQgetisnull(res, 0, 5)) + minv = PQgetvalue(res, 0, 5); + cache = PQgetvalue(res, 0, 6); + cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0); + called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0); /* * The logic we use for restoring sequences is as follows: * * Add a CREATE SEQUENCE statement as part of a "schema" dump (use * last_val for start if called is false, else use min_val for start_val). - * Also, if the sequence is owned by a column, add an ALTER SEQUENCE - * OWNED BY command for it. + * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED + * BY command for it. * * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump. */ @@ -9463,8 +9641,18 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) "CREATE SEQUENCE %s\n", fmtId(tbinfo->dobj.name)); - if (!called) - appendPQExpBuffer(query, " START WITH %s\n", last); + if (g_fout->remoteVersion >= 80400) + appendPQExpBuffer(query, " START WITH %s\n", startv); + else + { + /* + * Versions before 8.4 did not remember the true start value. If + * is_called is false then the sequence has never been incremented + * so we can use last_val. Otherwise punt and let it default. + */ + if (!called) + appendPQExpBuffer(query, " START WITH %s\n", last); + } appendPQExpBuffer(query, " INCREMENT BY %s\n", incby); @@ -9625,6 +9813,13 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo) else appendPQExpBuffer(query, " UPDATE"); } + if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype)) + { + if (findx > 0) + appendPQExpBuffer(query, " OR TRUNCATE"); + else + appendPQExpBuffer(query, " TRUNCATE"); + } appendPQExpBuffer(query, " ON %s\n", fmtId(tbinfo->dobj.name)); @@ -9818,28 +10013,28 @@ dumpRule(Archive *fout, RuleInfo *rinfo) printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0)); /* - * Add the command to alter the rules replication firing semantics - * if it differs from the default. + * Add the command to alter the rules replication firing semantics if it + * differs from the default. */ if (rinfo->ev_enabled != 'O') { appendPQExpBuffer(cmd, "ALTER TABLE %s.", - fmtId(tbinfo->dobj.namespace->dobj.name)); + fmtId(tbinfo->dobj.namespace->dobj.name)); appendPQExpBuffer(cmd, "%s ", - fmtId(tbinfo->dobj.name)); + fmtId(tbinfo->dobj.name)); switch (rinfo->ev_enabled) { case 'A': appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n", - fmtId(rinfo->dobj.name)); + fmtId(rinfo->dobj.name)); break; case 'R': appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n", - fmtId(rinfo->dobj.name)); + fmtId(rinfo->dobj.name)); break; case 'D': appendPQExpBuffer(cmd, "DISABLE RULE %s;\n", - fmtId(rinfo->dobj.name)); + fmtId(rinfo->dobj.name)); break; } }