diff --git a/doc/src/sgml/ref/postgres-ref.sgml b/doc/src/sgml/ref/postgres-ref.sgml
index e2e9909242814c6253a9c687be2f50d558b5f1fa..d60d4ffbfcca844fd29800abb810d77b5caf3bb6 100644
--- a/doc/src/sgml/ref/postgres-ref.sgml
+++ b/doc/src/sgml/ref/postgres-ref.sgml
@@ -529,7 +529,9 @@ PostgreSQL documentation
     </indexterm>
 
     <para>
-     The following options only apply to the single-user mode.
+     The following options only apply to the single-user mode
+     (see <xref linkend="app-postgres-single-user"
+     endterm="app-postgres-single-user-title">).
     </para>
 
     <variablelist>
@@ -558,7 +560,7 @@ PostgreSQL documentation
       <term><option>-E</option></term>
       <listitem>
        <para>
-        Echo all commands.
+        Echo all commands to standard output before executing them.
        </para>
       </listitem>
      </varlistentry>
@@ -567,7 +569,8 @@ PostgreSQL documentation
       <term><option>-j</option></term>
       <listitem>
        <para>
-        Disables use of newline as a statement delimiter.
+        Use semicolon followed by two newlines, rather than just newline,
+        as the command entry terminator.
        </para>
       </listitem>
      </varlistentry>
@@ -760,8 +763,8 @@ PostgreSQL documentation
   </para>
  </refsect1>
 
- <refsect1>
-  <title>Usage</title>
+ <refsect1 id="app-postgres-single-user">
+  <title id="app-postgres-single-user-title">Single-User Mode</title>
 
    <para>
     To start a single-user mode server, use a command like
@@ -778,30 +781,40 @@ PostgreSQL documentation
     entry terminator; there is no intelligence about semicolons,
     as there is in <application>psql</>.  To continue a command
     across multiple lines, you must type backslash just before each
-    newline except the last one.
+    newline except the last one.  The backslash and adjacent newline are
+    both dropped from the input command.  Note that this will happen even
+    when within a string literal or comment.
    </para>
 
    <para>
-    But if you use the <option>-j</> command line switch, then newline does
-    not terminate command entry.  In this case, the server will read the standard input
-    until the end-of-file (<acronym>EOF</>) marker, then
-    process the input as a single command string.  Backslash-newline is not
-    treated specially in this case.
+    But if you use the <option>-j</> command line switch, a single newline
+    does not terminate command entry; instead, the sequence
+    semicolon-newline-newline does.  That is, type a semicolon immediately
+    followed by a completely empty line.  Backslash-newline is not
+    treated specially in this mode.  Again, there is no intelligence about
+    such a sequence appearing within a string literal or comment.
+   </para>
+
+   <para>
+    In either input mode, if you type a semicolon that is not just before or
+    part of a command entry terminator, it is considered a command separator.
+    When you do type a command entry terminator, the multiple statements
+    you've entered will be executed as a single transaction.
    </para>
 
    <para>
     To quit the session, type <acronym>EOF</acronym>
     (<keycombo action="simul"><keycap>Control</><keycap>D</></>, usually).
-    If you've
-    used <option>-j</>, two consecutive <acronym>EOF</>s are needed to exit.
+    If you've entered any text since the last command entry terminator,
+    then <acronym>EOF</acronym> will be taken as a command entry terminator,
+    and another <acronym>EOF</> will be needed to exit.
    </para>
 
    <para>
     Note that the single-user mode server does not provide sophisticated
     line-editing features (no command history, for example).
-    Single-User mode also does not do any background processing, like
-    automatic checkpoints.
-
+    Single-user mode also does not do any background processing, such as
+    automatic checkpoints or replication.
    </para>
  </refsect1>
 
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 6e1b241956a5fa2575a2af6e5794f1aff158dfa5..22398598734816bf339c2dc0c3f0a78d03f56966 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -5,6 +5,14 @@
  * Copyright (c) 2003-2015, PostgreSQL Global Development Group
  *
  * src/backend/catalog/information_schema.sql
+ *
+ * Note: this file is read in single-user -j mode, which means that the
+ * command terminator is semicolon-newline-newline; whenever the backend
+ * sees that, it stops and executes what it's got.  If you write a lot of
+ * statements without empty lines between, they'll all get quoted to you
+ * in any error message about one of them, so don't do that.  Also, you
+ * cannot write a semicolon immediately followed by an empty line in a
+ * string literal (including a function body!) or a multiline comment.
  */
 
 /*
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index ccc030fd7fb9956a37b7387d1808ce8620a3f62a..536c805598b4c92b3d414fda2cd509091f323191 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -4,6 +4,14 @@
  * Copyright (c) 1996-2015, PostgreSQL Global Development Group
  *
  * src/backend/catalog/system_views.sql
+ *
+ * Note: this file is read in single-user -j mode, which means that the
+ * command terminator is semicolon-newline-newline; whenever the backend
+ * sees that, it stops and executes what it's got.  If you write a lot of
+ * statements without empty lines between, they'll all get quoted to you
+ * in any error message about one of them, so don't do that.  Also, you
+ * cannot write a semicolon immediately followed by an empty line in a
+ * string literal (including a function body!) or a multiline comment.
  */
 
 CREATE VIEW pg_roles AS
diff --git a/src/backend/snowball/snowball.sql.in b/src/backend/snowball/snowball.sql.in
index 2f68393ab5bb732dfc5ddf740eb1a8d9bf3740c1..68363f11a51380762fca22643daf7a34c14cc06d 100644
--- a/src/backend/snowball/snowball.sql.in
+++ b/src/backend/snowball/snowball.sql.in
@@ -1,6 +1,22 @@
--- src/backend/snowball/snowball.sql.in$
+/*
+ * text search configuration for _LANGNAME_ language
+ *
+ * Copyright (c) 2007-2015, PostgreSQL Global Development Group
+ *
+ * src/backend/snowball/snowball.sql.in
+ *
+ * _LANGNAME_ and certain other macros are replaced for each language;
+ * see the Makefile for details.
+ *
+ * Note: this file is read in single-user -j mode, which means that the
+ * command terminator is semicolon-newline-newline; whenever the backend
+ * sees that, it stops and executes what it's got.  If you write a lot of
+ * statements without empty lines between, they'll all get quoted to you
+ * in any error message about one of them, so don't do that.  Also, you
+ * cannot write a semicolon immediately followed by an empty line in a
+ * string literal (including a function body!) or a multiline comment.
+ */
 
--- text search configuration for _LANGNAME_ language
 CREATE TEXT SEARCH DICTIONARY _DICTNAME_
 	(TEMPLATE = snowball, Language = _LANGNAME_ _STOPWORDS_);
 
diff --git a/src/backend/snowball/snowball_func.sql.in b/src/backend/snowball/snowball_func.sql.in
index e7d45109b4e1a1122745e7c31537f138fad178c6..debb0e00e4e3ba963396f2b67f21326520cc692a 100644
--- a/src/backend/snowball/snowball_func.sql.in
+++ b/src/backend/snowball/snowball_func.sql.in
@@ -1,4 +1,21 @@
--- src/backend/snowball/snowball_func.sql.in$
+/*
+ * Create underlying C functions for Snowball stemmers
+ *
+ * Copyright (c) 2007-2015, PostgreSQL Global Development Group
+ *
+ * src/backend/snowball/snowball_func.sql.in
+ *
+ * This file is combined with multiple instances of snowball.sql.in to
+ * build snowball_create.sql, which is executed during initdb.
+ *
+ * Note: this file is read in single-user -j mode, which means that the
+ * command terminator is semicolon-newline-newline; whenever the backend
+ * sees that, it stops and executes what it's got.  If you write a lot of
+ * statements without empty lines between, they'll all get quoted to you
+ * in any error message about one of them, so don't do that.  Also, you
+ * cannot write a semicolon immediately followed by an empty line in a
+ * string literal (including a function body!) or a multiline comment.
+ */
 
 SET search_path = pg_catalog;
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1dc2eb0fcca3c87d1f424ef71592c5cf1045f89c..4ae25487ef4469bb81bb0587062ef90144a46312 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -157,18 +157,8 @@ static CachedPlanSource *unnamed_stmt_psrc = NULL;
 
 /* assorted command-line switches */
 static const char *userDoption = NULL;	/* -D switch */
-
 static bool EchoQuery = false;	/* -E switch */
-
-/*
- * people who want to use EOF should #define DONTUSENEWLINE in
- * tcop/tcopdebug.h
- */
-#ifndef TCOP_DONTUSENEWLINE
-static int	UseNewLine = 1;		/* Use newlines query delimiters (the default) */
-#else
-static int	UseNewLine = 0;		/* Use EOF as query delimiters */
-#endif   /* TCOP_DONTUSENEWLINE */
+static bool UseSemiNewlineNewline = false;		/* -j switch */
 
 /* whether or not, and why, we were canceled by conflict with recovery */
 static bool RecoveryConflictPending = false;
@@ -219,8 +209,6 @@ static int
 InteractiveBackend(StringInfo inBuf)
 {
 	int			c;				/* character read from getc() */
-	bool		end = false;	/* end-of-input flag */
-	bool		backslashSeen = false;	/* have we seen a \ ? */
 
 	/*
 	 * display a prompt and obtain input from the user
@@ -230,55 +218,56 @@ InteractiveBackend(StringInfo inBuf)
 
 	resetStringInfo(inBuf);
 
-	if (UseNewLine)
+	/*
+	 * Read characters until EOF or the appropriate delimiter is seen.
+	 */
+	while ((c = interactive_getc()) != EOF)
 	{
-		/*
-		 * if we are using \n as a delimiter, then read characters until the
-		 * \n.
-		 */
-		while ((c = interactive_getc()) != EOF)
+		if (c == '\n')
 		{
-			if (c == '\n')
+			if (UseSemiNewlineNewline)
 			{
-				if (backslashSeen)
+				/*
+				 * In -j mode, semicolon followed by two newlines ends the
+				 * command; otherwise treat newline as regular character.
+				 */
+				if (inBuf->len > 1 &&
+					inBuf->data[inBuf->len - 1] == '\n' &&
+					inBuf->data[inBuf->len - 2] == ';')
+				{
+					/* might as well drop the second newline */
+					break;
+				}
+			}
+			else
+			{
+				/*
+				 * In plain mode, newline ends the command unless preceded by
+				 * backslash.
+				 */
+				if (inBuf->len > 0 &&
+					inBuf->data[inBuf->len - 1] == '\\')
 				{
 					/* discard backslash from inBuf */
 					inBuf->data[--inBuf->len] = '\0';
-					backslashSeen = false;
+					/* discard newline too */
 					continue;
 				}
 				else
 				{
-					/* keep the newline character */
+					/* keep the newline character, but end the command */
 					appendStringInfoChar(inBuf, '\n');
 					break;
 				}
 			}
-			else if (c == '\\')
-				backslashSeen = true;
-			else
-				backslashSeen = false;
-
-			appendStringInfoChar(inBuf, (char) c);
 		}
 
-		if (c == EOF)
-			end = true;
-	}
-	else
-	{
-		/*
-		 * otherwise read characters until EOF.
-		 */
-		while ((c = interactive_getc()) != EOF)
-			appendStringInfoChar(inBuf, (char) c);
-
-		/* No input before EOF signal means time to quit. */
-		if (inBuf->len == 0)
-			end = true;
+		/* Not newline, or newline treated as regular character */
+		appendStringInfoChar(inBuf, (char) c);
 	}
 
-	if (end)
+	/* No input before EOF signal means time to quit. */
+	if (c == EOF && inBuf->len == 0)
 		return EOF;
 
 	/*
@@ -3391,7 +3380,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
 
 			case 'j':
 				if (secure)
-					UseNewLine = 0;
+					UseSemiNewlineNewline = true;
 				break;
 
 			case 'k':
@@ -3901,7 +3890,7 @@ PostgresMain(int argc, char *argv[],
 		if (pq_is_reading_msg())
 			ereport(FATAL,
 					(errcode(ERRCODE_PROTOCOL_VIOLATION),
-			errmsg("terminating connection because protocol synchronization was lost")));
+					 errmsg("terminating connection because protocol synchronization was lost")));
 
 		/* Now we can allow interrupts again */
 		RESUME_INTERRUPTS();
diff --git a/src/include/tcop/tcopdebug.h b/src/include/tcop/tcopdebug.h
deleted file mode 100644
index d7145ceed494cc76ae84e236167bfcd84b74bda2..0000000000000000000000000000000000000000
--- a/src/include/tcop/tcopdebug.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * tcopdebug.h
- *	  #defines governing debugging behaviour in the traffic cop
- *
- *
- * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * src/include/tcop/tcopdebug.h
- *
- *-------------------------------------------------------------------------
- */
-#ifndef TCOPDEBUG_H
-#define TCOPDEBUG_H
-
-/* ----------------------------------------------------------------
- *		debugging defines.
- *
- *		If you want certain debugging behaviour, then #define
- *		the variable to 1, else #undef it. -cim 10/26/89
- * ----------------------------------------------------------------
- */
-
-/* ----------------
- *		TCOP_SHOWSTATS controls whether or not buffer and
- *		access method statistics are shown for each query.  -cim 2/9/89
- * ----------------
- */
-#undef TCOP_SHOWSTATS
-
-/* ----------------
- *		TCOP_DONTUSENEWLINE controls the default setting of
- *		the UseNewLine variable in postgres.c
- * ----------------
- */
-#undef TCOP_DONTUSENEWLINE
-
-/* ----------------------------------------------------------------
- *		#defines controlled by above definitions
- * ----------------------------------------------------------------
- */
-
-#endif   /* TCOPDEBUG_H */