Cause pg_dump to emit a 'SET client_encoding' command at the start of
authorTom Lane
Tue, 24 Feb 2004 03:35:19 +0000 (03:35 +0000)
committerTom Lane
Tue, 24 Feb 2004 03:35:19 +0000 (03:35 +0000)
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
src/bin/pg_dump/pg_backup_archiver.h
src/bin/pg_dump/pg_dump.c

index c77382d613e3fd583fdac5706a0f0efb499aee69..c5d917267d6cb0ec32488726ec33760c3f0972a4 100644 (file)
@@ -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
index 4809989a196e3e09b8bb78a68cf6539f8fe05b1f..5e9d69f5206e698cab7e883b448f3a9d38011264 100644 (file)
@@ -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;
index 096a175dc702900982d55427de7ad27e7612397f..15e1b2bd01057128e1e5ce9acd5cb6679756efe8 100644 (file)
@@ -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