Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit 42eabee

Browse files
authored
enable savepoint (#472)
* add savepoint and release stmt categories * forbid savepoints in legacy http
1 parent 5f27d9b commit 42eabee

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

sqld/src/connection/libsql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ impl<W: WalHook> Connection<W> {
535535
let blocked = match query.stmt.kind {
536536
StmtKind::Read | StmtKind::TxnBegin | StmtKind::Other => config.block_reads,
537537
StmtKind::Write => config.block_reads || config.block_writes,
538-
StmtKind::TxnEnd => false,
538+
StmtKind::TxnEnd | StmtKind::Release | StmtKind::Savepoint => false,
539539
};
540540
if blocked {
541541
return Err(Error::Blocked(config.block_reason.clone()));

sqld/src/http/user/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ fn parse_queries(queries: Vec<QueryObject>) -> crate::Result<Vec<Query>> {
9797
out.push(query);
9898
}
9999

100+
// It's too complicated to predict the state of a transaction with savepoints in legacy http,
101+
// forbid them instead.
102+
if out
103+
.iter()
104+
.any(|q| q.stmt.kind.is_release() || q.stmt.kind.is_release())
105+
{
106+
return Err(Error::QueryError(
107+
"savepoints are not supported in HTTP API, use hrana protocol instead".to_string(),
108+
));
109+
}
110+
100111
match predict_final_state(State::Init, out.iter().map(|q| &q.stmt)) {
101112
State::Txn => {
102113
return Err(Error::QueryError(

sqld/src/query_analysis.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub enum StmtKind {
2828
TxnEnd,
2929
Read,
3030
Write,
31+
Savepoint,
32+
Release,
3133
Other,
3234
}
3335

@@ -51,7 +53,13 @@ impl StmtKind {
5153
Cmd::Explain(_) => Some(Self::Other),
5254
Cmd::ExplainQueryPlan(_) => Some(Self::Other),
5355
Cmd::Stmt(Stmt::Begin { .. }) => Some(Self::TxnBegin),
54-
Cmd::Stmt(Stmt::Commit { .. } | Stmt::Rollback { .. }) => Some(Self::TxnEnd),
56+
Cmd::Stmt(
57+
Stmt::Commit { .. }
58+
| Stmt::Rollback {
59+
savepoint_name: None,
60+
..
61+
},
62+
) => Some(Self::TxnEnd),
5563
Cmd::Stmt(
5664
Stmt::CreateVirtualTable { tbl_name, .. }
5765
| Stmt::CreateTable {
@@ -99,6 +107,12 @@ impl StmtKind {
99107
temporary: false, ..
100108
}) => Some(Self::Write),
101109
Cmd::Stmt(Stmt::DropView { .. }) => Some(Self::Write),
110+
Cmd::Stmt(Stmt::Savepoint(_)) => Some(Self::Savepoint),
111+
Cmd::Stmt(Stmt::Release(_))
112+
| Cmd::Stmt(Stmt::Rollback {
113+
savepoint_name: Some(_),
114+
..
115+
}) => Some(Self::Release),
102116
_ => None,
103117
}
104118
}
@@ -167,6 +181,22 @@ impl StmtKind {
167181
},
168182
}
169183
}
184+
185+
/// Returns `true` if the stmt kind is [`Savepoint`].
186+
///
187+
/// [`Savepoint`]: StmtKind::Savepoint
188+
#[must_use]
189+
pub fn is_savepoint(&self) -> bool {
190+
matches!(self, Self::Savepoint)
191+
}
192+
193+
/// Returns `true` if the stmt kind is [`Release`].
194+
///
195+
/// [`Release`]: StmtKind::Release
196+
#[must_use]
197+
pub fn is_release(&self) -> bool {
198+
matches!(self, Self::Release)
199+
}
170200
}
171201

172202
/// The state of a transaction for a series of statement
@@ -188,6 +218,7 @@ impl State {
188218
(state, StmtKind::Other | StmtKind::Write | StmtKind::Read) => state,
189219
(State::Invalid, _) => State::Invalid,
190220
(State::Init, StmtKind::TxnBegin) => State::Txn,
221+
_ => State::Invalid,
191222
};
192223
}
193224

@@ -276,7 +307,11 @@ impl Statement {
276307
pub fn is_read_only(&self) -> bool {
277308
matches!(
278309
self.kind,
279-
StmtKind::Read | StmtKind::TxnEnd | StmtKind::TxnBegin
310+
StmtKind::Read
311+
| StmtKind::TxnEnd
312+
| StmtKind::TxnBegin
313+
| StmtKind::Release
314+
| StmtKind::Savepoint
280315
)
281316
}
282317
}

0 commit comments

Comments
 (0)