Index: src/bin/psql/mainloop.c
===================================================================
--- src/bin/psql/mainloop.c	(HEAD)
+++ src/bin/psql/mainloop.c	(working copy)
Index: src/bin/psql/mainloop.c
@@ -13,8 +13,33 @@
 #include "common.h"
 #include "input.h"
 #include "settings.h"
+#include "mb/pg_wchar.h"
 
 
+static bool
+is_valid_encoding(int expected_encoding, const char *str)
+{
+	const char * s;
+
+	if (expected_encoding == PG_SQL_ASCII)
+		return true;	/* always accepted */
+
+	if (expected_encoding == pset.encoding)
+		return true;	/* matched */
+
+	for (s = str; *s; s++)
+	{
+		if (IS_HIGHBIT_SET(*s))
+		{
+			psql_error("explicit encoding is required: %s expected\n",
+							pg_encoding_to_char(expected_encoding));
+			return false;
+		}
+	}
+
+	return true;	/* accepted because all characters are in ascii */
+}
+
 /*
  * Main processing loop for reading lines of input
  *	and sending them to the backend.
@@ -36,6 +61,7 @@
 	int			added_nl_pos;
 	bool		success;
 	bool		line_saved_in_history;
+	int			expected_encoding = PG_SQL_ASCII;
 	volatile int successResult = EXIT_SUCCESS;
 	volatile backslashResult slashCmdStatus = PSQL_CMD_UNKNOWN;
 	volatile promptStatus_t prompt_status = PROMPT_READY;
@@ -134,8 +160,17 @@
 		else
 		{
 			line = gets_fromFile(source);
-			if (!line && ferror(source))
-				successResult = EXIT_FAILURE;
+			if (!line)
+			{
+				if (ferror(source))
+					successResult = EXIT_FAILURE;
+			}
+			else if (pset.lineno == 0 && strncmp(line, "\xef\xbb\xbf", 3) == 0)
+			{
+				/* trim BOM sequence to whitespaces */
+				memmove(line, line + 3, strlen(line + 3) + 1);
+				expected_encoding = PG_UTF8;
+			}
 		}
 
 		/*
@@ -248,7 +283,8 @@
 				}
 
 				/* execute query */
-				success = SendQuery(query_buf->data);
+				success = is_valid_encoding(expected_encoding, query_buf->data) &&
+						  SendQuery(query_buf->data);
 				slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
 
 				/* transfer query to previous_buf by pointer-swapping */
@@ -266,6 +302,7 @@
 			else if (scan_result == PSCAN_BACKSLASH)
 			{
 				/* handle backslash command */
+				PQExpBuffer	buf;
 
 				/*
 				 * If we added a newline to query_buf, and nothing else has
@@ -292,9 +329,11 @@
 				}
 
 				/* execute backslash command */
-				slashCmdStatus = HandleSlashCmds(scan_state,
-												 query_buf->len > 0 ?
-												 query_buf : previous_buf);
+				buf = query_buf->len > 0 ? query_buf : previous_buf;
+				if (is_valid_encoding(expected_encoding, buf->data))
+					slashCmdStatus = HandleSlashCmds(scan_state, buf);
+				else
+					slashCmdStatus = PSQL_CMD_ERROR;
 
 				success = slashCmdStatus != PSQL_CMD_ERROR;
 
@@ -378,7 +417,8 @@
 			pg_send_history(history_buf);
 
 		/* execute query */
-		success = SendQuery(query_buf->data);
+		success = is_valid_encoding(expected_encoding, query_buf->data) &&
+				  SendQuery(query_buf->data);
 
 		if (!success && die_on_error)
 			successResult = EXIT_USER;
