diff --git a/compute_tools/src/pg_helpers.rs b/compute_tools/src/pg_helpers.rs index 47f64f581d..79f851ed13 100644 --- a/compute_tools/src/pg_helpers.rs +++ b/compute_tools/src/pg_helpers.rs @@ -47,12 +47,23 @@ pub struct GenericOption { /// declare a `trait` on it. pub type GenericOptions = Option>; +/// Escape a string for including it in a SQL literal +fn escape_literal(s: &str) -> String { + s.replace('\'', "''").replace('\\', "\\\\") +} + +/// Escape a string so that it can be used in postgresql.conf. +/// Same as escape_literal, currently. +fn escape_conf_value(s: &str) -> String { + s.replace('\'', "''").replace('\\', "\\\\") +} + impl GenericOption { /// Represent `GenericOption` as SQL statement parameter. pub fn to_pg_option(&self) -> String { if let Some(val) = &self.value { match self.vartype.as_ref() { - "string" => format!("{} '{}'", self.name, val), + "string" => format!("{} '{}'", self.name, escape_literal(val)), _ => format!("{} {}", self.name, val), } } else { @@ -73,7 +84,7 @@ impl GenericOption { }; match self.vartype.as_ref() { - "string" => format!("{} = '{}'", name, val), + "string" => format!("{} = '{}'", name, escape_conf_value(val)), _ => format!("{} = {}", name, val), } } else { diff --git a/compute_tools/tests/cluster_spec.json b/compute_tools/tests/cluster_spec.json index c29416d9c4..8f81e7b3bd 100644 --- a/compute_tools/tests/cluster_spec.json +++ b/compute_tools/tests/cluster_spec.json @@ -178,6 +178,11 @@ "name": "neon.pageserver_connstring", "value": "host=127.0.0.1 port=6400", "vartype": "string" + }, + { + "name": "test.escaping", + "value": "here's a backslash \\ and a quote ' and a double-quote \" hooray", + "vartype": "string" } ] }, diff --git a/compute_tools/tests/pg_helpers_tests.rs b/compute_tools/tests/pg_helpers_tests.rs index c92bb13668..f48211f7ed 100644 --- a/compute_tools/tests/pg_helpers_tests.rs +++ b/compute_tools/tests/pg_helpers_tests.rs @@ -50,6 +50,7 @@ neon.timeline_id = '2414a61ffc94e428f14b5758fe308e13' shared_preload_libraries = 'neon' synchronous_standby_names = 'walproposer' neon.pageserver_connstring = 'host=127.0.0.1 port=6400' +test.escaping = 'here''s a backslash \\ and a quote '' and a double-quote " hooray' "# ); }