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

Commit 96109d3

Browse files
committed
forbid savepoints in legacy http
1 parent b5850bb commit 96109d3

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

sqld/src/connection/libsql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ impl<W: WalHook> Connection<W> {
531531
let blocked = match query.stmt.kind {
532532
StmtKind::Read | StmtKind::TxnBegin | StmtKind::Other => config.block_reads,
533533
StmtKind::Write => config.block_reads || config.block_writes,
534-
StmtKind::TxnEnd => false,
534+
StmtKind::TxnEnd | StmtKind::Release | StmtKind::Savepoint => false,
535535
};
536536
if blocked {
537537
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: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@ impl StmtKind {
5353
Cmd::Explain(_) => Some(Self::Other),
5454
Cmd::ExplainQueryPlan(_) => Some(Self::Other),
5555
Cmd::Stmt(Stmt::Begin { .. }) => Some(Self::TxnBegin),
56-
Cmd::Stmt(Stmt::Commit { .. } | Stmt::Rollback { savepoint_name: None, .. }) => Some(Self::TxnEnd),
56+
Cmd::Stmt(
57+
Stmt::Commit { .. }
58+
| Stmt::Rollback {
59+
savepoint_name: None,
60+
..
61+
},
62+
) => Some(Self::TxnEnd),
5763
Cmd::Stmt(
5864
Stmt::CreateVirtualTable { tbl_name, .. }
5965
| Stmt::CreateTable {
@@ -102,7 +108,11 @@ impl StmtKind {
102108
}) => Some(Self::Write),
103109
Cmd::Stmt(Stmt::DropView { .. }) => Some(Self::Write),
104110
Cmd::Stmt(Stmt::Savepoint(_)) => Some(Self::Savepoint),
105-
Cmd::Stmt(Stmt::Release(_)) | Cmd::Stmt(Stmt::Rollback { savepoint_name: Some(_) , ..}) => Some(Self::Release),
111+
Cmd::Stmt(Stmt::Release(_))
112+
| Cmd::Stmt(Stmt::Rollback {
113+
savepoint_name: Some(_),
114+
..
115+
}) => Some(Self::Release),
106116
_ => None,
107117
}
108118
}
@@ -171,6 +181,22 @@ impl StmtKind {
171181
},
172182
}
173183
}
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+
}
174200
}
175201

176202
/// The state of a transaction for a series of statement
@@ -191,7 +217,8 @@ impl State {
191217
(State::Txn, StmtKind::TxnEnd) => State::Init,
192218
(state, StmtKind::Other | StmtKind::Write | StmtKind::Read) => state,
193219
(State::Invalid, _) => State::Invalid,
194-
(State::Init, StmtKind::TxnBegin | ) => State::Txn,
220+
(State::Init, StmtKind::TxnBegin) => State::Txn,
221+
_ => State::Invalid,
195222
};
196223
}
197224

@@ -280,7 +307,11 @@ impl Statement {
280307
pub fn is_read_only(&self) -> bool {
281308
matches!(
282309
self.kind,
283-
StmtKind::Read | StmtKind::TxnEnd | StmtKind::TxnBegin
310+
StmtKind::Read
311+
| StmtKind::TxnEnd
312+
| StmtKind::TxnBegin
313+
| StmtKind::Release
314+
| StmtKind::Savepoint
284315
)
285316
}
286317
}

0 commit comments

Comments
 (0)