mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-03 00:14:21 +01:00
Merge 'emit proper column information for explain prepared statements' from Nikita Sivukhin
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #3612
This commit is contained in:
@@ -1,6 +1,97 @@
|
||||
import { expect, test } from 'vitest'
|
||||
import { connect, Database } from './promise-default.js'
|
||||
|
||||
test('explain', async () => {
|
||||
const db = await connect(":memory:");
|
||||
const stmt = db.prepare("EXPLAIN SELECT 1");
|
||||
expect(stmt.columns()).toEqual([
|
||||
{
|
||||
"name": "addr",
|
||||
"type": "INTEGER",
|
||||
},
|
||||
{
|
||||
"name": "opcode",
|
||||
"type": "TEXT",
|
||||
},
|
||||
{
|
||||
"name": "p1",
|
||||
"type": "INTEGER",
|
||||
},
|
||||
{
|
||||
"name": "p2",
|
||||
"type": "INTEGER",
|
||||
},
|
||||
{
|
||||
"name": "p3",
|
||||
"type": "INTEGER",
|
||||
},
|
||||
{
|
||||
"name": "p4",
|
||||
"type": "INTEGER",
|
||||
},
|
||||
{
|
||||
"name": "p5",
|
||||
"type": "INTEGER",
|
||||
},
|
||||
{
|
||||
"name": "comment",
|
||||
"type": "TEXT",
|
||||
},
|
||||
].map(x => ({ ...x, column: null, database: null, table: null })));
|
||||
expect(await stmt.all()).toEqual([
|
||||
{
|
||||
"addr": 0,
|
||||
"comment": "Start at 3",
|
||||
"opcode": "Init",
|
||||
"p1": 0,
|
||||
"p2": 3,
|
||||
"p3": 0,
|
||||
"p4": "",
|
||||
"p5": 0,
|
||||
},
|
||||
{
|
||||
"addr": 1,
|
||||
"comment": "output=r[1]",
|
||||
"opcode": "ResultRow",
|
||||
"p1": 1,
|
||||
"p2": 1,
|
||||
"p3": 0,
|
||||
"p4": "",
|
||||
"p5": 0,
|
||||
},
|
||||
{
|
||||
"addr": 2,
|
||||
"comment": "",
|
||||
"opcode": "Halt",
|
||||
"p1": 0,
|
||||
"p2": 0,
|
||||
"p3": 0,
|
||||
"p4": "",
|
||||
"p5": 0,
|
||||
},
|
||||
{
|
||||
"addr": 3,
|
||||
"comment": "r[1]=1",
|
||||
"opcode": "Integer",
|
||||
"p1": 1,
|
||||
"p2": 1,
|
||||
"p3": 0,
|
||||
"p4": "",
|
||||
"p5": 0,
|
||||
},
|
||||
{
|
||||
"addr": 4,
|
||||
"comment": "",
|
||||
"opcode": "Goto",
|
||||
"p1": 0,
|
||||
"p2": 1,
|
||||
"p3": 0,
|
||||
"p4": "",
|
||||
"p5": 0,
|
||||
},
|
||||
]);
|
||||
})
|
||||
|
||||
test('in-memory db', async () => {
|
||||
const db = await connect(":memory:");
|
||||
await db.exec("CREATE TABLE t(x)");
|
||||
@@ -10,6 +101,7 @@ test('in-memory db', async () => {
|
||||
expect(rows).toEqual([{ x: 1 }, { x: 3 }]);
|
||||
})
|
||||
|
||||
|
||||
test('implicit connect', async () => {
|
||||
const db = new Database(':memory:');
|
||||
const defer = db.prepare("SELECT * FROM t");
|
||||
|
||||
31
core/lib.rs
31
core/lib.rs
@@ -46,6 +46,7 @@ use crate::translate::pragma::TURSO_CDC_DEFAULT_TABLE_NAME;
|
||||
use crate::types::{WalFrameInfo, WalState};
|
||||
#[cfg(feature = "fs")]
|
||||
use crate::util::{OpenMode, OpenOptions};
|
||||
use crate::vdbe::explain::{EXPLAIN_COLUMNS_TYPE, EXPLAIN_QUERY_PLAN_COLUMNS_TYPE};
|
||||
use crate::vdbe::metrics::ConnectionMetrics;
|
||||
use crate::vtab::VirtualTable;
|
||||
use crate::{incremental::view::AllViewsTxState, translate::emitter::TransactionMode};
|
||||
@@ -2667,6 +2668,17 @@ impl Statement {
|
||||
}
|
||||
|
||||
pub fn get_column_name(&self, idx: usize) -> Cow<'_, str> {
|
||||
if self.query_mode == QueryMode::Explain {
|
||||
return Cow::Owned(EXPLAIN_COLUMNS.get(idx).expect("No column").to_string());
|
||||
}
|
||||
if self.query_mode == QueryMode::ExplainQueryPlan {
|
||||
return Cow::Owned(
|
||||
EXPLAIN_QUERY_PLAN_COLUMNS
|
||||
.get(idx)
|
||||
.expect("No column")
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
match self.query_mode {
|
||||
QueryMode::Normal => {
|
||||
let column = &self.program.result_columns.get(idx).expect("No column");
|
||||
@@ -2685,6 +2697,9 @@ impl Statement {
|
||||
}
|
||||
|
||||
pub fn get_column_table_name(&self, idx: usize) -> Option<Cow<'_, str>> {
|
||||
if self.query_mode == QueryMode::Explain || self.query_mode == QueryMode::ExplainQueryPlan {
|
||||
return None;
|
||||
}
|
||||
let column = &self.program.result_columns.get(idx).expect("No column");
|
||||
match &column.expr {
|
||||
turso_parser::ast::Expr::Column { table, .. } => self
|
||||
@@ -2697,6 +2712,22 @@ impl Statement {
|
||||
}
|
||||
|
||||
pub fn get_column_type(&self, idx: usize) -> Option<String> {
|
||||
if self.query_mode == QueryMode::Explain {
|
||||
return Some(
|
||||
EXPLAIN_COLUMNS_TYPE
|
||||
.get(idx)
|
||||
.expect("No column")
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
if self.query_mode == QueryMode::ExplainQueryPlan {
|
||||
return Some(
|
||||
EXPLAIN_QUERY_PLAN_COLUMNS_TYPE
|
||||
.get(idx)
|
||||
.expect("No column")
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
let column = &self.program.result_columns.get(idx).expect("No column");
|
||||
match &column.expr {
|
||||
turso_parser::ast::Expr::Column {
|
||||
|
||||
@@ -6,7 +6,11 @@ use super::{Insn, InsnReference, Program, Value};
|
||||
use crate::function::{Func, ScalarFunc};
|
||||
|
||||
pub const EXPLAIN_COLUMNS: [&str; 8] = ["addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment"];
|
||||
pub const EXPLAIN_COLUMNS_TYPE: [&str; 8] = [
|
||||
"INTEGER", "TEXT", "INTEGER", "INTEGER", "INTEGER", "INTEGER", "INTEGER", "TEXT",
|
||||
];
|
||||
pub const EXPLAIN_QUERY_PLAN_COLUMNS: [&str; 4] = ["id", "parent", "notused", "detail"];
|
||||
pub const EXPLAIN_QUERY_PLAN_COLUMNS_TYPE: [&str; 4] = ["INTEGER", "INTEGER", "INTEGER", "TEXT"];
|
||||
|
||||
pub fn insn_to_row(
|
||||
program: &Program,
|
||||
|
||||
Reference in New Issue
Block a user