Merge 'cli: Fix infinite loop on non-terminated literal' from Ihor Andrianov

Bug: Infinite loop when parsing unclosed string literal
To reproduce:
Run query: `SELECT max(';`
Current behavior:
- Query runner enters an infinite loop when encountering an unclosed
string literal and prints error
Fix:
- Throw error and stop query runner loop
Closes #988

Closes #989
This commit is contained in:
Pekka Enberg 2025-02-12 09:14:35 +02:00
commit e48c50faf6

View file

@ -310,13 +310,7 @@ impl Limbo {
if cmd.trim().starts_with('.') {
self.handle_dot_command(cmd);
} else {
let conn = self.conn.clone();
let runner = conn.query_runner(cmd.as_bytes());
for output in runner {
if let Err(e) = self.print_query_result(cmd, output) {
let _ = self.writeln(e.to_string());
}
}
self.run_query(cmd);
}
std::process::exit(0);
}
@ -434,6 +428,21 @@ impl Limbo {
self.input_buff.push(' ');
}
fn run_query(&mut self, input: &str) {
let echo = self.opts.echo;
if echo {
let _ = self.writeln(&input);
}
let conn = self.conn.clone();
let runner = conn.query_runner(input.as_bytes());
for output in runner {
if let Err(_) = self.print_query_result(&input, output) {
break;
}
}
self.reset_input();
}
pub fn handle_input_line(
&mut self,
line: &str,
@ -458,17 +467,7 @@ impl Limbo {
self.buffer_input(after_comment);
if after_comment.ends_with(';') {
if self.opts.echo {
let _ = self.writeln(after_comment);
}
let conn = self.conn.clone();
let runner = conn.query_runner(after_comment.as_bytes());
for output in runner {
if let Err(e) = self.print_query_result(after_comment, output) {
let _ = self.writeln(e.to_string());
}
}
self.reset_input();
self.run_query(after_comment);
} else {
self.set_multiline_prompt();
}
@ -489,18 +488,7 @@ impl Limbo {
if line.ends_with(';') {
self.buffer_input(line);
let buff = self.input_buff.clone();
let echo = self.opts.echo;
if echo {
let _ = self.writeln(&buff);
}
let conn = self.conn.clone();
let runner = conn.query_runner(buff.as_bytes());
for output in runner {
if let Err(e) = self.print_query_result(&buff, output) {
let _ = self.writeln(e.to_string());
}
}
self.reset_input();
self.run_query(buff.as_str());
} else {
self.buffer_input(format!("{}\n", line).as_str());
self.set_multiline_prompt();
@ -745,6 +733,7 @@ impl Limbo {
"{:?}",
miette::Error::from(err).with_source_code(sql.to_owned())
));
anyhow::bail!("We have to throw here, even if we printed error");
}
}
// for now let's cache flush always
@ -881,17 +870,7 @@ impl Limbo {
}
let buff = self.input_buff.clone();
let echo = self.opts.echo;
if echo {
let _ = self.writeln(&buff);
}
let conn = self.conn.clone();
let runner = conn.query_runner(buff.as_bytes());
for output in runner {
if let Err(e) = self.print_query_result(&buff, output) {
let _ = self.writeln(e.to_string());
}
}
self.run_query(buff.as_str());
self.reset_input();
}
}