Skip to main content

nodedb_types/
sql_quote.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! SQL-standard quoting for identifiers and string literals.
4//!
5//! These helpers preserve input bytes other than the delimiter being escaped.
6//! They are intended for SQL text reconstruction only; parameter binding remains
7//! preferable when the protocol supports it.
8
9/// Quote a SQL identifier by doubling embedded double quotes and wrapping the
10/// result in double quotes.
11#[must_use]
12pub fn quote_ident(value: &str) -> String {
13    let escaped = value.replace('"', "\"\"");
14    format!("\"{escaped}\"")
15}
16
17/// Quote a SQL string literal by doubling embedded single quotes and wrapping
18/// the result in single quotes.
19#[must_use]
20pub fn quote_literal(value: &str) -> String {
21    let escaped = value.replace('\'', "''");
22    format!("'{escaped}'")
23}
24
25#[cfg(test)]
26mod tests {
27    use super::*;
28
29    #[test]
30    fn identifiers_quote_empty_and_embedded_delimiters() {
31        assert_eq!(quote_ident(""), "\"\"");
32        assert_eq!(quote_ident("a\"b"), "\"a\"\"b\"");
33    }
34
35    #[test]
36    fn literals_quote_empty_and_embedded_delimiters() {
37        assert_eq!(quote_literal(""), "''");
38        assert_eq!(quote_literal("O'Reilly"), "'O''Reilly'");
39    }
40
41    #[test]
42    fn quoting_preserves_control_shaped_unicode_and_sql_punctuation() {
43        let value = "snow 雪;\n\t\u{0001}'\"--";
44        assert_eq!(quote_ident(value), "\"snow 雪;\n\t\u{0001}'\"\"--\"");
45        assert_eq!(quote_literal(value), "'snow 雪;\n\t\u{0001}''\"--'");
46    }
47}