mirror of
https://github.com/launchbadge/sqlx.git
synced 2026-04-19 21:25:46 +00:00
Fix compile time verification performance regression for sqlite (#1946)
* add instruction, register, and cursor state memorization * fix: fixed formating
This commit is contained in:
committed by
Austin Bonander
parent
d5b8c66e24
commit
75a34951ab
@@ -4,6 +4,7 @@ use crate::sqlite::connection::{execute, ConnectionState};
|
|||||||
use crate::sqlite::type_info::DataType;
|
use crate::sqlite::type_info::DataType;
|
||||||
use crate::sqlite::SqliteTypeInfo;
|
use crate::sqlite::SqliteTypeInfo;
|
||||||
use crate::HashMap;
|
use crate::HashMap;
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
// affinity
|
// affinity
|
||||||
@@ -121,7 +122,7 @@ const OP_CONCAT: &str = "Concat";
|
|||||||
const OP_RESULT_ROW: &str = "ResultRow";
|
const OP_RESULT_ROW: &str = "ResultRow";
|
||||||
const OP_HALT: &str = "Halt";
|
const OP_HALT: &str = "Halt";
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
struct ColumnType {
|
struct ColumnType {
|
||||||
pub datatype: DataType,
|
pub datatype: DataType,
|
||||||
pub nullable: Option<bool>,
|
pub nullable: Option<bool>,
|
||||||
@@ -145,7 +146,7 @@ impl ColumnType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
enum RegDataType {
|
enum RegDataType {
|
||||||
Single(ColumnType),
|
Single(ColumnType),
|
||||||
Record(Vec<ColumnType>),
|
Record(Vec<ColumnType>),
|
||||||
@@ -341,6 +342,49 @@ struct QueryState {
|
|||||||
pub result: Option<Vec<(Option<SqliteTypeInfo>, Option<bool>)>>,
|
pub result: Option<Vec<(Option<SqliteTypeInfo>, Option<bool>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq)]
|
||||||
|
struct BranchStateHash {
|
||||||
|
instruction: usize,
|
||||||
|
registers: Vec<(i64, RegDataType)>,
|
||||||
|
cursors: Vec<(i64, i64, Option<ColumnType>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// Opcode Reference: https://sqlite.org/opcode.html
|
||||||
pub(super) fn explain(
|
pub(super) fn explain(
|
||||||
conn: &mut ConnectionState,
|
conn: &mut ConnectionState,
|
||||||
@@ -366,6 +410,8 @@ pub(super) fn explain(
|
|||||||
result: None,
|
result: None,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
let mut visited_branch_state: HashSet<BranchStateHash> = HashSet::new();
|
||||||
|
|
||||||
let mut result_states = Vec::new();
|
let mut result_states = Vec::new();
|
||||||
|
|
||||||
while let Some(mut state) = states.pop() {
|
while let Some(mut state) = states.pop() {
|
||||||
@@ -407,7 +453,12 @@ pub(super) fn explain(
|
|||||||
|
|
||||||
let mut branch_state = state.clone();
|
let mut branch_state = state.clone();
|
||||||
branch_state.program_i = p2 as usize;
|
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;
|
state.program_i += 1;
|
||||||
continue;
|
continue;
|
||||||
@@ -520,15 +571,27 @@ pub(super) fn explain(
|
|||||||
|
|
||||||
let mut branch_state = state.clone();
|
let mut branch_state = state.clone();
|
||||||
branch_state.program_i = p1 as usize;
|
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();
|
let mut branch_state = state.clone();
|
||||||
branch_state.program_i = p2 as usize;
|
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();
|
let mut branch_state = state.clone();
|
||||||
branch_state.program_i = p3 as usize;
|
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 => {
|
OP_COLUMN => {
|
||||||
|
|||||||
Reference in New Issue
Block a user