From 3d8feb1c8af3aa8b4b4a1a85c3d2497966e64f13 Mon Sep 17 00:00:00 2001 From: Lining Pan Date: Sat, 2 Jul 2022 16:43:38 -0400 Subject: [PATCH 1/2] add instruction, register, and cursor state memorization --- sqlx-core/src/sqlite/connection/explain.rs | 77 ++++++++++++++++++++-- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/sqlx-core/src/sqlite/connection/explain.rs b/sqlx-core/src/sqlite/connection/explain.rs index 101ca56a2b..0dca29ae2c 100644 --- a/sqlx-core/src/sqlite/connection/explain.rs +++ b/sqlx-core/src/sqlite/connection/explain.rs @@ -4,6 +4,7 @@ use crate::sqlite::connection::{execute, ConnectionState}; use crate::sqlite::type_info::DataType; use crate::sqlite::SqliteTypeInfo; use crate::HashMap; +use std::collections::HashSet; use std::str::from_utf8; // affinity @@ -117,7 +118,7 @@ const OP_CONCAT: &str = "Concat"; const OP_RESULT_ROW: &str = "ResultRow"; const OP_HALT: &str = "Halt"; -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] struct ColumnType { pub datatype: DataType, pub nullable: Option, @@ -141,7 +142,7 @@ impl ColumnType { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] enum RegDataType { Single(ColumnType), Record(Vec), @@ -178,7 +179,7 @@ impl RegDataType { } } -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, )] enum CursorDataType { Normal(HashMap), Pseudo(i64), @@ -323,6 +324,49 @@ struct QueryState { pub result: Option, Option)>>, } +#[derive(Debug, Hash, PartialEq, Eq)] +struct BranchStateHash { + instruction: usize, + registers: Vec<(i64, RegDataType)>, + cursors: Vec<(i64, i64, Option)>, +} + +impl BranchStateHash { + pub fn from_query_state(st: &QueryState) -> Self { + let mut reg = vec![]; + for (k, v) in &st.r { + reg.push((*k, v.clone())); + } + reg.sort_by_key(|v| v.0); + + let mut cur = vec![]; + for (k, v) in &st.p { + match v { + CursorDataType::Normal(hm) => { + for (i, col) in hm { + cur.push((*k, *i, Some(col.clone()))); + } + } + CursorDataType::Pseudo(i) => { + cur.push((*k, *i, None)); + } + } + } + cur.sort_by(|a, b| { + if a.0 == b.0 { + a.1.cmp(&b.1) + } else { + a.0.cmp(&b.0) + } + }); + Self { + instruction: st.program_i, + registers: reg, + cursors: cur, + } + } +} + // Opcode Reference: https://sqlite.org/opcode.html pub(super) fn explain( conn: &mut ConnectionState, @@ -348,6 +392,8 @@ pub(super) fn explain( result: None, }]; + let mut visited_branch_state: HashSet = HashSet::new(); + let mut result_states = Vec::new(); while let Some(mut state) = states.pop() { @@ -389,7 +435,12 @@ pub(super) fn explain( let mut branch_state = state.clone(); branch_state.program_i = p2 as usize; - states.push(branch_state); + + let bs_hash = BranchStateHash::from_query_state(&branch_state); + if !visited_branch_state.contains(&bs_hash) { + visited_branch_state.insert(bs_hash); + states.push(branch_state); + } state.program_i += 1; continue; @@ -473,15 +524,27 @@ pub(super) fn explain( let mut branch_state = state.clone(); branch_state.program_i = p1 as usize; - states.push(branch_state); + let bs_hash = BranchStateHash::from_query_state(&branch_state); + if !visited_branch_state.contains(&bs_hash) { + visited_branch_state.insert(bs_hash); + states.push(branch_state); + } let mut branch_state = state.clone(); branch_state.program_i = p2 as usize; - states.push(branch_state); + let bs_hash = BranchStateHash::from_query_state(&branch_state); + if !visited_branch_state.contains(&bs_hash) { + visited_branch_state.insert(bs_hash); + states.push(branch_state); + } let mut branch_state = state.clone(); branch_state.program_i = p3 as usize; - states.push(branch_state); + let bs_hash = BranchStateHash::from_query_state(&branch_state); + if !visited_branch_state.contains(&bs_hash) { + visited_branch_state.insert(bs_hash); + states.push(branch_state); + } } OP_COLUMN => { From 92289c087c36d343517209ccfbea44ed3e765998 Mon Sep 17 00:00:00 2001 From: Lining Pan Date: Mon, 1 Aug 2022 13:22:02 -0400 Subject: [PATCH 2/2] fix: fixed formating --- sqlx-core/src/sqlite/connection/explain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlx-core/src/sqlite/connection/explain.rs b/sqlx-core/src/sqlite/connection/explain.rs index 0dca29ae2c..097dcccf9f 100644 --- a/sqlx-core/src/sqlite/connection/explain.rs +++ b/sqlx-core/src/sqlite/connection/explain.rs @@ -179,7 +179,7 @@ impl RegDataType { } } -#[derive(Debug, Clone, Eq, PartialEq, )] +#[derive(Debug, Clone, Eq, PartialEq)] enum CursorDataType { Normal(HashMap), Pseudo(i64),