|
1 | 1 | #![allow(unused_assignments)] |
2 | | -use crate::SqliteTransactionMode; |
| 2 | +use std::sync::Arc; |
| 3 | + |
| 4 | +#[cfg(feature = "sqlx-dep")] |
| 5 | +use sqlx::TransactionManager; |
| 6 | +use std::sync::Mutex; |
| 7 | +use tracing::instrument; |
| 8 | + |
3 | 9 | use crate::{ |
4 | 10 | AccessMode, ConnectionTrait, DbBackend, DbErr, ExecResult, InnerConnection, IsolationLevel, |
5 | | - QueryResult, Statement, StreamTrait, TransactionOptions, TransactionSession, TransactionStream, |
6 | | - TransactionTrait, debug_print, error::*, |
| 11 | + QueryResult, SqliteTransactionMode, Statement, StreamTrait, TransactionOptions, |
| 12 | + TransactionSession, TransactionStream, TransactionTrait, debug_print, error::*, |
7 | 13 | }; |
8 | 14 | #[cfg(feature = "sqlx-dep")] |
9 | 15 | use crate::{sqlx_error_to_exec_err, sqlx_error_to_query_err}; |
10 | | -#[cfg(feature = "sqlx-dep")] |
11 | | -use sqlx::TransactionManager; |
12 | | -use std::sync::Arc; |
13 | | -use std::sync::Mutex; |
14 | | -use tracing::instrument; |
15 | 16 |
|
16 | 17 | /// Defines a database transaction, whether it is an open transaction and the type of |
17 | 18 | /// backend to use. |
@@ -83,22 +84,25 @@ impl DatabaseTransaction { |
83 | 84 | } |
84 | 85 | #[cfg(feature = "sqlx-sqlite")] |
85 | 86 | InnerConnection::Sqlite(c) => { |
86 | | - // in SQLite isolation level and access mode are global settings |
87 | 87 | crate::driver::sqlx_sqlite::set_transaction_config( |
88 | 88 | c, |
89 | 89 | isolation_level, |
90 | 90 | access_mode, |
91 | 91 | )?; |
92 | | - // TODO using this for beginning a nested transaction currently causes an error. Should we make it a warning instead? |
93 | | - let statement = sqlite_transaction_mode.map(|mode| { |
94 | | - std::borrow::Cow::from(format!("BEGIN {}", mode.sqlite_keyword())) |
95 | | - }); |
| 92 | + let depth = <sqlx::Sqlite as sqlx::Database>::TransactionManager::get_transaction_depth(c); |
| 93 | + let statement = if depth == 0 { |
| 94 | + sqlite_transaction_mode.map(|mode| { |
| 95 | + std::borrow::Cow::from(format!("BEGIN {}", mode.sqlite_keyword())) |
| 96 | + }) |
| 97 | + } else { |
| 98 | + // Nested transaction uses SAVEPOINT; the mode only applies to the top-level BEGIN |
| 99 | + None |
| 100 | + }; |
96 | 101 | <sqlx::Sqlite as sqlx::Database>::TransactionManager::begin(c, statement) |
97 | | - .await |
98 | 102 | .map_err(sqlx_error_to_query_err) |
99 | 103 | } |
100 | 104 | #[cfg(feature = "rusqlite")] |
101 | | - InnerConnection::Rusqlite(c) => c.begin(), |
| 105 | + InnerConnection::Rusqlite(c) => c.begin(sqlite_transaction_mode), |
102 | 106 | #[cfg(feature = "mock")] |
103 | 107 | InnerConnection::Mock(c) => { |
104 | 108 | c.begin(); |
@@ -605,19 +609,15 @@ impl TransactionTrait for DatabaseTransaction { |
605 | 609 | #[instrument(level = "trace")] |
606 | 610 | fn begin_with_options( |
607 | 611 | &self, |
608 | | - TransactionOptions { |
609 | | - isolation_level, |
610 | | - access_mode, |
611 | | - sqlite_transaction_mode, |
612 | | - }: TransactionOptions, |
| 612 | + options: TransactionOptions, |
613 | 613 | ) -> Result<DatabaseTransaction, DbErr> { |
614 | 614 | DatabaseTransaction::begin( |
615 | 615 | Arc::clone(&self.conn), |
616 | 616 | self.backend, |
617 | 617 | self.metric_callback.clone(), |
618 | | - isolation_level, |
619 | | - access_mode, |
620 | | - sqlite_transaction_mode, |
| 618 | + options.isolation_level, |
| 619 | + options.access_mode, |
| 620 | + options.sqlite_transaction_mode, |
621 | 621 | ) |
622 | 622 | } |
623 | 623 |
|
|
0 commit comments