Skip to content

Commit 08cf1c8

Browse files
committed
correctly treat backslash in datafusion-cli
1 parent c92982c commit 08cf1c8

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

datafusion-cli/src/helper.rs

+40-16
Original file line numberDiff line numberDiff line change
@@ -170,28 +170,44 @@ impl Helper for CliHelper {}
170170
///
171171
/// The data read from stdio will be escaped, so we need to unescape the input before executing the input
172172
pub fn unescape_input(input: &str) -> datafusion::error::Result<String> {
173-
let mut chars = input.chars();
174-
173+
let mut chars = input.chars().peekable();
175174
let mut result = String::with_capacity(input.len());
176-
while let Some(char) = chars.next() {
177-
if char == '\\' {
178-
if let Some(next_char) = chars.next() {
179-
// https://static.rust-lang.org/doc/master/reference.html#literals
180-
result.push(match next_char {
181-
'0' => '\0',
182-
'n' => '\n',
183-
'r' => '\r',
184-
't' => '\t',
185-
'\\' => '\\',
175+
176+
while let Some(ch) = chars.next() {
177+
if ch == '\\' {
178+
if let Some(&next) = chars.peek() {
179+
match next {
180+
'0' => {
181+
chars.next();
182+
result.push('\0');
183+
}
184+
'n' => {
185+
chars.next();
186+
result.push('\n');
187+
}
188+
'r' => {
189+
chars.next();
190+
result.push('\r');
191+
}
192+
't' => {
193+
chars.next();
194+
result.push('\t');
195+
}
196+
'\\' | '\'' => result.push('\\'),
186197
_ => {
187-
return Err(sql_datafusion_err!(ParserError::TokenizerError(
188-
format!("unsupported escape char: '\\{}'", next_char)
198+
return Err(DataFusionError::Execution(format!(
199+
"Invalid escape sequence: \\{}",
200+
next
189201
)))
190202
}
191-
});
203+
}
204+
} else {
205+
return Err(sql_datafusion_err!(ParserError::TokenizerError(
206+
"incomplete escape sequence: trailing backslash".to_string()
207+
)));
192208
}
193209
} else {
194-
result.push(char);
210+
result.push(ch);
195211
}
196212
}
197213

@@ -319,6 +335,14 @@ mod tests {
319335
)?;
320336
assert!(matches!(result, ValidationResult::Invalid(Some(_))));
321337

338+
let result = readline_direct(
339+
Cursor::new(
340+
r"select '\', '\\', '\\\\\', 'dsdsds\\\\', '\t', '\0', '\n';".as_bytes(),
341+
),
342+
&validator,
343+
)?;
344+
assert!(matches!(result, ValidationResult::Valid(None)));
345+
322346
Ok(())
323347
}
324348

datafusion-cli/tests/cli_integration.rs

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ fn init() {
3939
["--command", "select 1; select 2;", "--format", "json", "-q"],
4040
"[{\"Int64(1)\":1}]\n[{\"Int64(2)\":2}]\n"
4141
)]
42+
#[case::exec_backslash(
43+
["--file", "tests/data/backslash.txt", "--format", "json", "-q"],
44+
"[{\"Utf8(\\\"\\\\\\\")\":\"\\\\\",\"Utf8(\\\"\\\\\\\\\\\")\":\"\\\\\\\\\",\"Utf8(\\\"\\\\\\\\\\\\\\\\\\\\\\\")\":\"\\\\\\\\\\\\\\\\\\\\\",\"Utf8(\\\"\\\\\\\\\\\\\\\\dsdsds\\\\\\\\\\\\\\\")\":\"\\\\\\\\\\\\\\\\dsdsds\\\\\\\\\\\\\",\"Utf8(\\\"\\t\\\")\":\"\\t\",\"Utf8(\\\"\\u0000\\\")\":\"\\u0000\",\"Utf8(\\\"\\n\\\")\":\"\\n\"}]\n"
45+
)]
4246
#[case::exec_from_files(
4347
["--file", "tests/data/sql.txt", "--format", "json", "-q"],
4448
"[{\"Int64(1)\":1}]\n"
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
select '\', '\\', '\\\\\', 'dsdsds\\\\', '\t', '\0', '\n';

0 commit comments

Comments
 (0)