diff --git a/src/domain/postgres/connection.rs b/src/domain/postgres/connection.rs index 0424938..cae7010 100644 --- a/src/domain/postgres/connection.rs +++ b/src/domain/postgres/connection.rs @@ -122,6 +122,14 @@ pub(crate) fn pg_restore_binary_name() -> &'static str { } } +pub(crate) fn quote_ident(s: &str) -> String { + format!("\"{}\"", s.replace('"', "\"\"")) +} + +pub(crate) fn quote_literal(s: &str) -> String { + format!("'{}'", s.replace('\'', "''")) +} + pub(crate) fn pg_dump_exists_in(dir: &std::path::Path) -> bool { dir.join(pg_dump_binary_name()).is_file() } diff --git a/src/tests/domain/postgres.rs b/src/tests/domain/postgres.rs index 032ed99..2093a67 100644 --- a/src/tests/domain/postgres.rs +++ b/src/tests/domain/postgres.rs @@ -383,3 +383,20 @@ mod select_pg_path_tests { } } } + +mod quoting_tests { + use crate::domain::postgres::connection::{quote_ident, quote_literal}; + + #[test] + fn quote_ident_escapes_double_quotes() { + assert_eq!(quote_ident("devdb"), "\"devdb\""); + assert_eq!(quote_ident("a\"b"), "\"a\"\"b\""); + assert_eq!(quote_ident("drop\"; --"), "\"drop\"\"; --\""); + } + + #[test] + fn quote_literal_escapes_single_quotes() { + assert_eq!(quote_literal("UTF8"), "'UTF8'"); + assert_eq!(quote_literal("O'Brien"), "'O''Brien'"); + } +}