(chars: &[char], pos: &mut usize)
| 93 | } |
| 94 | |
| 95 | fn parse_string(chars: &[char], pos: &mut usize) -> Result<String, SqlError> { |
| 96 | // Expect opening single-quote |
| 97 | if *pos >= chars.len() || chars[*pos] != '\'' { |
| 98 | return Err(SqlError::Parse { |
| 99 | detail: format!( |
| 100 | "expected single quote at position {}, found {:?}", |
| 101 | pos, |
| 102 | chars.get(*pos) |
| 103 | ), |
| 104 | }); |
| 105 | } |
| 106 | *pos += 1; // consume opening quote |
| 107 | let mut s = String::new(); |
| 108 | loop { |
| 109 | if *pos >= chars.len() { |
| 110 | return Err(SqlError::Parse { |
| 111 | detail: "unterminated string literal".to_string(), |
| 112 | }); |
| 113 | } |
| 114 | if chars[*pos] == '\'' { |
| 115 | *pos += 1; // consume quote |
| 116 | // SQL escaped quote: '' → ' |
| 117 | if *pos < chars.len() && chars[*pos] == '\'' { |
| 118 | s.push('\''); |
| 119 | *pos += 1; |
| 120 | } else { |
| 121 | break; // end of string |
| 122 | } |
| 123 | } else { |
| 124 | s.push(chars[*pos]); |
| 125 | *pos += 1; |
| 126 | } |
| 127 | } |
| 128 | Ok(s) |
| 129 | } |
| 130 | |
| 131 | fn parse_double_quoted_string(chars: &[char], pos: &mut usize) -> Result<String, SqlError> { |
| 132 | if *pos >= chars.len() || chars[*pos] != '"' { |
no test coverage detected