>From f722fee00a97ff1a7b4246176478fd97d360b716 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 26 Aug 2013 21:58:22 +0300
Subject: [PATCH 1/3] Divorce pg_dump -E option from PGCLIENTENCODING.

-E option now means the encoding to use in the dump output, and
PGCLIENTENCODING specifies what encoding object names given on the command
line options are in.
---
 doc/src/sgml/ref/pg_dump.sgml |   20 +++++++--
 src/bin/pg_dump/pg_dump.c     |   99 ++++++++++++++++++++++++++++-------------
 2 files changed, 84 insertions(+), 35 deletions(-)

diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml
index 1ed5e4f..007bace 100644
--- a/doc/src/sgml/ref/pg_dump.sgml
+++ b/doc/src/sgml/ref/pg_dump.sgml
@@ -184,10 +184,24 @@ PostgreSQL documentation
       <listitem>
        <para>
         Create the dump in the specified character set encoding. By default,
-        the dump is created in the database encoding.  (Another way to get the
-        same result is to set the <envar>PGCLIENTENCODING</envar> environment
-        variable to the desired dump encoding.)
+        the dump is created in the database encoding.
        </para>
+
+       <note>
+        <para>
+        -E only affects the encoding used for the output. The client encoding
+        used to interpret any object names given on the command line is
+        determined by the <envar>PGCLIENTENCODING</envar> environment
+        variable.
+        </para>
+
+        <para>
+        Before <productname>PostgreSQL</productname> 9.3 setting
+        <envar>PGCLIENTENCODING</envar> had the same effect as the -E
+        option, and command-line options were always interpreted in the same
+        encoding as used in the output.
+        </para>
+       </note>
       </listitem>
      </varlistentry>
 
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index e1ef55f..2b41e00 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -143,8 +143,8 @@ static int	serializable_deferrable = 0;
 
 
 static void help(const char *progname);
-static void setup_connection(Archive *AH, const char *dumpencoding,
-				 char *use_role);
+static void setup_connection(Archive *AH, char *use_role);
+static void setup_dump_encoding(Archive *AH, const char *dumpencoding);
 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
 static void expand_schema_name_patterns(Archive *fout,
 							SimpleStringList *patterns,
@@ -635,7 +635,19 @@ main(int argc, char **argv)
 	 * death.
 	 */
 	ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
-	setup_connection(fout, dumpencoding, use_role);
+	setup_connection(fout, use_role);
+	/*
+	 * Note that client_encoding is not set to the dump's output encoding,
+	 * specified by -E, yet. We must expand the table/schema names given on
+	 * the command line before we do that, because the command line arguments
+	 * are assumed to *not* be in the encoding specified by the -E option, but
+	 * whatever PGCLIENTENCODING is set to.
+	 *
+	 * Further note that the queries we run before setup_dump_encoding() is
+	 * called must not return any strings that would be included in the dump,
+	 * because they would be returned in different encoding than the dump.
+	 * Oids are OK.
+	 */
 
 	/*
 	 * Disable security label support if server version < v9.1.x (prevents
@@ -720,6 +732,14 @@ main(int argc, char **argv)
 	/* non-matching exclusion patterns aren't an error */
 
 	/*
+	 * We're now done with the queries using the table/schema names passed on
+	 * the command-line, which are assumed to be in the client's true encoding
+	 * (ie. PGCLIENTENCODING, not the encoding specified by -E). Switch
+	 * client_encoding to the encoding to be used in the dump output.
+	 */
+	setup_dump_encoding(fout, dumpencoding);
+
+	/*
 	 * Dumping blobs is now default unless we saw an inclusion switch or -s
 	 * ... but even if we did see one of these, -b turns it back on.
 	 */
@@ -915,37 +935,17 @@ help(const char *progname)
 	printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
 
+/*
+ * Sets connection options that affect the dump output.
+ *
+ * Note: This does not set client_encoding. Call setup_dump_encoding() to set
+ * that, after running any queries that need to be run in in the clienẗ́'s real
+ * encoding.
+ */
 static void
-setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
+setup_connection(Archive *AH, char *use_role)
 {
 	PGconn	   *conn = GetConnection(AH);
-	const char *std_strings;
-
-	/*
-	 * Set the client encoding if requested. If dumpencoding == NULL then
-	 * either it hasn't been requested or we're a cloned connection and then
-	 * this has already been set in CloneArchive according to the original
-	 * connection encoding.
-	 */
-	if (dumpencoding)
-	{
-		if (PQsetClientEncoding(conn, dumpencoding) < 0)
-			exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
-						  dumpencoding);
-	}
-
-	/*
-	 * Get the active encoding and the standard_conforming_strings setting, so
-	 * we know how to escape strings.
-	 */
-	AH->encoding = PQclientEncoding(conn);
-
-	std_strings = PQparameterStatus(conn, "standard_conforming_strings");
-	AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
-
-	/* Set the role if requested */
-	if (!use_role && AH->use_role)
-		use_role = AH->use_role;
 
 	/* Set the role if requested */
 	if (use_role && AH->remoteVersion >= 80100)
@@ -1042,10 +1042,45 @@ setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
 	}
 }
 
+/*
+ * Sets client_encoding to the encoding the dump should be output in.
+ */
+static void
+setup_dump_encoding(Archive *AH, const char *dumpencoding)
+{
+	PGconn	   *conn = GetConnection(AH);
+	const char *std_strings;
+
+	/*
+	 * If dumpenecoding is not specified, default to the server encoding.
+	 */
+	if (!dumpencoding)
+		dumpencoding = PQparameterStatus(conn, "server_encoding");
+	if (dumpencoding)
+	{
+		if (PQsetClientEncoding(conn, dumpencoding) < 0)
+		{
+			exit_horribly(NULL, "invalid dump encoding \"%s\" specified: %s\n",
+						  dumpencoding,
+						  PQerrorMessage(conn));
+		}
+	}
+
+	/*
+	 * Get the active encoding and the standard_conforming_strings setting, so
+	 * we know how to escape strings.
+	 */
+	AH->encoding = PQclientEncoding(conn);
+
+	std_strings = PQparameterStatus(conn, "standard_conforming_strings");
+	AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
+}
+
 static void
 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
 {
-	setup_connection(AHX, NULL, NULL);
+	setup_connection(AHX, AHX->use_role);
+	setup_dump_encoding(AHX, pg_encoding_to_char(AHX->encoding));
 }
 
 static char *
-- 
1.7.10.4

