Skip to content

Commit 11a020e

Browse files
committed
Allow escaping of option values for options passed at connection start.
This is useful to allow to set GUCs to values that include spaces; something that wasn't previously possible. The primary case motivating this is the desire to set default_transaction_isolation to 'repeatable read' on a per connection basis, but other usecases like seach_path do also exist. This introduces a slight backward incompatibility: Previously a \ in an option value would have been passed on literally, now it'll be taken as an escape. The relevant mailing list discussion starts with 20140204125823.GJ12016@awork2.anarazel.de.
1 parent e23014f commit 11a020e

File tree

3 files changed

+43
-17
lines changed

3 files changed

+43
-17
lines changed

doc/src/sgml/protocol.sgml

+4-1
Original file line numberDiff line numberDiff line change
@@ -4734,7 +4734,10 @@ StartupMessage (F)
47344734
set at backend start time might be listed. Such settings
47354735
will be applied during backend start (after parsing the
47364736
command-line options if any). The values will act as
4737-
session defaults.
4737+
session defaults. Spaces in option values need to be escaped
4738+
with a backslash (<literal>\</>). A literal backslash can be
4739+
passed by escaping it with another backslash
4740+
(i.e <literal>\\</>).
47384741
</para>
47394742
</listitem>
47404743
</varlistentry>

src/backend/postmaster/postmaster.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -4083,8 +4083,7 @@ BackendRun(Port *port)
40834083

40844084
/*
40854085
* Pass any backend switches specified with -o on the postmaster's own
4086-
* command line. We assume these are secure. (It's OK to mangle
4087-
* ExtraOptions now, since we're safely inside a subprocess.)
4086+
* command line. We assume these are secure.
40884087
*/
40894088
pg_split_opts(av, &ac, ExtraOptions);
40904089

src/backend/utils/init/postinit.c

+38-14
Original file line numberDiff line numberDiff line change
@@ -409,32 +409,57 @@ InitCommunication(void)
409409
/*
410410
* pg_split_opts -- split a string of options and append it to an argv array
411411
*
412-
* NB: the input string is destructively modified! Also, caller is responsible
413-
* for ensuring the argv array is large enough. The maximum possible number
414-
* of arguments added by this routine is (strlen(optstr) + 1) / 2.
412+
* The caller is responsible for ensuring the argv array is large enough. The
413+
* maximum possible number of arguments added by this routine is
414+
* (strlen(optstr) + 1) / 2.
415415
*
416-
* Since no current POSTGRES arguments require any quoting characters,
417-
* we can use the simple-minded tactic of assuming each set of space-
418-
* delimited characters is a separate argv element.
419-
*
420-
* If you don't like that, well, we *used* to pass the whole option string
421-
* as ONE argument to execl(), which was even less intelligent...
416+
* Because some option values can contain spaces we allow escaping using
417+
* backslashes, with \\ representing a literal backslash.
422418
*/
423419
void
424420
pg_split_opts(char **argv, int *argcp, char *optstr)
425421
{
422+
StringInfoData s;
423+
424+
initStringInfo(&s);
425+
426426
while (*optstr)
427427
{
428+
bool last_was_escape = false;
429+
430+
resetStringInfo(&s);
431+
432+
/* skip over leading space */
428433
while (isspace((unsigned char) *optstr))
429434
optstr++;
435+
430436
if (*optstr == '\0')
431437
break;
432-
argv[(*argcp)++] = optstr;
433-
while (*optstr && !isspace((unsigned char) *optstr))
438+
439+
/*
440+
* Parse a single option + value, stopping at the first space, unless
441+
* it's escaped.
442+
*/
443+
while (*optstr)
444+
{
445+
if (isspace(*optstr) && !last_was_escape)
446+
break;
447+
448+
if (!last_was_escape && *optstr == '\\')
449+
last_was_escape = true;
450+
else
451+
{
452+
last_was_escape = false;
453+
appendStringInfoChar(&s, *optstr);
454+
}
455+
434456
optstr++;
435-
if (*optstr)
436-
*optstr++ = '\0';
457+
}
458+
459+
/* now store the option */
460+
argv[(*argcp)++] = pstrdup(s.data);
437461
}
462+
resetStringInfo(&s);
438463
}
439464

440465
/*
@@ -981,7 +1006,6 @@ process_startup_options(Port *port, bool am_superuser)
9811006

9821007
av[ac++] = "postgres";
9831008

984-
/* Note this mangles port->cmdline_options */
9851009
pg_split_opts(av, &ac, port->cmdline_options);
9861010

9871011
av[ac] = NULL;

0 commit comments

Comments
 (0)