fix: ctrl-c stop current query execution

This commit is contained in:
JeanArhancet 2024-08-03 22:53:52 +02:00
parent e890a1d64f
commit 38a1b85094
3 changed files with 85 additions and 7 deletions

31
Cargo.lock generated
View file

@ -220,6 +220,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
@ -490,6 +496,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "ctrlc"
version = "3.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345"
dependencies = [
"nix 0.28.0",
"windows-sys 0.52.0",
]
[[package]]
name = "debugid"
version = "0.8.0"
@ -1014,6 +1030,7 @@ dependencies = [
"anyhow",
"clap 4.5.8",
"cli-table",
"ctrlc",
"dirs",
"env_logger 0.10.2",
"limbo_core",
@ -1149,6 +1166,18 @@ dependencies = [
"libc",
]
[[package]]
name = "nix"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases 0.1.1",
"libc",
]
[[package]]
name = "nix"
version = "0.29.0"
@ -1157,7 +1186,7 @@ checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases",
"cfg_aliases 0.2.1",
"libc",
]

View file

@ -17,6 +17,7 @@ dist = true
name = "limbo"
path = "main.rs"
[dependencies]
anyhow = "1.0.75"
clap = { version = "4.4.0", features = ["derive"] }
@ -25,3 +26,4 @@ dirs = "5.0.1"
env_logger = "0.10.1"
limbo_core = { path = "../core" }
rustyline = "12.0.0"
ctrlc = "3.4.4"

View file

@ -6,6 +6,7 @@ use limbo_core::{Database, RowResult, Value};
use opcodes_dictionary::OPCODE_DESCRIPTIONS;
use rustyline::{error::ReadlineError, DefaultEditor};
use std::path::PathBuf;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
@ -39,11 +40,24 @@ fn main() -> anyhow::Result<()> {
let io = Arc::new(limbo_core::PlatformIO::new()?);
let db = Database::open_file(io.clone(), path)?;
let conn = db.connect();
let interrupt_count = Arc::new(AtomicUsize::new(0));
{
let interrupt_count = Arc::clone(&interrupt_count);
ctrlc::set_handler(move || {
// Increment the interrupt count on Ctrl-C
interrupt_count.fetch_add(1, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");
}
if let Some(sql) = opts.sql {
if sql.trim().starts_with('.') {
handle_dot_command(io.clone(), &conn, &sql)?;
} else {
query(io.clone(), &conn, &sql, &opts.output_mode)?;
query(io.clone(), &conn, &sql, &opts.output_mode, &interrupt_count)?;
}
return Ok(());
}
@ -60,14 +74,27 @@ fn main() -> anyhow::Result<()> {
match readline {
Ok(line) => {
rl.add_history_entry(line.to_owned())?;
interrupt_count.store(0, Ordering::SeqCst);
if line.trim().starts_with('.') {
handle_dot_command(io.clone(), &conn, &line)?;
} else {
query(io.clone(), &conn, &line, &opts.output_mode)?;
query(
io.clone(),
&conn,
&line,
&opts.output_mode,
&interrupt_count,
)?;
}
}
Err(ReadlineError::Interrupted) => {
break;
// At prompt, increment interrupt count
if interrupt_count.fetch_add(1, Ordering::SeqCst) >= 1 {
eprintln!("Interrupted. Exiting...");
break;
}
println!("Use .quit to exit or press Ctrl-C again to force quit.");
continue;
}
Err(ReadlineError::Eof) => {
break;
@ -91,16 +118,20 @@ In addition to standard SQL commands, the following special commands are availab
Special Commands:
-----------------
.quit Stop interpreting input stream and exit.
.schema <table_name> Show the schema of the specified table.
.opcodes Display all the opcodes defined by the virtual machine
.help Display this help message.
Usage Examples:
---------------
1. To view the schema of a table named 'employees':
1. To quit the Limbo SQL Shell:
.quit
2. To view the schema of a table named 'employees':
.schema employees
2. To list all available SQL opcodes:
3. To list all available SQL opcodes:
.opcodes
Note:
@ -125,6 +156,10 @@ fn handle_dot_command(
}
match args[0] {
".quit" => {
println!("Exiting Limbo SQL Shell.");
std::process::exit(0)
}
".schema" => {
let table_name = args.get(1).copied();
display_schema(io, conn, table_name)?;
@ -218,10 +253,16 @@ fn query(
conn: &limbo_core::Connection,
sql: &str,
output_mode: &OutputMode,
interrupt_count: &Arc<AtomicUsize>,
) -> anyhow::Result<()> {
match conn.query(sql) {
Ok(Some(ref mut rows)) => match output_mode {
OutputMode::Raw => loop {
if interrupt_count.load(Ordering::SeqCst) > 0 {
println!("Query interrupted.");
return Ok(());
}
match rows.next_row()? {
RowResult::Row(row) => {
for (i, value) in row.values.iter().enumerate() {
@ -241,10 +282,16 @@ fn query(
RowResult::IO => {
io.run_once()?;
}
RowResult::Done => break,
RowResult::Done => {
break;
}
}
},
OutputMode::Pretty => {
if interrupt_count.load(Ordering::SeqCst) > 0 {
println!("Query interrupted.");
return Ok(());
}
let mut table_rows: Vec<Vec<_>> = vec![];
loop {
match rows.next_row()? {