on reprepare create new state with updated number of cursors and

registers, so that the Program insns are in sync with ProgramState
This commit is contained in:
pedrocarlo
2025-09-10 15:49:42 -03:00
parent 1559cd127e
commit 6264d694d5
6 changed files with 147 additions and 5 deletions

3
.gitignore vendored
View File

@@ -44,4 +44,5 @@ profile.json.gz
simulator-output/
&1
bisected.sql
bisected.sql
*.log

2
Cargo.lock generated
View File

@@ -4424,7 +4424,7 @@ dependencies = [
[[package]]
name = "turso_whopper"
version = "0.1.5"
version = "0.2.0-pre.1"
dependencies = [
"anyhow",
"clap",

View File

@@ -2078,6 +2078,8 @@ pub struct Statement {
/// indicates if the statement is a NORMAL/EXPLAIN/EXPLAIN QUERY PLAN
query_mode: QueryMode,
/// Flag to show if the statement ran to completion
done: bool,
}
impl Statement {
@@ -2103,6 +2105,7 @@ impl Statement {
pager,
accesses_db,
query_mode,
done: false,
}
}
pub fn get_query_mode(&self) -> QueryMode {
@@ -2158,6 +2161,7 @@ impl Statement {
if matches!(res, Ok(StepResult::Done)) {
let mut conn_metrics = self.program.connection.metrics.borrow_mut();
conn_metrics.record_statement(self.state.metrics.clone());
self.done = true;
}
res
@@ -2219,7 +2223,8 @@ impl Statement {
};
// Save parameters before they are reset
let parameters = std::mem::take(&mut self.state.parameters);
self.reset();
self.state =
vdbe::ProgramState::new(self.program.max_registers, self.program.cursor_ref.len());
// Load the parameters back into the state
self.state.parameters = parameters;
Ok(())
@@ -2320,11 +2325,20 @@ impl Statement {
pub fn reset(&mut self) {
self.state.reset();
self.done = false;
}
pub fn row(&self) -> Option<&Row> {
self.state.result_row.as_ref()
}
pub fn get_sql(&self) -> &str {
&self.program.sql
}
pub fn is_done(&self) -> bool {
self.done
}
}
pub type Row = vdbe::Row;

View File

@@ -2338,6 +2338,18 @@ pub enum Cursor {
MaterializedView(Box<crate::incremental::cursor::MaterializedViewCursor>),
}
impl Debug for Cursor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BTree(..) => f.debug_tuple("BTree").finish(),
Self::Pseudo(..) => f.debug_tuple("Pseudo").finish(),
Self::Sorter(..) => f.debug_tuple("Sorter").finish(),
Self::Virtual(..) => f.debug_tuple("Virtual").finish(),
Self::MaterializedView(..) => f.debug_tuple("MaterializedView").finish(),
}
}
}
impl Cursor {
pub fn new_btree(cursor: BTreeCursor) -> Self {
Self::BTree(Box::new(cursor))

View File

@@ -387,7 +387,29 @@ impl ProgramState {
self.parameters.clear();
self.current_collation = None;
#[cfg(feature = "json")]
self.json_cache.clear()
self.json_cache.clear();
// Reset state machines
self.op_delete_state = OpDeleteState {
sub_state: OpDeleteSubState::MaybeCaptureRecord,
deleted_record: None,
};
self.op_idx_delete_state = None;
self.op_integrity_check_state = OpIntegrityCheckState::Start;
self.metrics = StatementMetrics::new();
self.op_open_ephemeral_state = OpOpenEphemeralState::Start;
self.op_new_rowid_state = OpNewRowidState::Start;
self.op_idx_insert_state = OpIdxInsertState::MaybeSeek;
self.op_insert_state = OpInsertState {
sub_state: OpInsertSubState::MaybeCaptureRecord,
old_record: None,
};
self.op_no_conflict_state = OpNoConflictState::Start;
self.seek_state = OpSeekState::Start;
self.current_collation = None;
self.op_column_state = OpColumnState::Start;
self.op_row_id_state = OpRowIdState::Start;
self.view_delta_state = ViewDeltaCommitState::NotStarted;
}
pub fn get_cursor(&mut self, cursor_id: CursorID) -> &mut Cursor {

View File

@@ -1,6 +1,6 @@
use std::sync::{atomic::AtomicUsize, Arc};
use turso_core::StepResult;
use turso_core::{Statement, StepResult};
use crate::common::{maybe_setup_tracing, TempDatabase};
@@ -234,3 +234,96 @@ fn test_schema_reprepare_write() {
}
}
}
fn advance(stmt: &mut Statement) -> anyhow::Result<()> {
stmt.step()?;
stmt.run_once()?;
Ok(())
}
/// Regression test detected by whopper
#[test]
fn test_interleaved_transactions() -> anyhow::Result<()> {
maybe_setup_tracing();
let tmp_db = TempDatabase::new_empty(true);
{
let bootstrap_conn = tmp_db.connect_limbo();
bootstrap_conn.execute("CREATE TABLE table_0 (id INTEGER,col_1 REAL,col_2 INTEGER,col_3 REAL,col_4 TEXT,col_5 REAL,col_6 TEXT)")?;
bootstrap_conn.execute("CREATE INDEX idx_table_0_0 ON table_0 (col_4 ASC)")?;
bootstrap_conn.execute("CREATE INDEX idx_table_0_1 ON table_0 (id DESC)")?;
bootstrap_conn.execute("CREATE INDEX idx_table_0_2 ON table_0 (col_5 DESC)")?;
bootstrap_conn.close()?;
}
let conn = [
tmp_db.connect_limbo(),
tmp_db.connect_limbo(),
tmp_db.connect_limbo(),
tmp_db.connect_limbo(),
];
let mut statement2 = conn[2].prepare("BEGIN")?;
let mut statement0 = conn[0].prepare("BEGIN")?;
let mut statement1 = conn[1].prepare("BEGIN")?;
advance(&mut statement2)?;
let mut statement2 = conn[2].prepare("DELETE FROM table_0 WHERE (TRUE)")?;
advance(&mut statement0)?;
let mut statement0 = conn[0].prepare("COMMIT")?;
advance(&mut statement1)?;
let mut statement1 = conn[1].prepare("UPDATE table_0 SET col_5 = -2926216022.864461, col_1 = 1136343846.3760414, col_2 = 1260332354248861058, col_6 = 'breathtaking_wallace', col_3 = -8354252674.968108, id = -2763965266862900284 WHERE (TRUE)")?;
advance(&mut statement2)?;
advance(&mut statement0)?;
advance(&mut statement1)?;
advance(&mut statement2)?;
let mut statement2 = conn[2].prepare("COMMIT")?;
advance(&mut statement1)?;
advance(&mut statement2)?;
let mut statement2 = conn[2].prepare("BEGIN")?;
let mut statement3 = conn[3].prepare("BEGIN")?;
advance(&mut statement1)?;
advance(&mut statement2)?;
let mut statement2 = conn[2].prepare("INSERT INTO table_0 VALUES (3433031730186055493, -9049649117.499245, 377748201198469116, -303828055.307354, 'hardworking_pinotnoir', 3130880977.346573, 'dazzling_identity'), (4047491512698975530, -6415241771.805258, 8252804953477887816, 6468710871.6649, 'diplomatic_karamazov', 590358226.8343716, 'hilarious_strasbourg'), (2865599543545078376, 84894401.22016525, 9113810426850381627, -1136160051.7521439, 'funny_benton', 9522389352.598354, 'magnificent_french'), (-157899885850804353, -303833796.57147026, 486259919370287064, -9427424128.005714, 'considerate_diamant', -3105334243.936157, 'kind_walker'), (8502247374804763489, -2126532888.2616653, 5690470012873526939, 4011656749.2326107, 'kind_ladrido', 1381034902.7760563, 'humorous_crane'), (2487742055507017334, -5830452441.986847, 3661939929057695925, -6299976423.211256, 'adaptable_raevsky', -7871748970.666381, 'technological_bataille'), (-5348095239593101865, -998225440.4524403, 5195262288395229508, -8305444803.975374, 'upbeat_courtney', -3943473497.4281626, 'imaginative_arrigoni'), (-6470080787150464674, -5833281407.383408, 5877012236478010308, 3023123550.254177, 'fearless_cairo', -141073531.91679573, 'generous_university')")?;
advance(&mut statement3)?;
let mut statement3 = conn[3].prepare("INSERT INTO table_0 VALUES (-7468459471409934075, 8179435779.870651, -7868006515434924912, -5415470506.527203, 'affectionate_n1x', -88866295.57206345, 'agreeable_treloar'), (3000445982321368777, 3099814982.0727863, -5101787605795972474, -925278326.7265358, 'giving_individualiste', -6553332857.366568, 'brave_patrizia'), (406163996859206098, -3340292138.289094, -5058217201699339610, 2605267874.8582096, 'fabulous_burnett', -4601912326.914466, 'super_jedi'), (6398781934600428549, -6770226564.882048, -2332649333251794167, 6904161964.055864, 'shining_sergent', -4779129294.073781, 'hardworking_beggar'), (1530150677936272307, -8683321096.443897, -2211014401610293017, 2417417840.8996468, 'magnificent_datacide', -2218929107.793541, 'ravishing_nw'), (8028216547992752413, -8876487798.088352, 8974386493479719872, -6723037189.199554, 'glimmering_murray', -1973499548.0633707, 'spectacular_fitzpatrick')")?;
advance(&mut statement1)?;
let mut statement1 = conn[1].prepare(
"CREATE INDEX idx_table_0_persiste ON table_0 (col_2 ASC, col_6 ASC, col_3 ASC)",
)?;
advance(&mut statement2)?;
advance(&mut statement3)?;
let mut statement0 = conn[0].prepare("BEGIN")?;
advance(&mut statement1)?;
assert!(statement1.is_done());
let mut statement1 = conn[1].prepare("COMMIT")?;
advance(&mut statement2)?;
advance(&mut statement0)?;
let mut _statement0 = conn[0].prepare("UPDATE table_0 SET col_3 = 7634893024.5729065, col_6 = 'glimmering_besnard', col_1 = 9240915430.267292, col_4 = 'efficient_mekan' WHERE (TRUE)")?;
advance(&mut statement1)?;
advance(&mut statement2)?;
Ok(())
}