LCOV - code coverage report
Current view: top level - libs/proxy/postgres-protocol2/src/escape - mod.rs (source / functions) Coverage Total Hit
Test: 07bee600374ccd486c69370d0972d9035964fe68.info Lines: 100.0 % 55 55
Test Date: 2025-02-20 13:11:02 Functions: 100.0 % 3 3

            Line data    Source code
       1              : //! Provides functions for escaping literals and identifiers for use
       2              : //! in SQL queries.
       3              : //!
       4              : //! Prefer parameterized queries where possible. Do not escape
       5              : //! parameters in a parameterized query.
       6              : 
       7              : #[cfg(test)]
       8              : mod test;
       9              : 
      10              : /// Escape a literal and surround result with single quotes. Not
      11              : /// recommended in most cases.
      12              : ///
      13              : /// If input contains backslashes, result will be of the form `
      14              : /// E'...'` so it is safe to use regardless of the setting of
      15              : /// standard_conforming_strings.
      16            4 : pub fn escape_literal(input: &str) -> String {
      17            4 :     escape_internal(input, false)
      18            4 : }
      19              : 
      20              : /// Escape an identifier and surround result with double quotes.
      21            4 : pub fn escape_identifier(input: &str) -> String {
      22            4 :     escape_internal(input, true)
      23            4 : }
      24              : 
      25              : // Translation of PostgreSQL libpq's PQescapeInternal(). Does not
      26              : // require a connection because input string is known to be valid
      27              : // UTF-8.
      28              : //
      29              : // Escape arbitrary strings.  If as_ident is true, we escape the
      30              : // result as an identifier; if false, as a literal.  The result is
      31              : // returned in a newly allocated buffer.  If we fail due to an
      32              : // encoding violation or out of memory condition, we return NULL,
      33              : // storing an error message into conn.
      34            8 : fn escape_internal(input: &str, as_ident: bool) -> String {
      35            8 :     let mut num_backslashes = 0;
      36            8 :     let mut num_quotes = 0;
      37            8 :     let quote_char = if as_ident { '"' } else { '\'' };
      38              : 
      39              :     // Scan the string for characters that must be escaped.
      40           30 :     for ch in input.chars() {
      41           30 :         if ch == quote_char {
      42            2 :             num_quotes += 1;
      43           28 :         } else if ch == '\\' {
      44            2 :             num_backslashes += 1;
      45           26 :         }
      46              :     }
      47              : 
      48              :     // Allocate output String.
      49            8 :     let mut result_size = input.len() + num_quotes + 3; // two quotes, plus a NUL
      50            8 :     if !as_ident && num_backslashes > 0 {
      51            1 :         result_size += num_backslashes + 2;
      52            7 :     }
      53              : 
      54            8 :     let mut output = String::with_capacity(result_size);
      55            8 : 
      56            8 :     // If we are escaping a literal that contains backslashes, we use
      57            8 :     // the escape string syntax so that the result is correct under
      58            8 :     // either value of standard_conforming_strings.  We also emit a
      59            8 :     // leading space in this case, to guard against the possibility
      60            8 :     // that the result might be interpolated immediately following an
      61            8 :     // identifier.
      62            8 :     if !as_ident && num_backslashes > 0 {
      63            1 :         output.push(' ');
      64            1 :         output.push('E');
      65            7 :     }
      66              : 
      67              :     // Opening quote.
      68            8 :     output.push(quote_char);
      69            8 : 
      70            8 :     // Use fast path if possible.
      71            8 :     //
      72            8 :     // We've already verified that the input string is well-formed in
      73            8 :     // the current encoding.  If it contains no quotes and, in the
      74            8 :     // case of literal-escaping, no backslashes, then we can just copy
      75            8 :     // it directly to the output buffer, adding the necessary quotes.
      76            8 :     //
      77            8 :     // If not, we must rescan the input and process each character
      78            8 :     // individually.
      79            8 :     if num_quotes == 0 && (num_backslashes == 0 || as_ident) {
      80            5 :         output.push_str(input);
      81            5 :     } else {
      82           12 :         for ch in input.chars() {
      83           12 :             if ch == quote_char || (!as_ident && ch == '\\') {
      84            3 :                 output.push(ch);
      85            9 :             }
      86           12 :             output.push(ch);
      87              :         }
      88              :     }
      89              : 
      90            8 :     output.push(quote_char);
      91            8 : 
      92            8 :     output
      93            8 : }
        

Generated by: LCOV version 2.1-beta