Skip to content

Commit dca2363

Browse files
committed
fix invalid state in transaction
1 parent d7fc437 commit dca2363

1 file changed

Lines changed: 63 additions & 1 deletion

File tree

libsql/src/sync/connection.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::{
33
hrana::{connection::HttpConnection, hyper::HttpSender},
44
local::{self, impls::LibsqlStmt},
55
params::Params,
6+
parser,
67
replication::connection::State,
78
sync::SyncContext,
89
BatchRows, Error, Result, Statement, Transaction, TransactionBehavior,
@@ -33,7 +34,68 @@ impl SyncedConnection {
3334

3435
let mut state = self.state.lock().await;
3536

36-
crate::replication::connection::should_execute_local(&mut state, stmts.as_slice())
37+
if !self.remote.is_autocommit() {
38+
*state = State::Txn;
39+
}
40+
41+
{
42+
let predicted_end_state = {
43+
let mut state = state.clone();
44+
45+
stmts.iter().for_each(|parser::Statement { kind, .. }| {
46+
state = state.step(*kind);
47+
});
48+
49+
state
50+
};
51+
52+
dbg!((&state, sql, &predicted_end_state));
53+
54+
let should_execute_local = match (*state, predicted_end_state) {
55+
(State::Init, State::Init) => stmts.iter().all(parser::Statement::is_read_only),
56+
57+
(State::Init, State::TxnReadOnly) | (State::TxnReadOnly, State::TxnReadOnly) => {
58+
let is_read_only = stmts.iter().all(parser::Statement::is_read_only);
59+
60+
if !is_read_only {
61+
return Err(Error::Misuse(
62+
"Invalid write in a readonly transaction".into(),
63+
));
64+
}
65+
66+
*state = State::TxnReadOnly;
67+
true
68+
}
69+
70+
(State::TxnReadOnly, State::Init) => {
71+
let is_read_only = stmts.iter().all(parser::Statement::is_read_only);
72+
73+
if !is_read_only {
74+
return Err(Error::Misuse(
75+
"Invalid write in a readonly transaction".into(),
76+
));
77+
}
78+
79+
*state = State::Init;
80+
true
81+
}
82+
83+
(init, State::Invalid) => {
84+
let err = Err(Error::InvalidParserState(format!("{:?}", init)));
85+
86+
// Reset state always back to init so the user can start over
87+
*state = State::Init;
88+
89+
return err;
90+
}
91+
_ => {
92+
*state = predicted_end_state;
93+
false
94+
},
95+
};
96+
97+
Ok(should_execute_local)
98+
}
3799
}
38100
}
39101

0 commit comments

Comments
 (0)