From 92bec9a0bc459c13b546ef0e601d43311ea2b8dd Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
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
-- 
GitLab