From 92bec9a0bc459c13b546ef0e601d43311ea2b8dd Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 24 Feb 2004 03:35:19 +0000 Subject: [PATCH] Cause pg_dump to emit a 'SET client_encoding' command at the start of any restore operation, thereby ensuring that dumped data is interpreted the same way it was dumped even if the target database has a different encoding. Per suggestions from Pavel Stehule and others. Also, simplify scheme for handling check_function_bodies ... we may as well just set that at the head of the script. --- src/bin/pg_dump/pg_backup_archiver.c | 50 ++++++++++++++++++++------ src/bin/pg_dump/pg_backup_archiver.h | 3 +- src/bin/pg_dump/pg_dump.c | 54 +++++++++++++++++++++++++--- 3 files changed, 91 insertions(+), 16 deletions(-) diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index c77382d613e..c5d917267d6 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.82 2004/01/04 04:02:15 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.83 2004/02/24 03:35:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt, const int compression, ArchiveMode mode); static int _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData); +static void _doSetFixedOutputState(ArchiveHandle *AH); static void _doSetSessionAuth(ArchiveHandle *AH, const char *user); static void _reconnectToDB(ArchiveHandle *AH, const char *dbname, const char *user); static void _becomeUser(ArchiveHandle *AH, const char *user); @@ -200,6 +201,11 @@ RestoreArchive(Archive *AHX, RestoreOptions *ropt) ahprintf(AH, "--\n-- PostgreSQL database dump\n--\n\n"); + /* + * Establish important parameter values right away. + */ + _doSetFixedOutputState(AH); + /* * Drop the items at the start, in reverse order */ @@ -1568,7 +1574,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt, AH->currUser = strdup(""); /* So it's valid, but we can free() it * later if necessary */ AH->currSchema = strdup(""); /* ditto */ - AH->chk_fn_bodies = true; /* assumed default state */ AH->toc = (TocEntry *) calloc(1, sizeof(TocEntry)); if (!AH->toc) @@ -1826,6 +1831,10 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt) { teReqs res = 3; /* Schema = 1, Data = 2, Both = 3 */ + /* ENCODING objects are dumped specially, so always reject here */ + if (strcmp(te->desc, "ENCODING") == 0) + return 0; + /* If it's an ACL, maybe ignore it */ if (ropt->aclsSkip && strcmp(te->desc, "ACL") == 0) return 0; @@ -1910,6 +1919,33 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt) return res; } +/* + * Issue SET commands for parameters that we want to have set the same way + * at all times during execution of a restore script. + */ +static void +_doSetFixedOutputState(ArchiveHandle *AH) +{ + TocEntry *te; + + /* If we have an encoding setting, emit that */ + te = AH->toc->next; + while (te != AH->toc) + { + if (strcmp(te->desc, "ENCODING") == 0) + { + ahprintf(AH, "%s", te->defn); + break; + } + te = te->next; + } + + /* Make sure function checking is disabled */ + ahprintf(AH, "SET check_function_bodies = false;\n"); + + ahprintf(AH, "\n"); +} + /* * Issue a SET SESSION AUTHORIZATION command. Caller is responsible * for updating state if appropriate. If user is NULL or an empty string, @@ -1991,7 +2027,8 @@ _reconnectToDB(ArchiveHandle *AH, const char *dbname, const char *user) free(AH->currSchema); AH->currSchema = strdup(""); - AH->chk_fn_bodies = true; /* assumed default state */ + /* re-establish fixed state */ + _doSetFixedOutputState(AH); } /* @@ -2087,13 +2124,6 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat _becomeOwner(AH, te); _selectOutputSchema(AH, te->namespace); - /* If it's a function, make sure function checking is disabled */ - if (AH->chk_fn_bodies && strcmp(te->desc, "FUNCTION") == 0) - { - ahprintf(AH, "SET check_function_bodies = false;\n\n"); - AH->chk_fn_bodies = false; - } - if (isData) pfx = "Data for "; else diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h index 4809989a196..5e9d69f5206 100644 --- a/src/bin/pg_dump/pg_backup_archiver.h +++ b/src/bin/pg_dump/pg_backup_archiver.h @@ -17,7 +17,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.55 2003/12/08 16:39:05 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.56 2004/02/24 03:35:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -245,7 +245,6 @@ typedef struct _archiveHandle /* these vars track state to avoid sending redundant SET commands */ char *currUser; /* current username */ char *currSchema; /* current schema */ - bool chk_fn_bodies; /* current state of check_function_bodies */ void *lo_buf; size_t lo_buf_used; diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 096a175dc70..15e1b2bd010 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.364 2004/02/12 23:41:03 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.365 2004/02/24 03:35:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -148,6 +148,7 @@ static char *myFormatType(const char *typname, int32 typmod); static const char *fmtQualifiedId(const char *schema, const char *id); static int dumpBlobs(Archive *AH, void *arg); static void dumpDatabase(Archive *AH); +static void dumpEncoding(Archive *AH); static const char *getAttrName(int attrnum, TableInfo *tblInfo); static const char *fmtCopyColumnList(const TableInfo *ti); static void do_sql_command(PGconn *conn, const char *query); @@ -561,11 +562,14 @@ main(int argc, char **argv) * in a safe order. */ - /* The database item is always first. */ + /* First the special encoding entry. */ + dumpEncoding(g_fout); + + /* The database item is always second. */ if (!dataOnly) dumpDatabase(g_fout); - /* Max OID is second. */ + /* Max OID is next. */ if (oids == true) setMaxOid(g_fout); @@ -575,7 +579,7 @@ main(int argc, char **argv) dumpDumpableObject(g_fout, dobjs[i]); } - /* BLOBs are always last. */ + /* BLOBs are always last (XXX is this right?) */ if (outputBlobs) ArchiveEntry(g_fout, nilCatalogId, createDumpId(), "BLOBS", NULL, "", @@ -1246,6 +1250,48 @@ dumpDatabase(Archive *AH) } +/* + * dumpEncoding: put the correct encoding into the archive + */ +static void +dumpEncoding(Archive *AH) +{ + PQExpBuffer qry; + PGresult *res; + + /* Can't read the encoding from pre-7.3 servers (SHOW isn't a query) */ + if (AH->remoteVersion < 70300) + return; + + if (g_verbose) + write_msg(NULL, "saving encoding\n"); + + qry = createPQExpBuffer(); + + appendPQExpBuffer(qry, "SHOW client_encoding"); + + res = PQexec(g_conn, qry->data); + + check_sql_result(res, g_conn, qry->data, PGRES_TUPLES_OK); + + resetPQExpBuffer(qry); + + appendPQExpBuffer(qry, "SET client_encoding = "); + appendStringLiteral(qry, PQgetvalue(res, 0, 0), true); + appendPQExpBuffer(qry, ";\n"); + + ArchiveEntry(AH, nilCatalogId, createDumpId(), + "ENCODING", NULL, "", + "ENCODING", qry->data, "", NULL, + NULL, 0, + NULL, NULL); + + PQclear(res); + + destroyPQExpBuffer(qry); +} + + /* * dumpBlobs: * dump all blobs