Skip to content

Commit 5eebc05

Browse files
committed
sqlite: use Arc instead of Copy-able StatementHandle
This guarantees that StatementHandle is never used after calling `sqlite3_finalize`. Now `sqlite3_finalize` is only called when StatementHandle is dropped.
1 parent 5a8418e commit 5eebc05

File tree

6 files changed

+47
-38
lines changed

6 files changed

+47
-38
lines changed

sqlx-core/src/sqlite/connection/describe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub(super) fn describe<'c: 'e, 'q: 'e, 'e>(
6464
// fallback to [column_decltype]
6565
if !stepped && stmt.read_only() {
6666
stepped = true;
67-
let _ = conn.worker.step(*stmt).await;
67+
let _ = conn.worker.step(stmt).await;
6868
}
6969

7070
let mut ty = stmt.column_type_info(col);

sqlx-core/src/sqlite/connection/executor.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,14 @@ fn bind(
6262
/// A structure holding sqlite statement handle and resetting the
6363
/// statement when it is dropped.
6464
struct StatementResetter {
65-
handle: StatementHandle,
65+
handle: Arc<StatementHandle>,
6666
}
6767

6868
impl StatementResetter {
69-
fn new(handle: StatementHandle) -> Self {
70-
Self { handle }
69+
fn new(handle: &Arc<StatementHandle>) -> Self {
70+
Self {
71+
handle: Arc::clone(handle),
72+
}
7173
}
7274
}
7375

@@ -113,7 +115,7 @@ impl<'c> Executor<'c> for &'c mut SqliteConnection {
113115
// is dropped. `StatementResetter` will reliably reset the
114116
// statement even if the stream returned from `fetch_many`
115117
// is dropped early.
116-
let _resetter = StatementResetter::new(*stmt);
118+
let _resetter = StatementResetter::new(stmt);
117119

118120
// bind values to the statement
119121
num_arguments += bind(stmt, &arguments, num_arguments)?;
@@ -125,7 +127,7 @@ impl<'c> Executor<'c> for &'c mut SqliteConnection {
125127

126128
// invoke [sqlite3_step] on the dedicated worker thread
127129
// this will move us forward one row or finish the statement
128-
let s = worker.step(*stmt).await?;
130+
let s = worker.step(stmt).await?;
129131

130132
match s {
131133
Either::Left(changes) => {
@@ -145,7 +147,7 @@ impl<'c> Executor<'c> for &'c mut SqliteConnection {
145147

146148
Either::Right(()) => {
147149
let (row, weak_values_ref) = SqliteRow::current(
148-
*stmt,
150+
&stmt,
149151
columns,
150152
column_names
151153
);
@@ -205,12 +207,12 @@ impl<'c> Executor<'c> for &'c mut SqliteConnection {
205207

206208
// invoke [sqlite3_step] on the dedicated worker thread
207209
// this will move us forward one row or finish the statement
208-
match worker.step(*stmt).await? {
210+
match worker.step(stmt).await? {
209211
Either::Left(_) => (),
210212

211213
Either::Right(()) => {
212214
let (row, weak_values_ref) =
213-
SqliteRow::current(*stmt, columns, column_names);
215+
SqliteRow::current(stmt, columns, column_names);
214216

215217
*last_row_values = Some(weak_values_ref);
216218

sqlx-core/src/sqlite/row.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub struct SqliteRow {
2323
// IF the user drops the Row before iterating the stream (so
2424
// nearly all of our internal stream iterators), the executor moves on; otherwise,
2525
// it actually inflates this row with a list of owned sqlite3 values.
26-
pub(crate) statement: StatementHandle,
26+
pub(crate) statement: Arc<StatementHandle>,
2727

2828
pub(crate) values: Arc<AtomicPtr<SqliteValue>>,
2929
pub(crate) num_values: usize,
@@ -48,7 +48,7 @@ impl SqliteRow {
4848
// returns a weak reference to an atomic list where the executor should inflate if its going
4949
// to increment the statement with [step]
5050
pub(crate) fn current(
51-
statement: StatementHandle,
51+
statement: &Arc<StatementHandle>,
5252
columns: &Arc<Vec<SqliteColumn>>,
5353
column_names: &Arc<HashMap<UStr, usize>>,
5454
) -> (Self, Weak<AtomicPtr<SqliteValue>>) {
@@ -57,7 +57,7 @@ impl SqliteRow {
5757
let size = statement.column_count();
5858

5959
let row = Self {
60-
statement,
60+
statement: Arc::clone(statement),
6161
values,
6262
num_values: size,
6363
columns: Arc::clone(columns),

sqlx-core/src/sqlite/statement/handle.rs

+21-4
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ use libsqlite3_sys::{
1313
sqlite3_column_count, sqlite3_column_database_name, sqlite3_column_decltype,
1414
sqlite3_column_double, sqlite3_column_int, sqlite3_column_int64, sqlite3_column_name,
1515
sqlite3_column_origin_name, sqlite3_column_table_name, sqlite3_column_type,
16-
sqlite3_column_value, sqlite3_db_handle, sqlite3_reset, sqlite3_sql, sqlite3_stmt,
17-
sqlite3_stmt_readonly, sqlite3_table_column_metadata, sqlite3_value, SQLITE_OK,
18-
SQLITE_TRANSIENT, SQLITE_UTF8,
16+
sqlite3_column_value, sqlite3_db_handle, sqlite3_finalize, sqlite3_reset, sqlite3_sql,
17+
sqlite3_stmt, sqlite3_stmt_readonly, sqlite3_table_column_metadata, sqlite3_value,
18+
SQLITE_MISUSE, SQLITE_OK, SQLITE_TRANSIENT, SQLITE_UTF8,
1919
};
2020

2121
use crate::error::{BoxDynError, Error};
2222
use crate::sqlite::type_info::DataType;
2323
use crate::sqlite::{SqliteError, SqliteTypeInfo};
2424

25-
#[derive(Debug, Copy, Clone)]
25+
#[derive(Debug)]
2626
pub(crate) struct StatementHandle(pub(super) NonNull<sqlite3_stmt>);
2727

2828
// access to SQLite3 statement handles are safe to send and share between threads
@@ -284,3 +284,20 @@ impl StatementHandle {
284284
unsafe { sqlite3_reset(self.0.as_ptr()) };
285285
}
286286
}
287+
impl Drop for StatementHandle {
288+
fn drop(&mut self) {
289+
unsafe {
290+
// https://sqlite.org/c3ref/finalize.html
291+
let status = sqlite3_finalize(self.0.as_ptr());
292+
if status == SQLITE_MISUSE {
293+
// Panic in case of detected misuse of SQLite API.
294+
//
295+
// sqlite3_finalize returns it at least in the
296+
// case of detected double free, i.e. calling
297+
// sqlite3_finalize on already finalized
298+
// statement.
299+
panic!("Detected sqlite3_finalize misuse.");
300+
}
301+
}
302+
}
303+
}

sqlx-core/src/sqlite/statement/virtual.rs

+5-19
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use crate::sqlite::{SqliteColumn, SqliteError, SqliteRow, SqliteValue};
88
use crate::HashMap;
99
use bytes::{Buf, Bytes};
1010
use libsqlite3_sys::{
11-
sqlite3, sqlite3_clear_bindings, sqlite3_finalize, sqlite3_prepare_v3, sqlite3_reset,
12-
sqlite3_stmt, SQLITE_MISUSE, SQLITE_OK, SQLITE_PREPARE_PERSISTENT,
11+
sqlite3, sqlite3_clear_bindings, sqlite3_prepare_v3, sqlite3_reset, sqlite3_stmt, SQLITE_OK,
12+
SQLITE_PREPARE_PERSISTENT,
1313
};
1414
use smallvec::SmallVec;
1515
use std::i32;
@@ -31,7 +31,7 @@ pub(crate) struct VirtualStatement {
3131
// underlying sqlite handles for each inner statement
3232
// a SQL query string in SQLite is broken up into N statements
3333
// we use a [`SmallVec`] to optimize for the most likely case of a single statement
34-
pub(crate) handles: SmallVec<[StatementHandle; 1]>,
34+
pub(crate) handles: SmallVec<[Arc<StatementHandle>; 1]>,
3535

3636
// each set of columns
3737
pub(crate) columns: SmallVec<[Arc<Vec<SqliteColumn>>; 1]>,
@@ -126,7 +126,7 @@ impl VirtualStatement {
126126
conn: &mut ConnectionHandle,
127127
) -> Result<
128128
Option<(
129-
&StatementHandle,
129+
&Arc<StatementHandle>,
130130
&mut Arc<Vec<SqliteColumn>>,
131131
&Arc<HashMap<UStr, usize>>,
132132
&mut Option<Weak<AtomicPtr<SqliteValue>>>,
@@ -159,7 +159,7 @@ impl VirtualStatement {
159159
column_names.insert(name, i);
160160
}
161161

162-
self.handles.push(statement);
162+
self.handles.push(Arc::new(statement));
163163
self.columns.push(Arc::new(columns));
164164
self.column_names.push(Arc::new(column_names));
165165
self.last_row_values.push(None);
@@ -198,20 +198,6 @@ impl Drop for VirtualStatement {
198198
fn drop(&mut self) {
199199
for (i, handle) in self.handles.drain(..).enumerate() {
200200
SqliteRow::inflate_if_needed(&handle, &self.columns[i], self.last_row_values[i].take());
201-
202-
unsafe {
203-
// https://sqlite.org/c3ref/finalize.html
204-
let status = sqlite3_finalize(handle.0.as_ptr());
205-
if status == SQLITE_MISUSE {
206-
// Panic in case of detected misuse of SQLite API.
207-
//
208-
// sqlite3_finalize returns it at least in the
209-
// case of detected double free, i.e. calling
210-
// sqlite3_finalize on already finalized
211-
// statement.
212-
panic!("Detected sqlite3_finalize misuse.");
213-
}
214-
}
215201
}
216202
}
217203
}

sqlx-core/src/sqlite/statement/worker.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crossbeam_channel::{unbounded, Sender};
44
use either::Either;
55
use futures_channel::oneshot;
66
use libsqlite3_sys::{sqlite3_step, SQLITE_DONE, SQLITE_ROW};
7+
use std::sync::Arc;
78
use std::thread;
89

910
// Each SQLite connection has a dedicated thread.
@@ -18,7 +19,7 @@ pub(crate) struct StatementWorker {
1819

1920
enum StatementWorkerCommand {
2021
Step {
21-
statement: StatementHandle,
22+
statement: Arc<StatementHandle>,
2223
tx: oneshot::Sender<Result<Either<u64, ()>, Error>>,
2324
},
2425
}
@@ -50,12 +51,15 @@ impl StatementWorker {
5051

5152
pub(crate) async fn step(
5253
&mut self,
53-
statement: StatementHandle,
54+
statement: &Arc<StatementHandle>,
5455
) -> Result<Either<u64, ()>, Error> {
5556
let (tx, rx) = oneshot::channel();
5657

5758
self.tx
58-
.send(StatementWorkerCommand::Step { statement, tx })
59+
.send(StatementWorkerCommand::Step {
60+
statement: Arc::clone(statement),
61+
tx,
62+
})
5963
.map_err(|_| Error::WorkerCrashed)?;
6064

6165
rx.await.map_err(|_| Error::WorkerCrashed)?

0 commit comments

Comments
 (0)