Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 66d947b

Browse files
committed
Adjust behavior of single-user -j mode for better initdb error reporting.
Previously, -j caused the entire input file to be read in and executed as a single command string. That's undesirable, not least because any error causes the entire file to be regurgitated as the "failing query". Some experimentation suggests a better rule: end the command string when we see a semicolon immediately followed by two newlines, ie, an empty line after a query. This serves nicely to break up the existing examples such as information_schema.sql and system_views.sql. A limitation is that it's no longer possible to write such a sequence within a string literal or multiline comment in a file meant to be read with -j; but there are no instances of such a problem within the data currently used by initdb. (If someone does make such a mistake in future, it'll be obvious because they'll get an unterminated-literal or unterminated-comment syntax error.) Other than that, there shouldn't be any negative consequences; you're not forced to end statements that way, it's just a better idea in most cases. In passing, remove src/include/tcop/tcopdebug.h, which is dead code because it's not included anywhere, and hasn't been for more than ten years. One of the debug-support symbols it purported to describe has been unreferenced for at least the same amount of time, and the other is removed by this commit on the grounds that it was useless: forcing -j mode all the time would have broken initdb. The lack of complaints about that, or about the missing inclusion, shows that no one has tried to use TCOP_DONTUSENEWLINE in many years.
1 parent aee7705 commit 66d947b

File tree

7 files changed

+116
-109
lines changed

7 files changed

+116
-109
lines changed

doc/src/sgml/ref/postgres-ref.sgml

+29-16
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,9 @@ PostgreSQL documentation
529529
</indexterm>
530530

531531
<para>
532-
The following options only apply to the single-user mode.
532+
The following options only apply to the single-user mode
533+
(see <xref linkend="app-postgres-single-user"
534+
endterm="app-postgres-single-user-title">).
533535
</para>
534536

535537
<variablelist>
@@ -558,7 +560,7 @@ PostgreSQL documentation
558560
<term><option>-E</option></term>
559561
<listitem>
560562
<para>
561-
Echo all commands.
563+
Echo all commands to standard output before executing them.
562564
</para>
563565
</listitem>
564566
</varlistentry>
@@ -567,7 +569,8 @@ PostgreSQL documentation
567569
<term><option>-j</option></term>
568570
<listitem>
569571
<para>
570-
Disables use of newline as a statement delimiter.
572+
Use semicolon followed by two newlines, rather than just newline,
573+
as the command entry terminator.
571574
</para>
572575
</listitem>
573576
</varlistentry>
@@ -760,8 +763,8 @@ PostgreSQL documentation
760763
</para>
761764
</refsect1>
762765

763-
<refsect1>
764-
<title>Usage</title>
766+
<refsect1 id="app-postgres-single-user">
767+
<title id="app-postgres-single-user-title">Single-User Mode</title>
765768

766769
<para>
767770
To start a single-user mode server, use a command like
@@ -778,30 +781,40 @@ PostgreSQL documentation
778781
entry terminator; there is no intelligence about semicolons,
779782
as there is in <application>psql</>. To continue a command
780783
across multiple lines, you must type backslash just before each
781-
newline except the last one.
784+
newline except the last one. The backslash and adjacent newline are
785+
both dropped from the input command. Note that this will happen even
786+
when within a string literal or comment.
782787
</para>
783788

784789
<para>
785-
But if you use the <option>-j</> command line switch, then newline does
786-
not terminate command entry. In this case, the server will read the standard input
787-
until the end-of-file (<acronym>EOF</>) marker, then
788-
process the input as a single command string. Backslash-newline is not
789-
treated specially in this case.
790+
But if you use the <option>-j</> command line switch, a single newline
791+
does not terminate command entry; instead, the sequence
792+
semicolon-newline-newline does. That is, type a semicolon immediately
793+
followed by a completely empty line. Backslash-newline is not
794+
treated specially in this mode. Again, there is no intelligence about
795+
such a sequence appearing within a string literal or comment.
796+
</para>
797+
798+
<para>
799+
In either input mode, if you type a semicolon that is not just before or
800+
part of a command entry terminator, it is considered a command separator.
801+
When you do type a command entry terminator, the multiple statements
802+
you've entered will be executed as a single transaction.
790803
</para>
791804

792805
<para>
793806
To quit the session, type <acronym>EOF</acronym>
794807
(<keycombo action="simul"><keycap>Control</><keycap>D</></>, usually).
795-
If you've
796-
used <option>-j</>, two consecutive <acronym>EOF</>s are needed to exit.
808+
If you've entered any text since the last command entry terminator,
809+
then <acronym>EOF</acronym> will be taken as a command entry terminator,
810+
and another <acronym>EOF</> will be needed to exit.
797811
</para>
798812

799813
<para>
800814
Note that the single-user mode server does not provide sophisticated
801815
line-editing features (no command history, for example).
802-
Single-User mode also does not do any background processing, like
803-
automatic checkpoints.
804-
816+
Single-user mode also does not do any background processing, such as
817+
automatic checkpoints or replication.
805818
</para>
806819
</refsect1>
807820

src/backend/catalog/information_schema.sql

+8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
* Copyright (c) 2003-2015, PostgreSQL Global Development Group
66
*
77
* src/backend/catalog/information_schema.sql
8+
*
9+
* Note: this file is read in single-user -j mode, which means that the
10+
* command terminator is semicolon-newline-newline; whenever the backend
11+
* sees that, it stops and executes what it's got. If you write a lot of
12+
* statements without empty lines between, they'll all get quoted to you
13+
* in any error message about one of them, so don't do that. Also, you
14+
* cannot write a semicolon immediately followed by an empty line in a
15+
* string literal (including a function body!) or a multiline comment.
816
*/
917

1018
/*

src/backend/catalog/system_views.sql

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
* Copyright (c) 1996-2015, PostgreSQL Global Development Group
55
*
66
* src/backend/catalog/system_views.sql
7+
*
8+
* Note: this file is read in single-user -j mode, which means that the
9+
* command terminator is semicolon-newline-newline; whenever the backend
10+
* sees that, it stops and executes what it's got. If you write a lot of
11+
* statements without empty lines between, they'll all get quoted to you
12+
* in any error message about one of them, so don't do that. Also, you
13+
* cannot write a semicolon immediately followed by an empty line in a
14+
* string literal (including a function body!) or a multiline comment.
715
*/
816

917
CREATE VIEW pg_roles AS

src/backend/snowball/snowball.sql.in

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
1-
-- src/backend/snowball/snowball.sql.in$
1+
/*
2+
* text search configuration for _LANGNAME_ language
3+
*
4+
* Copyright (c) 2007-2015, PostgreSQL Global Development Group
5+
*
6+
* src/backend/snowball/snowball.sql.in
7+
*
8+
* _LANGNAME_ and certain other macros are replaced for each language;
9+
* see the Makefile for details.
10+
*
11+
* Note: this file is read in single-user -j mode, which means that the
12+
* command terminator is semicolon-newline-newline; whenever the backend
13+
* sees that, it stops and executes what it's got. If you write a lot of
14+
* statements without empty lines between, they'll all get quoted to you
15+
* in any error message about one of them, so don't do that. Also, you
16+
* cannot write a semicolon immediately followed by an empty line in a
17+
* string literal (including a function body!) or a multiline comment.
18+
*/
219

3-
-- text search configuration for _LANGNAME_ language
420
CREATE TEXT SEARCH DICTIONARY _DICTNAME_
521
(TEMPLATE = snowball, Language = _LANGNAME_ _STOPWORDS_);
622

src/backend/snowball/snowball_func.sql.in

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,21 @@
1-
-- src/backend/snowball/snowball_func.sql.in$
1+
/*
2+
* Create underlying C functions for Snowball stemmers
3+
*
4+
* Copyright (c) 2007-2015, PostgreSQL Global Development Group
5+
*
6+
* src/backend/snowball/snowball_func.sql.in
7+
*
8+
* This file is combined with multiple instances of snowball.sql.in to
9+
* build snowball_create.sql, which is executed during initdb.
10+
*
11+
* Note: this file is read in single-user -j mode, which means that the
12+
* command terminator is semicolon-newline-newline; whenever the backend
13+
* sees that, it stops and executes what it's got. If you write a lot of
14+
* statements without empty lines between, they'll all get quoted to you
15+
* in any error message about one of them, so don't do that. Also, you
16+
* cannot write a semicolon immediately followed by an empty line in a
17+
* string literal (including a function body!) or a multiline comment.
18+
*/
219

320
SET search_path = pg_catalog;
421

src/backend/tcop/postgres.c

+35-46
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,8 @@ static CachedPlanSource *unnamed_stmt_psrc = NULL;
157157

158158
/* assorted command-line switches */
159159
static const char *userDoption = NULL; /* -D switch */
160-
161160
static bool EchoQuery = false; /* -E switch */
162-
163-
/*
164-
* people who want to use EOF should #define DONTUSENEWLINE in
165-
* tcop/tcopdebug.h
166-
*/
167-
#ifndef TCOP_DONTUSENEWLINE
168-
static int UseNewLine = 1; /* Use newlines query delimiters (the default) */
169-
#else
170-
static int UseNewLine = 0; /* Use EOF as query delimiters */
171-
#endif /* TCOP_DONTUSENEWLINE */
161+
static bool UseSemiNewlineNewline = false; /* -j switch */
172162

173163
/* whether or not, and why, we were canceled by conflict with recovery */
174164
static bool RecoveryConflictPending = false;
@@ -219,8 +209,6 @@ static int
219209
InteractiveBackend(StringInfo inBuf)
220210
{
221211
int c; /* character read from getc() */
222-
bool end = false; /* end-of-input flag */
223-
bool backslashSeen = false; /* have we seen a \ ? */
224212

225213
/*
226214
* display a prompt and obtain input from the user
@@ -230,55 +218,56 @@ InteractiveBackend(StringInfo inBuf)
230218

231219
resetStringInfo(inBuf);
232220

233-
if (UseNewLine)
221+
/*
222+
* Read characters until EOF or the appropriate delimiter is seen.
223+
*/
224+
while ((c = interactive_getc()) != EOF)
234225
{
235-
/*
236-
* if we are using \n as a delimiter, then read characters until the
237-
* \n.
238-
*/
239-
while ((c = interactive_getc()) != EOF)
226+
if (c == '\n')
240227
{
241-
if (c == '\n')
228+
if (UseSemiNewlineNewline)
242229
{
243-
if (backslashSeen)
230+
/*
231+
* In -j mode, semicolon followed by two newlines ends the
232+
* command; otherwise treat newline as regular character.
233+
*/
234+
if (inBuf->len > 1 &&
235+
inBuf->data[inBuf->len - 1] == '\n' &&
236+
inBuf->data[inBuf->len - 2] == ';')
237+
{
238+
/* might as well drop the second newline */
239+
break;
240+
}
241+
}
242+
else
243+
{
244+
/*
245+
* In plain mode, newline ends the command unless preceded by
246+
* backslash.
247+
*/
248+
if (inBuf->len > 0 &&
249+
inBuf->data[inBuf->len - 1] == '\\')
244250
{
245251
/* discard backslash from inBuf */
246252
inBuf->data[--inBuf->len] = '\0';
247-
backslashSeen = false;
253+
/* discard newline too */
248254
continue;
249255
}
250256
else
251257
{
252-
/* keep the newline character */
258+
/* keep the newline character, but end the command */
253259
appendStringInfoChar(inBuf, '\n');
254260
break;
255261
}
256262
}
257-
else if (c == '\\')
258-
backslashSeen = true;
259-
else
260-
backslashSeen = false;
261-
262-
appendStringInfoChar(inBuf, (char) c);
263263
}
264264

265-
if (c == EOF)
266-
end = true;
267-
}
268-
else
269-
{
270-
/*
271-
* otherwise read characters until EOF.
272-
*/
273-
while ((c = interactive_getc()) != EOF)
274-
appendStringInfoChar(inBuf, (char) c);
275-
276-
/* No input before EOF signal means time to quit. */
277-
if (inBuf->len == 0)
278-
end = true;
265+
/* Not newline, or newline treated as regular character */
266+
appendStringInfoChar(inBuf, (char) c);
279267
}
280268

281-
if (end)
269+
/* No input before EOF signal means time to quit. */
270+
if (c == EOF && inBuf->len == 0)
282271
return EOF;
283272

284273
/*
@@ -3391,7 +3380,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
33913380

33923381
case 'j':
33933382
if (secure)
3394-
UseNewLine = 0;
3383+
UseSemiNewlineNewline = true;
33953384
break;
33963385

33973386
case 'k':
@@ -3901,7 +3890,7 @@ PostgresMain(int argc, char *argv[],
39013890
if (pq_is_reading_msg())
39023891
ereport(FATAL,
39033892
(errcode(ERRCODE_PROTOCOL_VIOLATION),
3904-
errmsg("terminating connection because protocol synchronization was lost")));
3893+
errmsg("terminating connection because protocol synchronization was lost")));
39053894

39063895
/* Now we can allow interrupts again */
39073896
RESUME_INTERRUPTS();

src/include/tcop/tcopdebug.h

-44
This file was deleted.

0 commit comments

Comments
 (0)