1#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2extern crate libsqlite3_sys as ffi;
3
4#[cfg(all(target_family = "wasm", target_os = "unknown"))]
5use sqlite_wasm_rs as ffi;
6
7mod bind_collector;
8mod functions;
9mod hooks;
10mod limits;
11mod owned_row;
12mod raw;
13mod row;
14mod serialized_database;
15pub(in crate::sqlite) mod sqlite_blob;
16mod sqlite_value;
17mod statement_iterator;
18mod stmt;
19
20pub(in crate::sqlite) use self::bind_collector::SqliteBindCollector;
21pub use self::bind_collector::SqliteBindValue;
22pub use self::limits::SqliteLimit;
23pub use self::serialized_database::SerializedDatabase;
24pub use self::sqlite_value::SqliteValue;
25
26use self::raw::RawConnection;
27use self::statement_iterator::*;
28use self::stmt::{Statement, StatementUse};
29use super::SqliteAggregateFunction;
30use crate::connection::instrumentation::{DynInstrumentation, StrQueryHelper};
31use crate::connection::statement_cache::StatementCache;
32use crate::connection::*;
33use crate::deserialize::{FromSqlRow, StaticallySizedRow};
34use crate::expression::QueryMetadata;
35use crate::query_builder::*;
36use crate::result::*;
37use crate::serialize::ToSql;
38use crate::sql_types::{HasSqlType, TypeMetadata};
39use crate::sqlite::{Sqlite, SqliteFunctionBehavior};
40use alloc::string::String;
41use alloc::vec::Vec;
42use core::ffi as libc;
43use core::num::NonZeroI64;
44
45#[allow(missing_debug_implementations)]
168#[cfg(feature = "__sqlite-shared")]
169pub struct SqliteConnection {
170 statement_cache: StatementCache<Sqlite, Statement>,
174 raw_connection: RawConnection,
175 transaction_state: AnsiTransactionManager,
176 metadata_lookup: (),
179 instrumentation: DynInstrumentation,
180 serialized_data: Vec<Vec<u8>>,
191}
192
193#[allow(unsafe_code)]
197unsafe impl Send for SqliteConnection {}
198
199impl SimpleConnection for SqliteConnection {
200 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
201 self.instrumentation
202 .on_connection_event(InstrumentationEvent::StartQuery {
203 query: &StrQueryHelper::new(query),
204 });
205 let resp = self.raw_connection.exec(query);
206 self.instrumentation
207 .on_connection_event(InstrumentationEvent::FinishQuery {
208 query: &StrQueryHelper::new(query),
209 error: resp.as_ref().err(),
210 });
211 resp
212 }
213}
214
215impl ConnectionSealed for SqliteConnection {}
216
217impl Connection for SqliteConnection {
218 type Backend = Sqlite;
219 type TransactionManager = AnsiTransactionManager;
220
221 fn establish(database_url: &str) -> ConnectionResult<Self> {
237 let mut instrumentation = DynInstrumentation::default_instrumentation();
238 instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
239 url: database_url,
240 });
241
242 let establish_result = Self::establish_inner(database_url);
243 instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
244 url: database_url,
245 error: establish_result.as_ref().err(),
246 });
247 let mut conn = establish_result?;
248 conn.instrumentation = instrumentation;
249 Ok(conn)
250 }
251
252 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
253 where
254 T: QueryFragment<Self::Backend> + QueryId,
255 {
256 let statement_use = self.prepared_query(source)?;
257 statement_use.run().and_then(|_| {
258 self.raw_connection
259 .rows_affected_by_last_query()
260 .map_err(Error::DeserializationError)
261 })
262 }
263
264 fn transaction_state(&mut self) -> &mut AnsiTransactionManager
265 where
266 Self: Sized,
267 {
268 &mut self.transaction_state
269 }
270
271 fn instrumentation(&mut self) -> &mut dyn Instrumentation {
272 &mut *self.instrumentation
273 }
274
275 fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
276 self.instrumentation = instrumentation.into();
277 }
278
279 fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
280 self.statement_cache.set_cache_size(size);
281 }
282}
283
284impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
285 type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>;
286 type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>;
287
288 fn load<'conn, 'query, T>(
289 &'conn mut self,
290 source: T,
291 ) -> QueryResult<Self::Cursor<'conn, 'query>>
292 where
293 T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
294 Self::Backend: QueryMetadata<T::SqlType>,
295 {
296 let statement = self.prepared_query(source)?;
297
298 Ok(StatementIterator::new(statement))
299 }
300}
301
302impl WithMetadataLookup for SqliteConnection {
303 fn metadata_lookup(&mut self) -> &mut <Sqlite as TypeMetadata>::MetadataLookup {
304 &mut self.metadata_lookup
305 }
306}
307
308#[cfg(feature = "r2d2")]
309impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
310 fn ping(&mut self) -> QueryResult<()> {
311 use crate::RunQueryDsl;
312
313 crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
314 }
315
316 fn is_broken(&mut self) -> bool {
317 AnsiTransactionManager::is_broken_transaction_manager(self)
318 }
319}
320
321impl MultiConnectionHelper for SqliteConnection {
322 fn to_any<'a>(
323 lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
324 ) -> &mut (dyn core::any::Any + 'a) {
325 lookup
326 }
327
328 fn from_any(
329 lookup: &mut dyn core::any::Any,
330 ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
331 lookup.downcast_mut()
332 }
333}
334
335#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CommitDecision {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
CommitDecision::Proceed => "Proceed",
CommitDecision::Rollback => "Rollback",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for CommitDecision {
#[inline]
fn clone(&self) -> CommitDecision { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CommitDecision { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for CommitDecision {
#[inline]
fn eq(&self, other: &CommitDecision) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CommitDecision {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
338pub enum CommitDecision {
339 Proceed,
341 Rollback,
343}
344
345#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ProgressDecision {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
ProgressDecision::Continue => "Continue",
ProgressDecision::Interrupt => "Interrupt",
})
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ProgressDecision {
#[inline]
fn clone(&self) -> ProgressDecision { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ProgressDecision { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for ProgressDecision {
#[inline]
fn eq(&self, other: &ProgressDecision) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ProgressDecision {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {}
}Eq)]
348pub enum ProgressDecision {
349 Continue,
351 Interrupt,
353}
354
355impl SqliteConnection {
356 pub fn immediate_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
378 where
379 F: FnOnce(&mut Self) -> Result<T, E>,
380 E: From<Error>,
381 {
382 self.transaction_sql(f, "BEGIN IMMEDIATE")
383 }
384
385 pub fn exclusive_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
407 where
408 F: FnOnce(&mut Self) -> Result<T, E>,
409 E: From<Error>,
410 {
411 self.transaction_sql(f, "BEGIN EXCLUSIVE")
412 }
413
414 pub fn last_insert_rowid(&self) -> Option<NonZeroI64> {
450 NonZeroI64::new(self.raw_connection.last_insert_rowid())
451 }
452
453 pub fn get_read_only_blob<'conn, 'query, U>(
482 &'conn self,
483 blob_column: U,
484 row_id: i64,
485 ) -> Result<sqlite_blob::SqliteReadOnlyBlob<'conn>, Error>
486 where
487 'query: 'conn,
488 U: crate::Column,
489 U::Table: nodes::StaticQueryFragment,
490 <U::Table as nodes::StaticQueryFragment>::Component: HasDatabaseAndTableName,
491 {
492 use crate::query_builder::nodes::StaticQueryFragment;
493 let _ = blob_column;
495
496 let database_name = U::Table::STATIC_COMPONENT.database_name().unwrap_or("main");
497 let column_name = U::NAME;
498 let table_name = U::Table::STATIC_COMPONENT.table_name();
499
500 self.raw_connection
501 .blob_open(database_name, table_name, column_name, row_id)
502 }
503
504 fn transaction_sql<T, E, F>(&mut self, f: F, sql: &str) -> Result<T, E>
505 where
506 F: FnOnce(&mut Self) -> Result<T, E>,
507 E: From<Error>,
508 {
509 AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?;
510 match f(&mut *self) {
511 Ok(value) => {
512 AnsiTransactionManager::commit_transaction(&mut *self)?;
513 Ok(value)
514 }
515 Err(e) => {
516 AnsiTransactionManager::rollback_transaction(&mut *self)?;
517 Err(e)
518 }
519 }
520 }
521
522 fn prepared_query<'conn, 'query, T>(
523 &'conn mut self,
524 source: T,
525 ) -> QueryResult<StatementUse<'conn, 'query>>
526 where
527 T: QueryFragment<Sqlite> + QueryId + 'query,
528 {
529 self.instrumentation
530 .on_connection_event(InstrumentationEvent::StartQuery {
531 query: &crate::debug_query(&source),
532 });
533 let raw_connection = &self.raw_connection;
534 let cache = &mut self.statement_cache;
535 let statement = match cache.cached_statement(
536 &source,
537 &Sqlite,
538 &[],
539 raw_connection,
540 Statement::prepare,
541 &mut *self.instrumentation,
542 ) {
543 Ok(statement) => statement,
544 Err(e) => {
545 self.instrumentation
546 .on_connection_event(InstrumentationEvent::FinishQuery {
547 query: &crate::debug_query(&source),
548 error: Some(&e),
549 });
550
551 return Err(e);
552 }
553 };
554
555 StatementUse::bind(statement, source, &mut *self.instrumentation)
556 }
557
558 #[doc(hidden)]
559 pub fn register_sql_function<ArgsSqlType, RetSqlType, Args, Ret, F>(
560 &mut self,
561 fn_name: &str,
562 behavior: SqliteFunctionBehavior,
563 mut f: F,
564 ) -> QueryResult<()>
565 where
566 F: FnMut(Args) -> Ret + core::panic::UnwindSafe + Send + 'static,
567 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
568 Ret: ToSql<RetSqlType, Sqlite>,
569 Sqlite: HasSqlType<RetSqlType>,
570 {
571 functions::register(&self.raw_connection, fn_name, behavior, move |_, args| {
572 f(args)
573 })
574 }
575
576 #[doc(hidden)]
577 pub fn register_noarg_sql_function<RetSqlType, Ret, F>(
578 &mut self,
579 fn_name: &str,
580 behavior: SqliteFunctionBehavior,
581 f: F,
582 ) -> QueryResult<()>
583 where
584 F: FnMut() -> Ret + core::panic::UnwindSafe + Send + 'static,
585 Ret: ToSql<RetSqlType, Sqlite>,
586 Sqlite: HasSqlType<RetSqlType>,
587 {
588 functions::register_noargs(&self.raw_connection, fn_name, behavior, f)
589 }
590
591 #[doc(hidden)]
592 pub fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
593 &mut self,
594 fn_name: &str,
595 behavior: SqliteFunctionBehavior,
596 ) -> QueryResult<()>
597 where
598 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
599 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
600 Ret: ToSql<RetSqlType, Sqlite>,
601 Sqlite: HasSqlType<RetSqlType>,
602 {
603 functions::register_aggregate::<_, _, _, _, A>(&self.raw_connection, fn_name, behavior)
604 }
605
606 pub fn register_collation<F>(&mut self, collation_name: &str, collation: F) -> QueryResult<()>
642 where
643 F: Fn(&str, &str) -> core::cmp::Ordering + Send + 'static + core::panic::UnwindSafe,
644 {
645 self.raw_connection
646 .register_collation_function(collation_name, collation)
647 }
648
649 pub fn serialize_database_to_buffer(&mut self) -> SerializedDatabase {
658 self.raw_connection.serialize()
659 }
660
661 #[allow(unsafe_code)]
701 pub fn deserialize_readonly_database_from_buffer(&mut self, data: &[u8]) -> QueryResult<()> {
702 self.serialized_data.push(data.to_vec());
705 let last = self
706 .serialized_data
707 .last()
708 .expect("We literally pushed it above, so it's there");
709 unsafe {
710 self.raw_connection.deserialize(last)
713 }
714 }
715
716 #[allow(unsafe_code)]
803 pub unsafe fn with_raw_connection<R, F>(&mut self, f: F) -> R
804 where
805 F: FnOnce(*mut ffi::sqlite3) -> R,
806 {
807 f(self.raw_connection.internal_connection.as_ptr())
808 }
809
810 #[allow(unsafe_code)]
819 pub(crate) unsafe fn with_borrowed_connection<R>(
820 db: core::ptr::NonNull<ffi::sqlite3>,
821 f: impl FnOnce(&mut SqliteConnection) -> R,
822 ) -> R {
823 struct Borrowed(core::mem::ManuallyDrop<SqliteConnection>);
826
827 impl Drop for Borrowed {
828 fn drop(&mut self) {
829 let conn = unsafe { core::mem::ManuallyDrop::take(&mut self.0) };
831 let SqliteConnection {
832 statement_cache,
833 raw_connection,
834 ..
835 } = conn;
836 drop(statement_cache);
839 core::mem::forget(raw_connection);
840 }
841 }
842
843 let mut conn = Borrowed(core::mem::ManuallyDrop::new(SqliteConnection {
844 statement_cache: StatementCache::new(),
845 raw_connection: RawConnection::from_ptr(db),
846 transaction_state: AnsiTransactionManager::default(),
847 metadata_lookup: (),
848 instrumentation: DynInstrumentation::default_instrumentation(),
849 serialized_data: Vec::new(),
850 }));
851
852 let result = f(&mut conn.0);
853
854 if true {
if !#[allow(non_exhaustive_omitted_patterns)] match AnsiTransactionManager::transaction_manager_status_mut(&mut *conn.0).transaction_depth()
{
Ok(None) => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("callback must not leave an open transaction on the borrowed connection"));
}
};
};debug_assert!(
857 matches!(
858 AnsiTransactionManager::transaction_manager_status_mut(&mut *conn.0)
859 .transaction_depth(),
860 Ok(None)
861 ),
862 "callback must not leave an open transaction on the borrowed connection"
863 );
864
865 result
866 }
867
868 pub fn set_limit(&mut self, limit: SqliteLimit, value: i32) -> i32 {
891 self.raw_connection.set_limit(limit, value)
892 }
893
894 pub fn get_limit(&self, limit: SqliteLimit) -> i32 {
912 self.raw_connection.get_limit(limit)
913 }
914
915 pub fn set_recommended_security_limits(&mut self) {
958 self.set_limit(SqliteLimit::Length, SqliteLimit::SAFE_LENGTH_LIMIT);
959 self.set_limit(SqliteLimit::SqlLength, SqliteLimit::SAFE_SQL_LENGTH_LIMIT);
960 self.set_limit(
961 SqliteLimit::ColumnCount,
962 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
963 );
964 self.set_limit(SqliteLimit::ExprDepth, SqliteLimit::SAFE_EXPR_DEPTH_LIMIT);
965 self.set_limit(
966 SqliteLimit::CompoundSelect,
967 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
968 );
969 self.set_limit(SqliteLimit::VdbeOp, SqliteLimit::SAFE_VDBE_OP_LIMIT);
970 self.set_limit(
971 SqliteLimit::FunctionArg,
972 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
973 );
974 self.set_limit(SqliteLimit::Attached, SqliteLimit::SAFE_ATTACHED_LIMIT);
975 self.set_limit(
976 SqliteLimit::LikePatternLength,
977 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
978 );
979 self.set_limit(
980 SqliteLimit::VariableNumber,
981 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
982 );
983 self.set_limit(
984 SqliteLimit::TriggerDepth,
985 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
986 );
987 }
988
989 pub fn set_defensive(&mut self, enabled: bool) -> QueryResult<()> {
1016 self.raw_connection
1017 .set_db_config_bool(ffi::SQLITE_DBCONFIG_DEFENSIVE, enabled)
1018 }
1019
1020 pub fn is_defensive(&self) -> QueryResult<bool> {
1024 self.raw_connection
1025 .get_db_config_bool(ffi::SQLITE_DBCONFIG_DEFENSIVE)
1026 }
1027
1028 pub fn set_trusted_schema(&mut self, trusted: bool) -> QueryResult<()> {
1040 self.raw_connection
1041 .set_db_config_bool(ffi::SQLITE_DBCONFIG_TRUSTED_SCHEMA, trusted)
1042 }
1043
1044 pub fn is_trusted_schema(&self) -> QueryResult<bool> {
1048 self.raw_connection
1049 .get_db_config_bool(ffi::SQLITE_DBCONFIG_TRUSTED_SCHEMA)
1050 }
1051
1052 pub fn with_load_extension_enabled<R, E>(
1080 &mut self,
1081 f: impl FnOnce(&mut Self) -> Result<R, E>,
1082 ) -> Result<R, E>
1083 where
1084 E: From<crate::result::Error>,
1085 {
1086 self.set_load_extension_enabled(true)?;
1087
1088 #[cfg(feature = "std")]
1092 {
1093 match std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| f(self))) {
1094 Ok(r) => {
1095 self.set_load_extension_enabled(false)?;
1096 r
1097 }
1098 Err(panic) => {
1099 let _ = self.set_load_extension_enabled(false);
1100 std::panic::resume_unwind(panic);
1101 }
1102 }
1103 }
1104 #[cfg(not(feature = "std"))]
1105 {
1106 let r = f(self);
1107 self.set_load_extension_enabled(false)?;
1108 r
1109 }
1110 }
1111
1112 fn set_load_extension_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1113 self.raw_connection
1114 .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, enabled)
1115 }
1116
1117 #[cfg(test)]
1118 fn is_load_extension_enabled(&self) -> QueryResult<bool> {
1119 self.raw_connection
1120 .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION)
1121 }
1122
1123 pub fn set_fts3_tokenizer_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1132 self.raw_connection
1133 .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, enabled)
1134 }
1135
1136 pub fn is_fts3_tokenizer_enabled(&self) -> QueryResult<bool> {
1140 self.raw_connection
1141 .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER)
1142 }
1143
1144 pub fn set_writable_schema(&mut self, enabled: bool) -> QueryResult<()> {
1153 self.raw_connection
1154 .set_db_config_bool(ffi::SQLITE_DBCONFIG_WRITABLE_SCHEMA, enabled)
1155 }
1156
1157 pub fn is_writable_schema(&self) -> QueryResult<bool> {
1161 self.raw_connection
1162 .get_db_config_bool(ffi::SQLITE_DBCONFIG_WRITABLE_SCHEMA)
1163 }
1164
1165 pub fn set_attach_create_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1173 self.raw_connection
1174 .set_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE, enabled)
1175 }
1176
1177 pub fn is_attach_create_enabled(&self) -> QueryResult<bool> {
1181 self.raw_connection
1182 .get_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE)
1183 }
1184
1185 pub fn set_attach_write_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1192 self.raw_connection
1193 .set_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE, enabled)
1194 }
1195
1196 pub fn is_attach_write_enabled(&self) -> QueryResult<bool> {
1200 self.raw_connection
1201 .get_db_config_bool(raw::SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE)
1202 }
1203
1204 pub fn set_triggers_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1210 self.raw_connection
1211 .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER, enabled)
1212 }
1213
1214 pub fn are_triggers_enabled(&self) -> QueryResult<bool> {
1218 self.raw_connection
1219 .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_TRIGGER)
1220 }
1221
1222 pub fn set_views_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1228 self.raw_connection
1229 .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_VIEW, enabled)
1230 }
1231
1232 pub fn are_views_enabled(&self) -> QueryResult<bool> {
1236 self.raw_connection
1237 .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_VIEW)
1238 }
1239
1240 pub fn set_foreign_keys_enabled(&mut self, enabled: bool) -> QueryResult<()> {
1246 self.raw_connection
1247 .set_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FKEY, enabled)
1248 }
1249
1250 pub fn are_foreign_keys_enabled(&self) -> QueryResult<bool> {
1254 self.raw_connection
1255 .get_db_config_bool(ffi::SQLITE_DBCONFIG_ENABLE_FKEY)
1256 }
1257
1258 pub fn set_double_quoted_strings_dml(&mut self, enabled: bool) -> QueryResult<()> {
1266 self.raw_connection
1267 .set_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DML, enabled)
1268 }
1269
1270 pub fn are_double_quoted_strings_dml_enabled(&self) -> QueryResult<bool> {
1274 self.raw_connection
1275 .get_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DML)
1276 }
1277
1278 pub fn set_double_quoted_strings_ddl(&mut self, enabled: bool) -> QueryResult<()> {
1286 self.raw_connection
1287 .set_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DDL, enabled)
1288 }
1289
1290 pub fn are_double_quoted_strings_ddl_enabled(&self) -> QueryResult<bool> {
1294 self.raw_connection
1295 .get_db_config_bool(ffi::SQLITE_DBCONFIG_DQS_DDL)
1296 }
1297
1298 fn register_diesel_sql_functions(&self) -> QueryResult<()> {
1299 use crate::sql_types::{Integer, Text};
1300
1301 functions::register::<Text, Integer, _, _, _>(
1305 &self.raw_connection,
1306 "diesel_manage_updated_at",
1307 SqliteFunctionBehavior::DIRECTONLY,
1308 |conn, table_name: String| {
1309 conn.exec(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CREATE TRIGGER __diesel_manage_updated_at_{0}\nAFTER UPDATE ON {0}\nFOR EACH ROW WHEN\n old.updated_at IS NULL AND\n new.updated_at IS NULL OR\n old.updated_at == new.updated_at\nBEGIN\n UPDATE {0}\n SET updated_at = CURRENT_TIMESTAMP\n WHERE ROWID = new.ROWID;\nEND\n",
table_name))
})alloc::format!(
1310 include_str!("diesel_manage_updated_at.sql"),
1311 table_name = table_name
1312 ))
1313 .expect("Failed to create trigger");
1314 0 },
1316 )
1317 }
1318
1319 fn establish_inner(database_url: &str) -> Result<SqliteConnection, ConnectionError> {
1320 use crate::result::ConnectionError::CouldntSetupConfiguration;
1321 let raw_connection = RawConnection::establish(database_url)?;
1322 let conn = Self {
1323 statement_cache: StatementCache::new(),
1324 raw_connection,
1325 transaction_state: AnsiTransactionManager::default(),
1326 metadata_lookup: (),
1327 instrumentation: DynInstrumentation::none(),
1328 serialized_data: Vec::new(),
1329 };
1330 conn.register_diesel_sql_functions()
1331 .map_err(CouldntSetupConfiguration)?;
1332 Ok(conn)
1333 }
1334}
1335
1336fn error_message(err_code: libc::c_int) -> &'static str {
1337 ffi::code_to_str(err_code)
1338}
1339
1340mod private {
1341 #[doc(hidden)]
1342 pub trait HasDatabaseAndTableName {
1343 fn database_name(&self) -> Option<&'static str>;
1344 fn table_name(&self) -> &'static str;
1345 }
1346
1347 impl HasDatabaseAndTableName for crate::query_builder::nodes::Identifier<'static> {
1348 fn database_name(&self) -> Option<&'static str> {
1349 None
1350 }
1351
1352 fn table_name(&self) -> &'static str {
1353 self.0
1354 }
1355 }
1356
1357 impl<M> HasDatabaseAndTableName
1358 for crate::query_builder::nodes::InfixNode<
1359 crate::query_builder::nodes::Identifier<'static>,
1360 crate::query_builder::nodes::Identifier<'static>,
1361 M,
1362 >
1363 {
1364 fn database_name(&self) -> Option<&'static str> {
1365 Some(self.lhs.0)
1366 }
1367
1368 fn table_name(&self) -> &'static str {
1369 self.rhs.0
1370 }
1371 }
1372}
1373pub(crate) use self::private::HasDatabaseAndTableName;
1374
1375#[cfg(test)]
1376mod tests {
1377 use super::*;
1378 use crate::dsl::sql;
1379 use crate::prelude::*;
1380 use crate::sql_types::{Integer, Text};
1381 use crate::sqlite::SqliteFunctionBehavior;
1382
1383 fn connection() -> SqliteConnection {
1384 SqliteConnection::establish(":memory:").unwrap()
1385 }
1386
1387 #[diesel_test_helper::test]
1388 #[allow(unsafe_code)]
1389 fn with_raw_connection_can_return_values() {
1390 let connection = &mut connection();
1391
1392 let autocommit_status = unsafe {
1394 connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1395 };
1396
1397 assert_ne!(autocommit_status, 0, "Expected autocommit to be enabled");
1399 }
1400
1401 #[diesel_test_helper::test]
1402 #[allow(unsafe_code)]
1403 fn with_raw_connection_works_after_diesel_operations() {
1404 let connection = &mut connection();
1405
1406 crate::sql_query("CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT)")
1408 .execute(connection)
1409 .unwrap();
1410 crate::sql_query("INSERT INTO test_table (value) VALUES ('hello')")
1411 .execute(connection)
1412 .unwrap();
1413
1414 let last_rowid = unsafe {
1416 connection.with_raw_connection(|raw_conn| ffi::sqlite3_last_insert_rowid(raw_conn))
1417 };
1418
1419 assert_eq!(last_rowid, 1, "Last insert rowid should be 1");
1420
1421 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM test_table")
1423 .get_result(connection)
1424 .unwrap();
1425 assert_eq!(count, 1);
1426 }
1427
1428 #[diesel_test_helper::test]
1429 #[allow(unsafe_code)]
1430 fn with_raw_connection_can_execute_raw_sql() {
1431 let connection = &mut connection();
1432
1433 crate::sql_query("CREATE TABLE raw_test (id INTEGER PRIMARY KEY, name TEXT)")
1435 .execute(connection)
1436 .unwrap();
1437
1438 let result = unsafe {
1441 connection.with_raw_connection(|raw_conn| {
1442 let sql = c"INSERT INTO raw_test (name) VALUES ('from_raw')";
1443 let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
1444 let rc = ffi::sqlite3_exec(
1445 raw_conn,
1446 sql.as_ptr(),
1447 None,
1448 core::ptr::null_mut(),
1449 &mut err_msg,
1450 );
1451 if rc != ffi::SQLITE_OK && !err_msg.is_null() {
1452 ffi::sqlite3_free(err_msg as *mut libc::c_void);
1453 }
1454 rc
1455 })
1456 };
1457
1458 assert_eq!(result, ffi::SQLITE_OK, "Raw SQL execution should succeed");
1459
1460 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM raw_test")
1462 .get_result(connection)
1463 .unwrap();
1464 assert_eq!(count, 1);
1465
1466 let name: String = sql::<Text>("SELECT name FROM raw_test WHERE id = 1")
1467 .get_result(connection)
1468 .unwrap();
1469 assert_eq!(name, "from_raw");
1470 }
1471
1472 #[diesel_test_helper::test]
1473 #[allow(unsafe_code)]
1474 fn with_raw_connection_works_within_transaction() {
1475 let connection = &mut connection();
1476
1477 crate::sql_query("CREATE TABLE txn_test (id INTEGER PRIMARY KEY, value INTEGER)")
1478 .execute(connection)
1479 .unwrap();
1480
1481 connection
1482 .transaction::<_, crate::result::Error, _>(|conn| {
1483 crate::sql_query("INSERT INTO txn_test (value) VALUES (42)")
1484 .execute(conn)
1485 .unwrap();
1486
1487 let autocommit = unsafe {
1489 conn.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1490 };
1491
1492 assert_eq!(
1494 autocommit, 0,
1495 "Autocommit should be disabled inside transaction"
1496 );
1497
1498 Ok(())
1499 })
1500 .unwrap();
1501
1502 let autocommit = unsafe {
1504 connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1505 };
1506 assert_ne!(
1507 autocommit, 0,
1508 "Autocommit should be enabled after transaction"
1509 );
1510 }
1511
1512 #[diesel_test_helper::test]
1513 #[allow(unsafe_code)]
1514 fn with_raw_connection_can_read_database_filename() {
1515 let connection = &mut connection();
1516
1517 let filename = unsafe {
1519 connection.with_raw_connection(|raw_conn| {
1520 let db_name = c"main";
1521 let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1522 if filename_ptr.is_null() {
1523 None
1524 } else {
1525 let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1527 Some(cstr.to_string_lossy().into_owned())
1528 }
1529 })
1530 };
1531
1532 assert_eq!(
1535 filename,
1536 Some(String::new()),
1537 "In-memory database filename should be an empty string"
1538 );
1539 }
1540
1541 #[diesel_test_helper::test]
1542 #[allow(unsafe_code)]
1543 fn with_raw_connection_changes_count() {
1544 let connection = &mut connection();
1545
1546 crate::sql_query("CREATE TABLE changes_test (id INTEGER PRIMARY KEY, value INTEGER)")
1547 .execute(connection)
1548 .unwrap();
1549
1550 crate::sql_query("INSERT INTO changes_test (value) VALUES (1), (2), (3)")
1551 .execute(connection)
1552 .unwrap();
1553
1554 let changes = unsafe {
1556 connection.with_raw_connection(|raw_conn| {
1557 let sql = c"UPDATE changes_test SET value = value + 10";
1558 let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
1559 let rc = ffi::sqlite3_exec(
1560 raw_conn,
1561 sql.as_ptr(),
1562 None,
1563 core::ptr::null_mut(),
1564 &mut err_msg,
1565 );
1566 if rc != ffi::SQLITE_OK && !err_msg.is_null() {
1567 ffi::sqlite3_free(err_msg as *mut libc::c_void);
1568 return -1;
1569 }
1570 ffi::sqlite3_changes(raw_conn)
1571 })
1572 };
1573
1574 assert_eq!(changes, 3, "Should have updated 3 rows");
1575
1576 let values: Vec<i32> = sql::<Integer>("SELECT value FROM changes_test ORDER BY id")
1578 .load(connection)
1579 .unwrap();
1580 assert_eq!(values, vec![11, 12, 13]);
1581 }
1582
1583 #[diesel_test_helper::test]
1585 #[allow(unsafe_code)]
1586 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1587 fn with_raw_connection_recovers_after_panic() {
1588 let connection = &mut connection();
1589
1590 crate::sql_query("CREATE TABLE panic_test (id INTEGER PRIMARY KEY, value TEXT)")
1591 .execute(connection)
1592 .unwrap();
1593
1594 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1596 connection.with_raw_connection(|_raw_conn| {
1597 panic!("intentional panic inside with_raw_connection");
1598 })
1599 }));
1600 assert!(result.is_err(), "Should have caught the panic");
1601
1602 crate::sql_query("INSERT INTO panic_test (value) VALUES ('after_panic')")
1604 .execute(connection)
1605 .unwrap();
1606
1607 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM panic_test")
1608 .get_result(connection)
1609 .unwrap();
1610 assert_eq!(count, 1, "Connection should work after panic in callback");
1611 }
1612
1613 #[diesel_test_helper::test]
1615 #[allow(unsafe_code)]
1616 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1617 fn with_raw_connection_can_read_file_database_filename() {
1618 let dir = std::env::temp_dir().join("diesel_test_filename.db");
1619 let db_path = dir.to_str().unwrap();
1620
1621 let _ = std::fs::remove_file(db_path);
1623
1624 let connection = &mut SqliteConnection::establish(db_path).unwrap();
1625
1626 let filename = unsafe {
1628 connection.with_raw_connection(|raw_conn| {
1629 let db_name = c"main";
1630 let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1631 if filename_ptr.is_null() {
1632 None
1633 } else {
1634 let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1635 Some(cstr.to_string_lossy().into_owned())
1636 }
1637 })
1638 };
1639
1640 let filename = filename.expect("File-based database should have a filename");
1641 assert!(
1642 filename.contains("diesel_test_filename.db"),
1643 "Filename should contain the database name, got: {filename}"
1644 );
1645
1646 let _ = std::fs::remove_file(db_path);
1648 }
1649
1650 #[declare_sql_function]
1651 extern "SQL" {
1652 fn fun_case(x: Text) -> Text;
1653 fn my_add(x: Integer, y: Integer) -> Integer;
1654 fn answer() -> Integer;
1655 fn add_counter(x: Integer) -> Integer;
1656
1657 #[aggregate]
1658 fn my_sum(expr: Integer) -> Integer;
1659 #[aggregate]
1660 fn range_max(expr1: Integer, expr2: Integer, expr3: Integer) -> Nullable<Integer>;
1661 }
1662
1663 #[diesel_test_helper::test]
1664 fn database_serializes_and_deserializes_successfully() {
1665 let expected_users = vec![
1666 (
1667 1,
1668 "John Doe".to_string(),
1669 "john.doe@example.com".to_string(),
1670 ),
1671 (
1672 2,
1673 "Jane Doe".to_string(),
1674 "jane.doe@example.com".to_string(),
1675 ),
1676 ];
1677
1678 let conn1 = &mut connection();
1679 let _ =
1680 crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1681 .execute(conn1);
1682 let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1683 .execute(conn1);
1684
1685 for _i in 0..2 {
1686 let serialized_database = conn1.serialize_database_to_buffer();
1687 let conn2 = &mut connection();
1688 conn2
1689 .deserialize_readonly_database_from_buffer(serialized_database.as_slice())
1690 .unwrap();
1691
1692 let query =
1693 sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1694 let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1695
1696 assert_eq!(expected_users, actual_users);
1697 std::mem::drop(serialized_database);
1701 let query =
1702 sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1703 let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1704
1705 assert_eq!(expected_users, actual_users);
1706 }
1707 }
1708
1709 #[diesel_test_helper::test]
1710 fn database_deserialize_random_bytes() {
1711 let buffer = vec![0, 1, 2, 3, 4];
1712 let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1713
1714 conn.deserialize_readonly_database_from_buffer(&buffer)
1715 .unwrap();
1716
1717 let r = sql::<Integer>("SELECT id FROM users").load::<i32>(conn);
1718
1719 assert!(r.is_err());
1720 assert_eq!(r.unwrap_err().to_string(), "file is not a database");
1721
1722 let conn = &mut SqliteConnection::establish(":memory:").unwrap();
1723
1724 let _ =
1725 crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1726 .execute(conn);
1727 let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1728 .execute(conn);
1729
1730 let db = conn.serialize_database_to_buffer();
1731 let mut bad_buffer = db[..100].to_vec();
1733 bad_buffer.extend(b"whatever");
1734 conn.deserialize_readonly_database_from_buffer(&bad_buffer)
1735 .unwrap();
1736
1737 let r = sql::<Integer>("SELECT id FROM users").load::<i32>(conn);
1738
1739 assert!(r.is_err());
1740 assert_eq!(
1741 r.unwrap_err().to_string(),
1742 "database disk image is malformed"
1743 );
1744
1745 let mut size_fitting_bad_buffer = db[..100].to_vec();
1747 size_fitting_bad_buffer.extend(
1748 core::iter::repeat(b"abcdefghij")
1749 .flatten()
1750 .take(db.len() - 100),
1751 );
1752 let r = conn.deserialize_readonly_database_from_buffer(&size_fitting_bad_buffer);
1753
1754 assert!(r.is_err());
1755 assert_eq!(
1756 r.unwrap_err().to_string(),
1757 "database disk image is malformed"
1758 );
1759 }
1760
1761 #[diesel_test_helper::test]
1762 fn register_custom_function() {
1763 let connection = &mut connection();
1764 fun_case_utils::register_impl(connection, |x: String| {
1765 x.chars()
1766 .enumerate()
1767 .map(|(i, c)| {
1768 if i % 2 == 0 {
1769 c.to_lowercase().to_string()
1770 } else {
1771 c.to_uppercase().to_string()
1772 }
1773 })
1774 .collect::<String>()
1775 })
1776 .unwrap();
1777
1778 let mapped_string = crate::select(fun_case("foobar"))
1779 .get_result::<String>(connection)
1780 .unwrap();
1781 assert_eq!("fOoBaR", mapped_string);
1782 }
1783
1784 #[diesel_test_helper::test]
1785 fn register_multiarg_function() {
1786 let connection = &mut connection();
1787 my_add_utils::register_impl(connection, |x: i32, y: i32| x + y).unwrap();
1788
1789 let added = crate::select(my_add(1, 2)).get_result::<i32>(connection);
1790 assert_eq!(Ok(3), added);
1791 }
1792
1793 #[diesel_test_helper::test]
1794 fn register_noarg_function() {
1795 let connection = &mut connection();
1796 answer_utils::register_impl(connection, || 42).unwrap();
1797
1798 let answer = crate::select(answer()).get_result::<i32>(connection);
1799 assert_eq!(Ok(42), answer);
1800 }
1801
1802 #[diesel_test_helper::test]
1803 fn register_nondeterministic_noarg_function() {
1804 let connection = &mut connection();
1805 answer_utils::register_nondeterministic_impl(connection, || 42).unwrap();
1806
1807 let answer = crate::select(answer()).get_result::<i32>(connection);
1808 assert_eq!(Ok(42), answer);
1809 }
1810
1811 #[diesel_test_helper::test]
1812 fn register_nondeterministic_function() {
1813 let connection = &mut connection();
1814 let mut y = 0;
1815 add_counter_utils::register_nondeterministic_impl(connection, move |x: i32| {
1816 y += 1;
1817 x + y
1818 })
1819 .unwrap();
1820
1821 let added = crate::select((add_counter(1), add_counter(1), add_counter(1)))
1822 .get_result::<(i32, i32, i32)>(connection);
1823 assert_eq!(Ok((2, 3, 4)), added);
1824 }
1825
1826 #[derive(Default)]
1827 struct MySum {
1828 sum: i32,
1829 }
1830
1831 impl SqliteAggregateFunction<i32> for MySum {
1832 type Output = i32;
1833
1834 fn step(&mut self, expr: i32) {
1835 self.sum += expr;
1836 }
1837
1838 fn finalize(aggregator: Option<Self>) -> Self::Output {
1839 aggregator.map(|a| a.sum).unwrap_or_default()
1840 }
1841 }
1842
1843 table! {
1844 my_sum_example {
1845 id -> Integer,
1846 value -> Integer,
1847 }
1848 }
1849
1850 #[diesel_test_helper::test]
1851 fn register_aggregate_function() {
1852 use self::my_sum_example::dsl::*;
1853
1854 let connection = &mut connection();
1855 crate::sql_query(
1856 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1857 )
1858 .execute(connection)
1859 .unwrap();
1860 crate::sql_query("INSERT INTO my_sum_example (value) VALUES (1), (2), (3)")
1861 .execute(connection)
1862 .unwrap();
1863
1864 my_sum_utils::register_impl_with_behavior::<MySum, _>(
1865 connection,
1866 SqliteFunctionBehavior::DETERMINISTIC,
1867 )
1868 .unwrap();
1869
1870 let result = my_sum_example
1871 .select(my_sum(value))
1872 .get_result::<i32>(connection);
1873 assert_eq!(Ok(6), result);
1874 }
1875
1876 #[diesel_test_helper::test]
1877 fn register_aggregate_function_returns_finalize_default_on_empty_set() {
1878 use self::my_sum_example::dsl::*;
1879
1880 let connection = &mut connection();
1881 crate::sql_query(
1882 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1883 )
1884 .execute(connection)
1885 .unwrap();
1886
1887 my_sum_utils::register_impl_with_behavior::<MySum, _>(
1888 connection,
1889 SqliteFunctionBehavior::DETERMINISTIC,
1890 )
1891 .unwrap();
1892
1893 let result = my_sum_example
1894 .select(my_sum(value))
1895 .get_result::<i32>(connection);
1896 assert_eq!(Ok(0), result);
1897 }
1898
1899 #[derive(Default)]
1900 struct RangeMax<T> {
1901 max_value: Option<T>,
1902 }
1903
1904 impl<T: Default + Ord + Copy + Clone> SqliteAggregateFunction<(T, T, T)> for RangeMax<T> {
1905 type Output = Option<T>;
1906
1907 fn step(&mut self, (x0, x1, x2): (T, T, T)) {
1908 let max = if x0 >= x1 && x0 >= x2 {
1909 x0
1910 } else if x1 >= x0 && x1 >= x2 {
1911 x1
1912 } else {
1913 x2
1914 };
1915
1916 self.max_value = match self.max_value {
1917 Some(current_max_value) if max > current_max_value => Some(max),
1918 None => Some(max),
1919 _ => self.max_value,
1920 };
1921 }
1922
1923 fn finalize(aggregator: Option<Self>) -> Self::Output {
1924 aggregator?.max_value
1925 }
1926 }
1927
1928 table! {
1929 range_max_example {
1930 id -> Integer,
1931 value1 -> Integer,
1932 value2 -> Integer,
1933 value3 -> Integer,
1934 }
1935 }
1936
1937 #[diesel_test_helper::test]
1938 fn register_aggregate_multiarg_function() {
1939 use self::range_max_example::dsl::*;
1940
1941 let connection = &mut connection();
1942 crate::sql_query(
1943 r#"CREATE TABLE range_max_example (
1944 id integer primary key autoincrement,
1945 value1 integer,
1946 value2 integer,
1947 value3 integer
1948 )"#,
1949 )
1950 .execute(connection)
1951 .unwrap();
1952 crate::sql_query(
1953 "INSERT INTO range_max_example (value1, value2, value3) VALUES (3, 2, 1), (2, 2, 2)",
1954 )
1955 .execute(connection)
1956 .unwrap();
1957
1958 range_max_utils::register_impl_with_behavior::<RangeMax<i32>, _, _, _>(
1959 connection,
1960 SqliteFunctionBehavior::DETERMINISTIC,
1961 )
1962 .unwrap();
1963 let result = range_max_example
1964 .select(range_max(value1, value2, value3))
1965 .get_result::<Option<i32>>(connection)
1966 .unwrap();
1967 assert_eq!(Some(3), result);
1968 }
1969
1970 table! {
1971 my_collation_example {
1972 id -> Integer,
1973 value -> Text,
1974 }
1975 }
1976
1977 #[diesel_test_helper::test]
1978 fn register_collation_function() {
1979 use self::my_collation_example::dsl::*;
1980
1981 let connection = &mut connection();
1982
1983 connection
1984 .register_collation("RUSTNOCASE", |rhs, lhs| {
1985 rhs.to_lowercase().cmp(&lhs.to_lowercase())
1986 })
1987 .unwrap();
1988
1989 crate::sql_query(
1990 "CREATE TABLE my_collation_example (id integer primary key autoincrement, value text collate RUSTNOCASE)",
1991 ).execute(connection)
1992 .unwrap();
1993 crate::sql_query(
1994 "INSERT INTO my_collation_example (value) VALUES ('foo'), ('FOo'), ('f00')",
1995 )
1996 .execute(connection)
1997 .unwrap();
1998
1999 let result = my_collation_example
2000 .filter(value.eq("foo"))
2001 .select(value)
2002 .load::<String>(connection);
2003 assert_eq!(
2004 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
2005 result.as_ref().map(|vec| vec.as_ref())
2006 );
2007
2008 let result = my_collation_example
2009 .filter(value.eq("FOO"))
2010 .select(value)
2011 .load::<String>(connection);
2012 assert_eq!(
2013 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
2014 result.as_ref().map(|vec| vec.as_ref())
2015 );
2016
2017 let result = my_collation_example
2018 .filter(value.eq("f00"))
2019 .select(value)
2020 .load::<String>(connection);
2021 assert_eq!(
2022 Ok(&["f00".to_owned()][..]),
2023 result.as_ref().map(|vec| vec.as_ref())
2024 );
2025
2026 let result = my_collation_example
2027 .filter(value.eq("F00"))
2028 .select(value)
2029 .load::<String>(connection);
2030 assert_eq!(
2031 Ok(&["f00".to_owned()][..]),
2032 result.as_ref().map(|vec| vec.as_ref())
2033 );
2034
2035 let result = my_collation_example
2036 .filter(value.eq("oof"))
2037 .select(value)
2038 .load::<String>(connection);
2039 assert_eq!(Ok(&[][..]), result.as_ref().map(|vec| vec.as_ref()));
2040 }
2041
2042 #[diesel_test_helper::test]
2044 fn test_correct_serialization_of_owned_strings() {
2045 use crate::prelude::*;
2046
2047 #[derive(Debug, crate::expression::AsExpression)]
2048 #[diesel(sql_type = diesel::sql_types::Text)]
2049 struct CustomWrapper(String);
2050
2051 impl crate::serialize::ToSql<Text, Sqlite> for CustomWrapper {
2052 fn to_sql<'b>(
2053 &'b self,
2054 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
2055 ) -> crate::serialize::Result {
2056 out.set_value(self.0.to_string());
2057 Ok(crate::serialize::IsNull::No)
2058 }
2059 }
2060
2061 let connection = &mut connection();
2062
2063 let res = crate::select(
2064 CustomWrapper("".into())
2065 .into_sql::<crate::sql_types::Text>()
2066 .nullable(),
2067 )
2068 .get_result::<Option<String>>(connection)
2069 .unwrap();
2070 assert_eq!(res, Some(String::new()));
2071 }
2072
2073 #[diesel_test_helper::test]
2074 fn test_correct_serialization_of_owned_bytes() {
2075 use crate::prelude::*;
2076
2077 #[derive(Debug, crate::expression::AsExpression)]
2078 #[diesel(sql_type = diesel::sql_types::Binary)]
2079 struct CustomWrapper(Vec<u8>);
2080
2081 impl crate::serialize::ToSql<crate::sql_types::Binary, Sqlite> for CustomWrapper {
2082 fn to_sql<'b>(
2083 &'b self,
2084 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
2085 ) -> crate::serialize::Result {
2086 out.set_value(self.0.clone());
2087 Ok(crate::serialize::IsNull::No)
2088 }
2089 }
2090
2091 let connection = &mut connection();
2092
2093 let res = crate::select(
2094 CustomWrapper(Vec::new())
2095 .into_sql::<crate::sql_types::Binary>()
2096 .nullable(),
2097 )
2098 .get_result::<Option<Vec<u8>>>(connection)
2099 .unwrap();
2100 assert_eq!(res, Some(Vec::new()));
2101 }
2102
2103 #[diesel_test_helper::test]
2104 fn correctly_handle_empty_query() {
2105 let check_empty_query_error = |r: crate::QueryResult<usize>| {
2106 assert!(r.is_err());
2107 let err = r.unwrap_err();
2108 assert!(
2109 matches!(err, crate::result::Error::QueryBuilderError(ref b) if b.is::<crate::result::EmptyQuery>()),
2110 "Expected a query builder error, but got {err}"
2111 );
2112 };
2113 let connection = &mut SqliteConnection::establish(":memory:").unwrap();
2114 check_empty_query_error(crate::sql_query("").execute(connection));
2115 check_empty_query_error(crate::sql_query(" ").execute(connection));
2116 check_empty_query_error(crate::sql_query("\n\t").execute(connection));
2117 check_empty_query_error(crate::sql_query("-- SELECT 1;").execute(connection));
2118 }
2119
2120 #[diesel_test_helper::test]
2121 fn last_insert_rowid_returns_none_on_fresh_connection() {
2122 let conn = &mut connection();
2123 assert_eq!(conn.last_insert_rowid(), None);
2124 }
2125
2126 #[diesel_test_helper::test]
2127 fn last_insert_rowid_returns_rowid_after_insert() {
2128 let conn = &mut connection();
2129 crate::sql_query("CREATE TABLE li_test (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
2130 .execute(conn)
2131 .unwrap();
2132
2133 crate::sql_query("INSERT INTO li_test (val) VALUES ('a')")
2134 .execute(conn)
2135 .unwrap();
2136 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2137
2138 crate::sql_query("INSERT INTO li_test (val) VALUES ('b')")
2139 .execute(conn)
2140 .unwrap();
2141 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(2));
2142 }
2143
2144 #[diesel_test_helper::test]
2145 fn last_insert_rowid_unchanged_after_failed_insert() {
2146 let conn = &mut connection();
2147 crate::sql_query(
2148 "CREATE TABLE li_test2 (id INTEGER PRIMARY KEY, val TEXT NOT NULL UNIQUE)",
2149 )
2150 .execute(conn)
2151 .unwrap();
2152
2153 crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')")
2154 .execute(conn)
2155 .unwrap();
2156 let rowid = conn.last_insert_rowid();
2157 assert_eq!(rowid, NonZeroI64::new(1));
2158
2159 let result = crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')").execute(conn);
2161 assert!(result.is_err());
2162
2163 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2165 }
2166
2167 #[diesel_test_helper::test]
2168 fn last_insert_rowid_with_explicit_rowid() {
2169 let conn = &mut connection();
2170 crate::sql_query("CREATE TABLE li_test3 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
2171 .execute(conn)
2172 .unwrap();
2173
2174 crate::sql_query("INSERT INTO li_test3 (id, val) VALUES (42, 'a')")
2175 .execute(conn)
2176 .unwrap();
2177 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(42));
2178 }
2179
2180 #[diesel_test_helper::test]
2181 fn last_insert_rowid_unchanged_after_delete_and_update() {
2182 let conn = &mut connection();
2183 crate::sql_query("CREATE TABLE li_test4 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
2184 .execute(conn)
2185 .unwrap();
2186
2187 crate::sql_query("INSERT INTO li_test4 (val) VALUES ('a')")
2188 .execute(conn)
2189 .unwrap();
2190 let rowid = conn.last_insert_rowid();
2191 assert_eq!(rowid, NonZeroI64::new(1));
2192
2193 crate::sql_query("UPDATE li_test4 SET val = 'b' WHERE id = 1")
2194 .execute(conn)
2195 .unwrap();
2196 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2197
2198 crate::sql_query("DELETE FROM li_test4 WHERE id = 1")
2199 .execute(conn)
2200 .unwrap();
2201 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
2202 }
2203
2204 #[diesel_test_helper::test]
2205 fn read_bytes_from_blob() {
2206 table! {
2207 blobs {
2208 id -> Integer,
2209 data -> Blob,
2210 data2 -> Blob,
2211 }
2212 }
2213
2214 use std::io::Read;
2215
2216 let conn = &mut connection();
2217
2218 let _ =
2219 crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB, data2 BLOB)")
2220 .execute(conn);
2221
2222 let _ = crate::sql_query(
2223 "INSERT INTO blobs (data, data2) VALUES ('abc', 'def'), ('123', '456')",
2224 )
2225 .execute(conn);
2226
2227 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2228 let mut buf = vec![];
2229 data.read_to_end(&mut buf).unwrap();
2230
2231 assert_eq!(buf, b"abc");
2232
2233 let mut data2 = conn.get_read_only_blob(blobs::data2, 1).unwrap();
2234 let mut buf = vec![];
2235 data2.read_to_end(&mut buf).unwrap();
2236
2237 assert_eq!(buf, b"def");
2238 }
2239
2240 #[diesel_test_helper::test]
2241 fn read_seek_bytes() {
2242 table! {
2243 blobs {
2244 id -> Integer,
2245 data -> Blob,
2246 }
2247 }
2248
2249 use std::io::Read;
2250 use std::io::Seek;
2251 use std::io::SeekFrom;
2252
2253 let conn = &mut connection();
2254
2255 let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
2256 .execute(conn);
2257
2258 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abcdefghi')").execute(conn);
2259
2260 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2261
2262 let mut buf = [0; 1];
2263 assert_eq!(data.read(&mut buf).unwrap(), 1);
2264 assert_eq!(&buf, b"a");
2265
2266 assert_eq!(data.seek(SeekFrom::Current(1)).unwrap(), 2);
2268
2269 let mut buf = [0; 1];
2270 assert_eq!(data.read(&mut buf).unwrap(), 1);
2271 assert_eq!(&buf, b"c");
2272
2273 assert_eq!(data.seek(SeekFrom::Start(0)).unwrap(), 0);
2275
2276 let mut buf = [0; 1];
2277 assert_eq!(data.read(&mut buf).unwrap(), 1);
2278 assert_eq!(&buf, b"a");
2279
2280 assert_eq!(data.seek(SeekFrom::Current(-10)).unwrap(), 0);
2282
2283 let mut buf = [0; 1];
2284 assert_eq!(data.read(&mut buf).unwrap(), 1);
2285 assert_eq!(&buf, b"a");
2286
2287 data.seek(SeekFrom::Current(100)).unwrap();
2289
2290 let mut buf = [0; 1];
2292 assert_eq!(data.read(&mut buf).unwrap(), 0);
2293 }
2294
2295 #[diesel_test_helper::test]
2296 fn use_conn_after_blob_drop() {
2297 table! {
2298 blobs {
2299 id -> Integer,
2300 data -> Blob,
2301 }
2302 }
2303
2304 let conn = &mut connection();
2305
2306 let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
2307 .execute(conn);
2308
2309 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abc')").execute(conn);
2310
2311 let data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2312 drop(data);
2313
2314 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('def')").execute(conn);
2315 }
2316
2317 #[diesel_test_helper::test]
2318 fn blob_transaction() {
2319 table! {
2320 blobs {
2321 id -> Integer,
2322 data -> Blob,
2323 }
2324 }
2325
2326 use std::io::Read;
2327
2328 let conn = &mut connection();
2329
2330 let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
2331 .execute(conn);
2332
2333 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abc')").execute(conn);
2334
2335 {
2336 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2337 let mut buf = vec![];
2338 data.read_to_end(&mut buf).unwrap();
2339 assert_eq!(buf, b"abc");
2340 }
2341
2342 let res = conn.exclusive_transaction(|conn| {
2343 crate::sql_query("UPDATE blobs SET data = 'def' WHERE id = 1").execute(conn)?;
2344
2345 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2346 let mut buf = vec![];
2347 data.read_to_end(&mut buf).unwrap();
2348 assert_eq!(buf, b"def");
2349
2350 Result::<(), _>::Err(Error::RollbackTransaction)
2351 });
2352
2353 assert_eq!(res.unwrap_err(), Error::RollbackTransaction);
2354
2355 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
2356 let mut buf = vec![];
2357 data.read_to_end(&mut buf).unwrap();
2358 assert_eq!(buf, b"abc");
2359 }
2360
2361 #[diesel_test_helper::test]
2362 fn aggregate_function_works_with_aligned_data() {
2363 #[derive(Debug, Default)]
2364 #[repr(align(64))]
2365 struct OverAligned;
2366
2367 impl SqliteAggregateFunction<i32> for OverAligned {
2368 type Output = i64;
2369
2370 fn step(&mut self, _value: i32) {
2371 let need = core::mem::align_of::<Self>();
2372 let got = core::mem::align_of_val(self);
2373 assert_eq!(need, got);
2374 }
2375
2376 fn finalize(_agg: Option<Self>) -> i64 {
2377 0
2378 }
2379 }
2380 #[declare_sql_function]
2381 extern "SQL" {
2382 #[aggregate]
2383 fn over_aligned_sum(x: Integer) -> diesel::sql_types::BigInt;
2384 }
2385
2386 let mut conn = SqliteConnection::establish(":memory:").unwrap();
2387 over_aligned_sum_utils::register_impl::<OverAligned, _>(&mut conn).unwrap();
2388
2389 diesel::select(over_aligned_sum(1))
2390 .execute(&mut conn)
2391 .unwrap();
2392 }
2393
2394 #[diesel_test_helper::test]
2395 fn sum_twice() {
2396 #[derive(Default)]
2397 struct Sum(i32);
2398
2399 impl SqliteAggregateFunction<i32> for Sum {
2400 type Output = i32;
2401
2402 fn step(&mut self, value: i32) {
2403 self.0 += value;
2404 }
2405
2406 fn finalize(agg: Option<Self>) -> i32 {
2407 agg.map(|s| s.0).unwrap_or_default()
2408 }
2409 }
2410
2411 #[declare_sql_function]
2412 extern "SQL" {
2413 #[aggregate]
2414 fn my_sum(x: Integer) -> Integer;
2415 }
2416
2417 let mut conn = SqliteConnection::establish(":memory:").unwrap();
2418 my_sum_utils::register_impl::<Sum, _>(&mut conn).unwrap();
2419
2420 conn.batch_execute(
2421 "
2422 CREATE TABLE test(key1 INTEGER, key2 INTEGER);
2423 INSERT INTO test(key1, key2) VALUES (1, 2), (2, 4), (3, 6);
2424",
2425 )
2426 .unwrap();
2427
2428 table! {
2429 test (key1, key2) {
2430 key1 -> Integer,
2431 key2 -> Integer,
2432 }
2433 }
2434
2435 let (first_res, second_res) = test::table
2436 .select((my_sum(test::key1), my_sum(test::key2)))
2437 .get_result::<(i32, i32)>(&mut conn)
2438 .unwrap();
2439
2440 assert_eq!(first_res, 6);
2441 assert_eq!(second_res, 12);
2442
2443 conn.batch_execute("DELETE FROM test").unwrap();
2444 let (first_res, second_res) = test::table
2445 .select((my_sum(test::key1), my_sum(test::key2)))
2446 .get_result::<(i32, i32)>(&mut conn)
2447 .unwrap();
2448
2449 assert_eq!(first_res, 0);
2450 assert_eq!(second_res, 0);
2451 }
2452
2453 #[diesel_test_helper::test]
2454 fn test_injection() {
2455 diesel::table! {
2456 #[sql_name = "quote'table"]
2457 quote_table (id) {
2458 id -> Nullable<Integer>,
2459 name -> Nullable<Text>,
2460 }
2461 }
2462
2463 let mut conn = SqliteConnection::establish(":memory:").unwrap();
2464
2465 conn.batch_execute("CREATE TABLE \"quote'table\" (id INTEGER PRIMARY KEY, name TEXT);")
2466 .unwrap();
2467
2468 diesel::insert_into(quote_table::table)
2469 .values((quote_table::id.eq(1), quote_table::name.eq("Jane")))
2470 .execute(&mut conn)
2471 .unwrap();
2472
2473 let data = quote_table::table
2474 .load::<(Option<i32>, Option<String>)>(&mut conn)
2475 .unwrap();
2476 assert_eq!(data, [(Some(1), Some("Jane".to_owned()))]);
2477 }
2478
2479 #[diesel_test_helper::test]
2480 fn set_limit_returns_previous_value() {
2481 let mut conn = connection();
2482 let original = conn.get_limit(SqliteLimit::SqlLength);
2483
2484 assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 1024), original);
2487 assert_eq!(conn.set_limit(SqliteLimit::SqlLength, 2048), 1024);
2488 assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 2048);
2489 }
2490
2491 #[diesel_test_helper::test]
2492 fn get_limit_does_not_mutate() {
2493 let conn = connection();
2494 let first = conn.get_limit(SqliteLimit::ExprDepth);
2495 assert!(first > 0);
2498 assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), first);
2499 }
2500
2501 #[diesel_test_helper::test]
2502 fn set_limit_enforces_length() {
2503 let mut conn = connection();
2504 conn.set_limit(SqliteLimit::Length, 100);
2505
2506 assert!(
2507 crate::sql_query("SELECT length(randomblob(50))")
2508 .execute(&mut conn)
2509 .is_ok()
2510 );
2511 assert!(
2513 crate::sql_query("SELECT length(randomblob(500))")
2514 .execute(&mut conn)
2515 .is_err()
2516 );
2517 }
2518
2519 #[diesel_test_helper::test]
2520 fn set_limit_enforces_column_count() {
2521 let wide = format!(
2524 "SELECT {}",
2525 (1..=30)
2526 .map(|i| i.to_string())
2527 .collect::<Vec<_>>()
2528 .join(", ")
2529 );
2530
2531 let mut unconstrained = connection();
2532 assert!(crate::sql_query(&wide).execute(&mut unconstrained).is_ok());
2533
2534 let mut conn = connection();
2535 conn.set_limit(SqliteLimit::ColumnCount, 10);
2536 assert!(crate::sql_query(&wide).execute(&mut conn).is_err());
2537 }
2538
2539 #[diesel_test_helper::test]
2540 fn set_limit_enforces_expr_depth() {
2541 let mut conn = connection();
2542 conn.set_limit(SqliteLimit::ExprDepth, 5);
2543
2544 assert!(crate::sql_query("SELECT 1+1").execute(&mut conn).is_ok());
2545 let deep = format!("SELECT {}1", "1+".repeat(40));
2547 assert!(crate::sql_query(&deep).execute(&mut conn).is_err());
2548 }
2549
2550 #[diesel_test_helper::test]
2551 fn set_limit_enforces_compound_select() {
2552 let mut conn = connection();
2553 conn.set_limit(SqliteLimit::CompoundSelect, 2);
2554
2555 assert!(
2556 crate::sql_query("SELECT 1 UNION SELECT 2")
2557 .execute(&mut conn)
2558 .is_ok()
2559 );
2560 assert!(
2562 crate::sql_query(
2563 "SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5"
2564 )
2565 .execute(&mut conn)
2566 .is_err()
2567 );
2568 }
2569
2570 #[diesel_test_helper::test]
2571 fn set_limit_enforces_vdbe_op() {
2572 let heavy = "SELECT count(*) FROM sqlite_master a, sqlite_master b, sqlite_master c";
2575
2576 let mut unconstrained = connection();
2577 assert!(crate::sql_query(heavy).execute(&mut unconstrained).is_ok());
2578
2579 let mut conn = connection();
2580 conn.set_limit(SqliteLimit::VdbeOp, 5);
2581 assert!(crate::sql_query(heavy).execute(&mut conn).is_err());
2582 }
2583
2584 #[diesel_test_helper::test]
2585 fn set_limit_enforces_function_arg() {
2586 let mut conn = connection();
2587 conn.set_limit(SqliteLimit::FunctionArg, 3);
2588
2589 assert!(
2590 crate::sql_query("SELECT max(1, 2, 3)")
2591 .execute(&mut conn)
2592 .is_ok()
2593 );
2594 assert!(
2596 crate::sql_query("SELECT max(1, 2, 3, 4, 5, 6, 7, 8)")
2597 .execute(&mut conn)
2598 .is_err()
2599 );
2600 }
2601
2602 #[diesel_test_helper::test]
2603 fn set_limit_enforces_attached() {
2604 let mut conn = connection();
2605 conn.set_limit(SqliteLimit::Attached, 0);
2606
2607 assert!(
2609 crate::sql_query("ATTACH DATABASE ':memory:' AS aux_db")
2610 .execute(&mut conn)
2611 .is_err()
2612 );
2613 }
2614
2615 #[diesel_test_helper::test]
2616 fn set_limit_enforces_variable_number() {
2617 let mut conn = connection();
2618 conn.set_limit(
2622 SqliteLimit::VariableNumber,
2623 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
2624 );
2625 let at_limit = format!("SELECT ?{}", SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT);
2626 let past_limit = format!(
2627 "SELECT ?{}",
2628 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT as i64 + 1
2629 );
2630 assert!(crate::sql_query(&at_limit).execute(&mut conn).is_ok());
2631 assert!(crate::sql_query(&past_limit).execute(&mut conn).is_err());
2632 }
2633
2634 #[diesel_test_helper::test]
2635 fn set_limit_enforces_trigger_depth() {
2636 use crate::connection::SimpleConnection;
2637
2638 let setup = "PRAGMA recursive_triggers = ON;\
2640 CREATE TABLE recur (x INTEGER);\
2641 CREATE TRIGGER recur_tr AFTER INSERT ON recur WHEN NEW.x < 100 \
2642 BEGIN INSERT INTO recur VALUES (NEW.x + 1); END;";
2643
2644 let mut unconstrained = connection();
2646 unconstrained.batch_execute(setup).unwrap();
2647 assert!(
2648 crate::sql_query("INSERT INTO recur VALUES (1)")
2649 .execute(&mut unconstrained)
2650 .is_ok()
2651 );
2652
2653 let mut conn = connection();
2656 conn.set_limit(SqliteLimit::TriggerDepth, 3);
2657 conn.batch_execute(setup).unwrap();
2658 assert!(
2659 crate::sql_query("INSERT INTO recur VALUES (1)")
2660 .execute(&mut conn)
2661 .is_err()
2662 );
2663 }
2664
2665 #[diesel_test_helper::test]
2666 fn worker_threads_limit_has_no_runtime_error_path() {
2667 let mut conn = connection();
2672 conn.set_limit(SqliteLimit::WorkerThreads, 0);
2673 assert_eq!(conn.get_limit(SqliteLimit::WorkerThreads), 0);
2674 assert!(crate::sql_query("SELECT 1").execute(&mut conn).is_ok());
2675 }
2676
2677 #[diesel_test_helper::test]
2678 fn set_limit_enforces_sql_length() {
2679 let mut conn = connection();
2680 conn.set_limit(SqliteLimit::SqlLength, 20);
2681
2682 let result =
2684 crate::sql_query("SELECT * FROM sqlite_master WHERE type = 'table'").execute(&mut conn);
2685 assert!(result.is_err());
2686 }
2687
2688 #[diesel_test_helper::test]
2689 fn set_limit_enforces_like_pattern_length() {
2690 let mut conn = connection();
2691 conn.set_limit(SqliteLimit::LikePatternLength, 100);
2692
2693 assert!(
2694 crate::sql_query("SELECT 'test' LIKE 'te%'")
2695 .execute(&mut conn)
2696 .is_ok()
2697 );
2698
2699 let long_pattern = "%".repeat(200);
2700 let query = format!("SELECT 'test' LIKE '{long_pattern}'");
2701 assert!(crate::sql_query(&query).execute(&mut conn).is_err());
2702 }
2703
2704 #[diesel_test_helper::test]
2705 fn set_limit_clamps_above_compile_time_maximum() {
2706 let mut conn = connection();
2707 conn.set_limit(SqliteLimit::Length, i32::MAX);
2710 let clamped = conn.get_limit(SqliteLimit::Length);
2711 assert!(clamped > 0 && clamped < i32::MAX);
2712 }
2713
2714 #[diesel_test_helper::test]
2715 fn set_recommended_security_limits_applies_documented_table() {
2716 let mut conn = connection();
2717 conn.set_recommended_security_limits();
2718
2719 assert_eq!(conn.get_limit(SqliteLimit::Length), 1_000_000);
2720 assert_eq!(conn.get_limit(SqliteLimit::SqlLength), 100_000);
2721 assert_eq!(conn.get_limit(SqliteLimit::ColumnCount), 100);
2722 assert_eq!(conn.get_limit(SqliteLimit::ExprDepth), 10);
2723 assert_eq!(conn.get_limit(SqliteLimit::CompoundSelect), 3);
2724 assert_eq!(conn.get_limit(SqliteLimit::VdbeOp), 25_000);
2725 assert_eq!(conn.get_limit(SqliteLimit::FunctionArg), 8);
2726 assert_eq!(conn.get_limit(SqliteLimit::Attached), 0);
2727 assert_eq!(conn.get_limit(SqliteLimit::LikePatternLength), 50);
2728 assert_eq!(conn.get_limit(SqliteLimit::VariableNumber), 10);
2729 assert_eq!(conn.get_limit(SqliteLimit::TriggerDepth), 10);
2730 }
2731
2732 #[diesel_test_helper::test]
2733 fn safe_limit_constants_do_not_exceed_defaults() {
2734 let pairs = [
2740 (
2741 SqliteLimit::SAFE_LENGTH_LIMIT,
2742 SqliteLimit::DEFAULT_LENGTH_LIMIT,
2743 ),
2744 (
2745 SqliteLimit::SAFE_SQL_LENGTH_LIMIT,
2746 SqliteLimit::DEFAULT_SQL_LENGTH_LIMIT,
2747 ),
2748 (
2749 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT,
2750 SqliteLimit::DEFAULT_COLUMN_COUNT_LIMIT,
2751 ),
2752 (
2753 SqliteLimit::SAFE_EXPR_DEPTH_LIMIT,
2754 SqliteLimit::DEFAULT_EXPR_DEPTH_LIMIT,
2755 ),
2756 (
2757 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT,
2758 SqliteLimit::DEFAULT_COMPOUND_SELECT_LIMIT,
2759 ),
2760 (
2761 SqliteLimit::SAFE_VDBE_OP_LIMIT,
2762 SqliteLimit::DEFAULT_VDBE_OP_LIMIT,
2763 ),
2764 (
2765 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT,
2766 SqliteLimit::DEFAULT_FUNCTION_ARG_LIMIT,
2767 ),
2768 (
2769 SqliteLimit::SAFE_ATTACHED_LIMIT,
2770 SqliteLimit::DEFAULT_ATTACHED_LIMIT,
2771 ),
2772 (
2773 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT,
2774 SqliteLimit::DEFAULT_LIKE_PATTERN_LENGTH_LIMIT,
2775 ),
2776 (
2777 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT,
2778 SqliteLimit::DEFAULT_VARIABLE_NUMBER_LIMIT,
2779 ),
2780 (
2781 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT,
2782 SqliteLimit::DEFAULT_TRIGGER_DEPTH_LIMIT,
2783 ),
2784 (
2785 SqliteLimit::SAFE_WORKER_THREADS_LIMIT,
2786 SqliteLimit::DEFAULT_WORKER_THREADS_LIMIT,
2787 ),
2788 ];
2789 for (safe, default) in pairs {
2790 assert!(
2791 safe <= default,
2792 "safe value {safe} exceeds default {default}"
2793 );
2794 }
2795 }
2796
2797 #[diesel_test_helper::test]
2798 fn safe_limit_constants_match_recommended_setter() {
2799 let mut conn = connection();
2800 conn.set_recommended_security_limits();
2801
2802 assert_eq!(
2803 conn.get_limit(SqliteLimit::Length),
2804 SqliteLimit::SAFE_LENGTH_LIMIT
2805 );
2806 assert_eq!(
2807 conn.get_limit(SqliteLimit::SqlLength),
2808 SqliteLimit::SAFE_SQL_LENGTH_LIMIT
2809 );
2810 assert_eq!(
2811 conn.get_limit(SqliteLimit::ColumnCount),
2812 SqliteLimit::SAFE_COLUMN_COUNT_LIMIT
2813 );
2814 assert_eq!(
2815 conn.get_limit(SqliteLimit::ExprDepth),
2816 SqliteLimit::SAFE_EXPR_DEPTH_LIMIT
2817 );
2818 assert_eq!(
2819 conn.get_limit(SqliteLimit::CompoundSelect),
2820 SqliteLimit::SAFE_COMPOUND_SELECT_LIMIT
2821 );
2822 assert_eq!(
2823 conn.get_limit(SqliteLimit::VdbeOp),
2824 SqliteLimit::SAFE_VDBE_OP_LIMIT
2825 );
2826 assert_eq!(
2827 conn.get_limit(SqliteLimit::FunctionArg),
2828 SqliteLimit::SAFE_FUNCTION_ARG_LIMIT
2829 );
2830 assert_eq!(
2831 conn.get_limit(SqliteLimit::Attached),
2832 SqliteLimit::SAFE_ATTACHED_LIMIT
2833 );
2834 assert_eq!(
2835 conn.get_limit(SqliteLimit::LikePatternLength),
2836 SqliteLimit::SAFE_LIKE_PATTERN_LENGTH_LIMIT
2837 );
2838 assert_eq!(
2839 conn.get_limit(SqliteLimit::VariableNumber),
2840 SqliteLimit::SAFE_VARIABLE_NUMBER_LIMIT
2841 );
2842 assert_eq!(
2843 conn.get_limit(SqliteLimit::TriggerDepth),
2844 SqliteLimit::SAFE_TRIGGER_DEPTH_LIMIT
2845 );
2846 assert_eq!(
2849 conn.get_limit(SqliteLimit::WorkerThreads),
2850 SqliteLimit::SAFE_WORKER_THREADS_LIMIT
2851 );
2852 }
2853
2854 #[diesel_test_helper::test]
2857 fn db_config_defensive_roundtrip() {
2858 let conn = &mut connection();
2859 conn.set_defensive(true).unwrap();
2860 assert!(conn.is_defensive().unwrap());
2861 conn.set_defensive(false).unwrap();
2862 assert!(!conn.is_defensive().unwrap());
2863 }
2864
2865 #[diesel_test_helper::test]
2866 fn db_config_trusted_schema_roundtrip() {
2867 let conn = &mut connection();
2868 conn.set_trusted_schema(false).unwrap();
2869 assert!(!conn.is_trusted_schema().unwrap());
2870 conn.set_trusted_schema(true).unwrap();
2871 assert!(conn.is_trusted_schema().unwrap());
2872 }
2873
2874 #[diesel_test_helper::test]
2875 fn db_config_with_load_extension_enabled_scopes_the_flag() {
2876 let conn = &mut connection();
2877 conn.with_load_extension_enabled(|conn| {
2878 assert!(conn.is_load_extension_enabled().unwrap());
2880 QueryResult::Ok(())
2881 })
2882 .unwrap();
2883 assert!(!conn.is_load_extension_enabled().unwrap());
2885 }
2886
2887 #[cfg(all(
2888 feature = "std",
2889 not(all(target_family = "wasm", target_os = "unknown"))
2890 ))]
2891 #[diesel_test_helper::test]
2892 fn with_load_extension_enabled_disables_after_panic() {
2893 let conn = &mut connection();
2894 let outcome = std::panic::catch_unwind(core::panic::AssertUnwindSafe(|| {
2895 conn.with_load_extension_enabled(|_conn| -> QueryResult<()> {
2896 panic!("boom inside closure");
2897 })
2898 }));
2899 assert!(outcome.is_err(), "panic should propagate");
2900 assert!(
2901 !conn.is_load_extension_enabled().unwrap(),
2902 "extension loading must be disabled again after a panic"
2903 );
2904 }
2905
2906 #[diesel_test_helper::test]
2907 fn db_config_triggers_roundtrip() {
2908 let conn = &mut connection();
2909 conn.set_triggers_enabled(false).unwrap();
2910 assert!(!conn.are_triggers_enabled().unwrap());
2911 conn.set_triggers_enabled(true).unwrap();
2912 assert!(conn.are_triggers_enabled().unwrap());
2913 }
2914
2915 #[diesel_test_helper::test]
2916 fn db_config_views_roundtrip() {
2917 let conn = &mut connection();
2918 conn.set_views_enabled(false).unwrap();
2919 assert!(!conn.are_views_enabled().unwrap());
2920 conn.set_views_enabled(true).unwrap();
2921 assert!(conn.are_views_enabled().unwrap());
2922 }
2923
2924 #[diesel_test_helper::test]
2925 fn db_config_foreign_keys_roundtrip() {
2926 let conn = &mut connection();
2927 conn.set_foreign_keys_enabled(true).unwrap();
2928 assert!(conn.are_foreign_keys_enabled().unwrap());
2929 conn.set_foreign_keys_enabled(false).unwrap();
2930 assert!(!conn.are_foreign_keys_enabled().unwrap());
2931 }
2932
2933 #[diesel_test_helper::test]
2934 fn db_config_dqs_dml_roundtrip() {
2935 let conn = &mut connection();
2936 conn.set_double_quoted_strings_dml(false).unwrap();
2937 assert!(!conn.are_double_quoted_strings_dml_enabled().unwrap());
2938 conn.set_double_quoted_strings_dml(true).unwrap();
2939 assert!(conn.are_double_quoted_strings_dml_enabled().unwrap());
2940 }
2941
2942 #[diesel_test_helper::test]
2943 fn db_config_dqs_ddl_roundtrip() {
2944 let conn = &mut connection();
2945 conn.set_double_quoted_strings_ddl(false).unwrap();
2946 assert!(!conn.are_double_quoted_strings_ddl_enabled().unwrap());
2947 conn.set_double_quoted_strings_ddl(true).unwrap();
2948 assert!(conn.are_double_quoted_strings_ddl_enabled().unwrap());
2949 }
2950
2951 #[diesel_test_helper::test]
2952 fn db_config_fts3_tokenizer_roundtrip() {
2953 let conn = &mut connection();
2954 conn.set_fts3_tokenizer_enabled(false).unwrap();
2955 assert!(!conn.is_fts3_tokenizer_enabled().unwrap());
2956 conn.set_fts3_tokenizer_enabled(true).unwrap();
2957 assert!(conn.is_fts3_tokenizer_enabled().unwrap());
2958 }
2959
2960 #[diesel_test_helper::test]
2961 fn db_config_writable_schema_roundtrip() {
2962 let conn = &mut connection();
2963 conn.set_writable_schema(false).unwrap();
2964 assert!(!conn.is_writable_schema().unwrap());
2965 conn.set_writable_schema(true).unwrap();
2966 assert!(conn.is_writable_schema().unwrap());
2967 }
2968
2969 #[diesel_test_helper::test]
2970 fn db_config_attach_create_roundtrip() {
2971 let conn = &mut connection();
2972 if conn.set_attach_create_enabled(false).is_err() {
2974 return;
2975 }
2976 assert!(!conn.is_attach_create_enabled().unwrap());
2977 conn.set_attach_create_enabled(true).unwrap();
2978 assert!(conn.is_attach_create_enabled().unwrap());
2979 }
2980
2981 #[diesel_test_helper::test]
2982 fn db_config_attach_write_roundtrip() {
2983 let conn = &mut connection();
2984 if conn.set_attach_write_enabled(false).is_err() {
2986 return;
2987 }
2988 assert!(!conn.is_attach_write_enabled().unwrap());
2989 conn.set_attach_write_enabled(true).unwrap();
2990 assert!(conn.is_attach_write_enabled().unwrap());
2991 }
2992
2993 #[diesel_test_helper::test]
2996 fn defensive_mode_blocks_writable_schema() {
2997 let conn = &mut connection();
2998 conn.set_defensive(true).unwrap();
2999 let _ = crate::sql_query("PRAGMA writable_schema = ON").execute(conn);
3001 assert!(!conn.is_writable_schema().unwrap());
3002 }
3003
3004 #[diesel_test_helper::test]
3005 fn foreign_keys_enabled_enforces_constraints() {
3006 let conn = &mut connection();
3007 conn.set_foreign_keys_enabled(true).unwrap();
3008
3009 crate::sql_query("CREATE TABLE parent (id INTEGER PRIMARY KEY)")
3010 .execute(conn)
3011 .unwrap();
3012 crate::sql_query(
3013 "CREATE TABLE child (id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES parent(id))",
3014 )
3015 .execute(conn)
3016 .unwrap();
3017
3018 let result =
3020 crate::sql_query("INSERT INTO child (id, parent_id) VALUES (1, 999)").execute(conn);
3021 assert!(result.is_err());
3022 }
3023
3024 #[diesel_test_helper::test]
3025 fn views_disabled_blocks_view_queries() {
3026 let conn = &mut connection();
3027 crate::sql_query("CREATE TABLE base (id INTEGER PRIMARY KEY)")
3028 .execute(conn)
3029 .unwrap();
3030 crate::sql_query("INSERT INTO base (id) VALUES (1)")
3031 .execute(conn)
3032 .unwrap();
3033 crate::sql_query("CREATE VIEW base_view AS SELECT id FROM base")
3034 .execute(conn)
3035 .unwrap();
3036
3037 conn.set_views_enabled(true).unwrap();
3039 assert!(
3040 crate::sql_query("SELECT id FROM base_view")
3041 .execute(conn)
3042 .is_ok()
3043 );
3044
3045 conn.set_views_enabled(false).unwrap();
3047 assert!(
3048 crate::sql_query("SELECT id FROM base_view")
3049 .execute(conn)
3050 .is_err()
3051 );
3052 }
3053
3054 #[diesel_test_helper::test]
3055 fn triggers_disabled_prevents_firing() {
3056 let conn = &mut connection();
3057 crate::sql_query("CREATE TABLE source (id INTEGER PRIMARY KEY)")
3058 .execute(conn)
3059 .unwrap();
3060 crate::sql_query("CREATE TABLE trigger_log (n INTEGER)")
3061 .execute(conn)
3062 .unwrap();
3063 crate::sql_query("CREATE TRIGGER log_insert AFTER INSERT ON source BEGIN INSERT INTO trigger_log (n) VALUES (1); END")
3064 .execute(conn)
3065 .unwrap();
3066
3067 conn.set_triggers_enabled(false).unwrap();
3069 crate::sql_query("INSERT INTO source (id) VALUES (1)")
3070 .execute(conn)
3071 .unwrap();
3072 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM trigger_log")
3073 .get_result(conn)
3074 .unwrap();
3075 assert_eq!(0, count, "trigger should not fire while disabled");
3076
3077 conn.set_triggers_enabled(true).unwrap();
3079 crate::sql_query("INSERT INTO source (id) VALUES (2)")
3080 .execute(conn)
3081 .unwrap();
3082 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM trigger_log")
3083 .get_result(conn)
3084 .unwrap();
3085 assert_eq!(1, count, "trigger should fire while enabled");
3086 }
3087
3088 #[diesel_test_helper::test]
3089 fn dqs_dml_controls_double_quoted_string_literals() {
3090 let conn = &mut connection();
3091
3092 conn.set_double_quoted_strings_dml(false).unwrap();
3095 let disabled = sql::<Text>(r#"SELECT "bare_token""#).get_result::<String>(conn);
3096 assert!(disabled.is_err());
3097
3098 conn.set_double_quoted_strings_dml(true).unwrap();
3100 let enabled = sql::<Text>(r#"SELECT "bare_token""#).get_result::<String>(conn);
3101 assert_eq!(Ok("bare_token".to_owned()), enabled);
3102 }
3103
3104 #[diesel_test_helper::test]
3105 fn dqs_ddl_controls_double_quoted_string_literals() {
3106 let conn = &mut connection();
3107
3108 conn.set_double_quoted_strings_ddl(false).unwrap();
3111 let disabled =
3112 crate::sql_query(r#"CREATE TABLE dqs_off (name TEXT, CHECK (name <> "not_a_column"))"#)
3113 .execute(conn);
3114 assert!(disabled.is_err());
3115
3116 conn.set_double_quoted_strings_ddl(true).unwrap();
3119 let enabled =
3120 crate::sql_query(r#"CREATE TABLE dqs_on (name TEXT, CHECK (name <> "not_a_column"))"#)
3121 .execute(conn);
3122 assert!(enabled.is_ok());
3123 }
3124
3125 #[diesel_test_helper::test]
3126 fn writable_schema_controls_direct_sqlite_master_writes() {
3127 let conn = &mut connection();
3128 crate::sql_query("CREATE TABLE protected (id INTEGER PRIMARY KEY)")
3129 .execute(conn)
3130 .unwrap();
3131
3132 let update =
3133 "UPDATE sqlite_master SET sql = sql WHERE type = 'table' AND name = 'protected'";
3134
3135 conn.set_writable_schema(false).unwrap();
3137 assert!(crate::sql_query(update).execute(conn).is_err());
3138
3139 conn.set_writable_schema(true).unwrap();
3141 assert!(crate::sql_query(update).execute(conn).is_ok());
3142 }
3143
3144 #[diesel_test_helper::test]
3145 fn fts3_tokenizer_disabled_blocks_the_function() {
3146 let conn = &mut connection();
3147
3148 conn.set_fts3_tokenizer_enabled(true).unwrap();
3150 let enabled = sql::<crate::sql_types::Binary>("SELECT fts3_tokenizer('simple')")
3151 .get_result::<Vec<u8>>(conn);
3152 if enabled.is_err() {
3153 return;
3155 }
3156
3157 conn.set_fts3_tokenizer_enabled(false).unwrap();
3159 let disabled = sql::<crate::sql_types::Binary>("SELECT fts3_tokenizer('simple')")
3160 .get_result::<Vec<u8>>(conn);
3161 assert!(disabled.is_err());
3162 }
3163
3164 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3167 fn temp_db_path(tag: &str) -> std::path::PathBuf {
3168 let mut path = std::env::temp_dir();
3169 path.push(format!("diesel_attach_{}_{}.db", std::process::id(), tag));
3170 path
3171 }
3172
3173 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3174 #[diesel_test_helper::test]
3175 fn attach_create_disabled_blocks_new_database_files() {
3176 let conn = &mut connection();
3177
3178 if conn.set_attach_create_enabled(false).is_err() {
3181 return;
3182 }
3183
3184 let path = temp_db_path("create");
3185 let _ = std::fs::remove_file(&path);
3186 let attach = format!("ATTACH DATABASE '{}' AS aux_create", path.display());
3187
3188 assert!(crate::sql_query(&attach).execute(conn).is_err());
3190
3191 conn.set_attach_create_enabled(true).unwrap();
3193 crate::sql_query(&attach).execute(conn).unwrap();
3194 crate::sql_query("DETACH DATABASE aux_create")
3195 .execute(conn)
3196 .unwrap();
3197
3198 let _ = std::fs::remove_file(&path);
3199 }
3200
3201 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3202 #[diesel_test_helper::test]
3203 fn attach_write_disabled_opens_attached_databases_read_only() {
3204 let conn = &mut connection();
3205
3206 if conn.set_attach_write_enabled(false).is_err() {
3210 return;
3211 }
3212
3213 let path = temp_db_path("write");
3215 let _ = std::fs::remove_file(&path);
3216 {
3217 let mut seed = SqliteConnection::establish(path.to_str().unwrap()).unwrap();
3218 crate::sql_query("CREATE TABLE t (id INTEGER)")
3219 .execute(&mut seed)
3220 .unwrap();
3221 }
3222 let attach = format!("ATTACH DATABASE '{}' AS aux_write", path.display());
3223
3224 crate::sql_query(&attach).execute(conn).unwrap();
3226 assert!(
3227 crate::sql_query("INSERT INTO aux_write.t (id) VALUES (1)")
3228 .execute(conn)
3229 .is_err()
3230 );
3231 crate::sql_query("DETACH DATABASE aux_write")
3232 .execute(conn)
3233 .unwrap();
3234
3235 conn.set_attach_write_enabled(true).unwrap();
3237 crate::sql_query(&attach).execute(conn).unwrap();
3238 crate::sql_query("INSERT INTO aux_write.t (id) VALUES (1)")
3239 .execute(conn)
3240 .unwrap();
3241 crate::sql_query("DETACH DATABASE aux_write")
3242 .execute(conn)
3243 .unwrap();
3244
3245 let _ = std::fs::remove_file(&path);
3246 }
3247
3248 #[declare_sql_function]
3251 extern "SQL" {
3252 fn directonly_fn() -> Integer;
3253 fn innocuous_fn() -> Integer;
3254 }
3255
3256 #[diesel_test_helper::test]
3257 fn directonly_function_blocked_from_view() {
3258 let conn = &mut connection();
3259
3260 directonly_fn_utils::register_impl_with_behavior(
3262 conn,
3263 SqliteFunctionBehavior::DIRECTONLY,
3264 || 42,
3265 )
3266 .unwrap();
3267
3268 let result = crate::select(directonly_fn()).get_result::<i32>(conn);
3270 assert_eq!(Ok(42), result);
3271
3272 crate::sql_query("CREATE VIEW test_view AS SELECT directonly_fn() AS val")
3274 .execute(conn)
3275 .unwrap();
3276
3277 conn.set_trusted_schema(false).unwrap();
3279
3280 let result = crate::sql_query("SELECT val FROM test_view").execute(conn);
3282 assert!(result.is_err());
3283 }
3284
3285 #[diesel_test_helper::test]
3286 fn innocuous_function_allowed_from_view_with_untrusted_schema() {
3287 let conn = &mut connection();
3288
3289 innocuous_fn_utils::register_impl_with_behavior(
3291 conn,
3292 SqliteFunctionBehavior::DETERMINISTIC | SqliteFunctionBehavior::INNOCUOUS,
3293 || 99,
3294 )
3295 .unwrap();
3296
3297 crate::sql_query("CREATE VIEW innocuous_view AS SELECT innocuous_fn() AS val")
3299 .execute(conn)
3300 .unwrap();
3301
3302 conn.set_trusted_schema(false).unwrap();
3304
3305 let result = crate::sql_query("SELECT val FROM innocuous_view").execute(conn);
3307 assert!(result.is_ok());
3308 }
3309}