Merge 'Expose 'Explain' to prepared statement to allow for alternate Writer ' from Preston Thorpe

### The problem:
I often need to copy the output of an `Explain` statement to my
clipboard. Currently this is not possible because it currently will only
write to stdout.
All other limbo output, I am able to run `.output file` in the CLI, then
enter my query and in another tmux pane I simply `cat file | xclip -in
-selection clipboard`.
### The solution:
Expose a `statement.explain()` method that returns the query explanation
as a string. If the user uses something like `execute` instead of
prepare, it will default to `stdout` as expected, but this allows the
user to access the query plan on the prepared statement and do with it
what they please.

Closes #1166
This commit is contained in:
Pekka Enberg 2025-03-28 09:55:58 +02:00
commit 387b68fc06
4 changed files with 53 additions and 37 deletions

View file

@ -40,6 +40,7 @@ use std::{
borrow::Cow,
cell::{Cell, RefCell},
collections::HashMap,
io::Write,
num::NonZero,
ops::Deref,
rc::Rc,
@ -335,37 +336,25 @@ impl Connection {
pub(crate) fn run_cmd(self: &Rc<Connection>, cmd: Cmd) -> Result<Option<Statement>> {
let syms = self.syms.borrow();
match cmd {
Cmd::Stmt(stmt) => {
let program = Rc::new(translate::translate(
self.schema
.try_read()
.ok_or(LimboError::SchemaLocked)?
.deref(),
stmt,
self.header.clone(),
self.pager.clone(),
Rc::downgrade(self),
&syms,
QueryMode::Normal,
)?);
let stmt = Statement::new(program, self._db.mv_store.clone(), self.pager.clone());
Ok(Some(stmt))
}
Cmd::Explain(stmt) => {
Cmd::Stmt(ref stmt) | Cmd::Explain(ref stmt) => {
let program = translate::translate(
self.schema
.try_read()
.ok_or(LimboError::SchemaLocked)?
.deref(),
stmt,
stmt.clone(),
self.header.clone(),
self.pager.clone(),
Rc::downgrade(self),
&syms,
QueryMode::Explain,
cmd.into(),
)?;
program.explain();
Ok(None)
let stmt = Statement::new(
program.into(),
self._db.mv_store.clone(),
self.pager.clone(),
);
Ok(Some(stmt))
}
Cmd::ExplainQueryPlan(stmt) => {
match stmt {
@ -386,7 +375,7 @@ impl Connection {
.ok_or(LimboError::SchemaLocked)?
.deref(),
)?;
println!("{}", plan);
let _ = std::io::stdout().write_all(plan.to_string().as_bytes());
}
_ => todo!(),
}
@ -421,7 +410,7 @@ impl Connection {
&syms,
QueryMode::Explain,
)?;
program.explain();
let _ = std::io::stdout().write_all(program.explain().as_bytes());
}
Cmd::ExplainQueryPlan(_stmt) => todo!(),
Cmd::Stmt(stmt) => {
@ -601,6 +590,10 @@ impl Statement {
pub fn row(&self) -> Option<&Row> {
self.state.result_row.as_ref()
}
pub fn explain(&self) -> String {
self.program.explain()
}
}
pub type Row = types::Record;