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 owned_row;
10mod raw;
11mod row;
12mod serialized_database;
13mod sqlite_value;
14mod statement_iterator;
15mod stmt;
16
17pub(in crate::sqlite) use self::bind_collector::SqliteBindCollector;
18pub use self::bind_collector::SqliteBindValue;
19pub use self::serialized_database::SerializedDatabase;
20pub use self::sqlite_value::SqliteValue;
21
22use self::raw::RawConnection;
23use self::statement_iterator::*;
24use self::stmt::{Statement, StatementUse};
25use super::SqliteAggregateFunction;
26use crate::connection::instrumentation::{DynInstrumentation, StrQueryHelper};
27use crate::connection::statement_cache::StatementCache;
28use crate::connection::*;
29use crate::deserialize::{FromSqlRow, StaticallySizedRow};
30use crate::expression::QueryMetadata;
31use crate::query_builder::*;
32use crate::result::*;
33use crate::serialize::ToSql;
34use crate::sql_types::{HasSqlType, TypeMetadata};
35use crate::sqlite::Sqlite;
36use alloc::string::String;
37use core::ffi as libc;
38use core::num::NonZeroI64;
39
40#[allow(missing_debug_implementations)]
163#[cfg(feature = "__sqlite-shared")]
164pub struct SqliteConnection {
165 statement_cache: StatementCache<Sqlite, Statement>,
169 raw_connection: RawConnection,
170 transaction_state: AnsiTransactionManager,
171 metadata_lookup: (),
174 instrumentation: DynInstrumentation,
175}
176
177#[allow(unsafe_code)]
181unsafe impl Send for SqliteConnection {}
182
183impl SimpleConnection for SqliteConnection {
184 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
185 self.instrumentation
186 .on_connection_event(InstrumentationEvent::StartQuery {
187 query: &StrQueryHelper::new(query),
188 });
189 let resp = self.raw_connection.exec(query);
190 self.instrumentation
191 .on_connection_event(InstrumentationEvent::FinishQuery {
192 query: &StrQueryHelper::new(query),
193 error: resp.as_ref().err(),
194 });
195 resp
196 }
197}
198
199impl ConnectionSealed for SqliteConnection {}
200
201impl Connection for SqliteConnection {
202 type Backend = Sqlite;
203 type TransactionManager = AnsiTransactionManager;
204
205 fn establish(database_url: &str) -> ConnectionResult<Self> {
221 let mut instrumentation = DynInstrumentation::default_instrumentation();
222 instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
223 url: database_url,
224 });
225
226 let establish_result = Self::establish_inner(database_url);
227 instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
228 url: database_url,
229 error: establish_result.as_ref().err(),
230 });
231 let mut conn = establish_result?;
232 conn.instrumentation = instrumentation;
233 Ok(conn)
234 }
235
236 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
237 where
238 T: QueryFragment<Self::Backend> + QueryId,
239 {
240 let statement_use = self.prepared_query(source)?;
241 statement_use.run().and_then(|_| {
242 self.raw_connection
243 .rows_affected_by_last_query()
244 .map_err(Error::DeserializationError)
245 })
246 }
247
248 fn transaction_state(&mut self) -> &mut AnsiTransactionManager
249 where
250 Self: Sized,
251 {
252 &mut self.transaction_state
253 }
254
255 fn instrumentation(&mut self) -> &mut dyn Instrumentation {
256 &mut *self.instrumentation
257 }
258
259 fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
260 self.instrumentation = instrumentation.into();
261 }
262
263 fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
264 self.statement_cache.set_cache_size(size);
265 }
266}
267
268impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
269 type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>;
270 type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>;
271
272 fn load<'conn, 'query, T>(
273 &'conn mut self,
274 source: T,
275 ) -> QueryResult<Self::Cursor<'conn, 'query>>
276 where
277 T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
278 Self::Backend: QueryMetadata<T::SqlType>,
279 {
280 let statement = self.prepared_query(source)?;
281
282 Ok(StatementIterator::new(statement))
283 }
284}
285
286impl WithMetadataLookup for SqliteConnection {
287 fn metadata_lookup(&mut self) -> &mut <Sqlite as TypeMetadata>::MetadataLookup {
288 &mut self.metadata_lookup
289 }
290}
291
292#[cfg(feature = "r2d2")]
293impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
294 fn ping(&mut self) -> QueryResult<()> {
295 use crate::RunQueryDsl;
296
297 crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
298 }
299
300 fn is_broken(&mut self) -> bool {
301 AnsiTransactionManager::is_broken_transaction_manager(self)
302 }
303}
304
305impl MultiConnectionHelper for SqliteConnection {
306 fn to_any<'a>(
307 lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
308 ) -> &mut (dyn core::any::Any + 'a) {
309 lookup
310 }
311
312 fn from_any(
313 lookup: &mut dyn core::any::Any,
314 ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
315 lookup.downcast_mut()
316 }
317}
318
319impl SqliteConnection {
320 pub fn immediate_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
342 where
343 F: FnOnce(&mut Self) -> Result<T, E>,
344 E: From<Error>,
345 {
346 self.transaction_sql(f, "BEGIN IMMEDIATE")
347 }
348
349 pub fn exclusive_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
371 where
372 F: FnOnce(&mut Self) -> Result<T, E>,
373 E: From<Error>,
374 {
375 self.transaction_sql(f, "BEGIN EXCLUSIVE")
376 }
377
378 pub fn last_insert_rowid(&self) -> Option<NonZeroI64> {
414 NonZeroI64::new(self.raw_connection.last_insert_rowid())
415 }
416
417 fn transaction_sql<T, E, F>(&mut self, f: F, sql: &str) -> Result<T, E>
418 where
419 F: FnOnce(&mut Self) -> Result<T, E>,
420 E: From<Error>,
421 {
422 AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?;
423 match f(&mut *self) {
424 Ok(value) => {
425 AnsiTransactionManager::commit_transaction(&mut *self)?;
426 Ok(value)
427 }
428 Err(e) => {
429 AnsiTransactionManager::rollback_transaction(&mut *self)?;
430 Err(e)
431 }
432 }
433 }
434
435 fn prepared_query<'conn, 'query, T>(
436 &'conn mut self,
437 source: T,
438 ) -> QueryResult<StatementUse<'conn, 'query>>
439 where
440 T: QueryFragment<Sqlite> + QueryId + 'query,
441 {
442 self.instrumentation
443 .on_connection_event(InstrumentationEvent::StartQuery {
444 query: &crate::debug_query(&source),
445 });
446 let raw_connection = &self.raw_connection;
447 let cache = &mut self.statement_cache;
448 let statement = match cache.cached_statement(
449 &source,
450 &Sqlite,
451 &[],
452 raw_connection,
453 Statement::prepare,
454 &mut *self.instrumentation,
455 ) {
456 Ok(statement) => statement,
457 Err(e) => {
458 self.instrumentation
459 .on_connection_event(InstrumentationEvent::FinishQuery {
460 query: &crate::debug_query(&source),
461 error: Some(&e),
462 });
463
464 return Err(e);
465 }
466 };
467
468 StatementUse::bind(statement, source, &mut *self.instrumentation)
469 }
470
471 #[doc(hidden)]
472 pub fn register_sql_function<ArgsSqlType, RetSqlType, Args, Ret, F>(
473 &mut self,
474 fn_name: &str,
475 deterministic: bool,
476 mut f: F,
477 ) -> QueryResult<()>
478 where
479 F: FnMut(Args) -> Ret + core::panic::UnwindSafe + Send + 'static,
480 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
481 Ret: ToSql<RetSqlType, Sqlite>,
482 Sqlite: HasSqlType<RetSqlType>,
483 {
484 functions::register(
485 &self.raw_connection,
486 fn_name,
487 deterministic,
488 move |_, args| f(args),
489 )
490 }
491
492 #[doc(hidden)]
493 pub fn register_noarg_sql_function<RetSqlType, Ret, F>(
494 &self,
495 fn_name: &str,
496 deterministic: bool,
497 f: F,
498 ) -> QueryResult<()>
499 where
500 F: FnMut() -> Ret + core::panic::UnwindSafe + Send + 'static,
501 Ret: ToSql<RetSqlType, Sqlite>,
502 Sqlite: HasSqlType<RetSqlType>,
503 {
504 functions::register_noargs(&self.raw_connection, fn_name, deterministic, f)
505 }
506
507 #[doc(hidden)]
508 pub fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
509 &mut self,
510 fn_name: &str,
511 ) -> QueryResult<()>
512 where
513 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
514 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
515 Ret: ToSql<RetSqlType, Sqlite>,
516 Sqlite: HasSqlType<RetSqlType>,
517 {
518 functions::register_aggregate::<_, _, _, _, A>(&self.raw_connection, fn_name)
519 }
520
521 pub fn register_collation<F>(&mut self, collation_name: &str, collation: F) -> QueryResult<()>
557 where
558 F: Fn(&str, &str) -> core::cmp::Ordering + Send + 'static + core::panic::UnwindSafe,
559 {
560 self.raw_connection
561 .register_collation_function(collation_name, collation)
562 }
563
564 pub fn serialize_database_to_buffer(&mut self) -> SerializedDatabase {
573 self.raw_connection.serialize()
574 }
575
576 pub fn deserialize_readonly_database_from_buffer(&mut self, data: &[u8]) -> QueryResult<()> {
613 self.raw_connection.deserialize(data)
614 }
615
616 #[allow(unsafe_code)]
703 pub unsafe fn with_raw_connection<R, F>(&mut self, f: F) -> R
704 where
705 F: FnOnce(*mut ffi::sqlite3) -> R,
706 {
707 f(self.raw_connection.internal_connection.as_ptr())
708 }
709
710 fn register_diesel_sql_functions(&self) -> QueryResult<()> {
711 use crate::sql_types::{Integer, Text};
712
713 functions::register::<Text, Integer, _, _, _>(
714 &self.raw_connection,
715 "diesel_manage_updated_at",
716 false,
717 |conn, table_name: String| {
718 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!(
719 include_str!("diesel_manage_updated_at.sql"),
720 table_name = table_name
721 ))
722 .expect("Failed to create trigger");
723 0 },
725 )
726 }
727
728 fn establish_inner(database_url: &str) -> Result<SqliteConnection, ConnectionError> {
729 use crate::result::ConnectionError::CouldntSetupConfiguration;
730 let raw_connection = RawConnection::establish(database_url)?;
731 let conn = Self {
732 statement_cache: StatementCache::new(),
733 raw_connection,
734 transaction_state: AnsiTransactionManager::default(),
735 metadata_lookup: (),
736 instrumentation: DynInstrumentation::none(),
737 };
738 conn.register_diesel_sql_functions()
739 .map_err(CouldntSetupConfiguration)?;
740 Ok(conn)
741 }
742}
743
744fn error_message(err_code: libc::c_int) -> &'static str {
745 ffi::code_to_str(err_code)
746}
747
748#[cfg(test)]
749mod tests {
750 use super::*;
751 use crate::dsl::sql;
752 use crate::prelude::*;
753 use crate::sql_types::{Integer, Text};
754
755 fn connection() -> SqliteConnection {
756 SqliteConnection::establish(":memory:").unwrap()
757 }
758
759 #[diesel_test_helper::test]
760 #[allow(unsafe_code)]
761 fn with_raw_connection_can_return_values() {
762 let connection = &mut connection();
763
764 let autocommit_status = unsafe {
766 connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
767 };
768
769 assert_ne!(autocommit_status, 0, "Expected autocommit to be enabled");
771 }
772
773 #[diesel_test_helper::test]
774 #[allow(unsafe_code)]
775 fn with_raw_connection_works_after_diesel_operations() {
776 let connection = &mut connection();
777
778 crate::sql_query("CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT)")
780 .execute(connection)
781 .unwrap();
782 crate::sql_query("INSERT INTO test_table (value) VALUES ('hello')")
783 .execute(connection)
784 .unwrap();
785
786 let last_rowid = unsafe {
788 connection.with_raw_connection(|raw_conn| ffi::sqlite3_last_insert_rowid(raw_conn))
789 };
790
791 assert_eq!(last_rowid, 1, "Last insert rowid should be 1");
792
793 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM test_table")
795 .get_result(connection)
796 .unwrap();
797 assert_eq!(count, 1);
798 }
799
800 #[diesel_test_helper::test]
801 #[allow(unsafe_code)]
802 fn with_raw_connection_can_execute_raw_sql() {
803 let connection = &mut connection();
804
805 crate::sql_query("CREATE TABLE raw_test (id INTEGER PRIMARY KEY, name TEXT)")
807 .execute(connection)
808 .unwrap();
809
810 let result = unsafe {
813 connection.with_raw_connection(|raw_conn| {
814 let sql = c"INSERT INTO raw_test (name) VALUES ('from_raw')";
815 let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
816 let rc = ffi::sqlite3_exec(
817 raw_conn,
818 sql.as_ptr(),
819 None,
820 core::ptr::null_mut(),
821 &mut err_msg,
822 );
823 if rc != ffi::SQLITE_OK && !err_msg.is_null() {
824 ffi::sqlite3_free(err_msg as *mut libc::c_void);
825 }
826 rc
827 })
828 };
829
830 assert_eq!(result, ffi::SQLITE_OK, "Raw SQL execution should succeed");
831
832 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM raw_test")
834 .get_result(connection)
835 .unwrap();
836 assert_eq!(count, 1);
837
838 let name: String = sql::<Text>("SELECT name FROM raw_test WHERE id = 1")
839 .get_result(connection)
840 .unwrap();
841 assert_eq!(name, "from_raw");
842 }
843
844 #[diesel_test_helper::test]
845 #[allow(unsafe_code)]
846 fn with_raw_connection_works_within_transaction() {
847 let connection = &mut connection();
848
849 crate::sql_query("CREATE TABLE txn_test (id INTEGER PRIMARY KEY, value INTEGER)")
850 .execute(connection)
851 .unwrap();
852
853 connection
854 .transaction::<_, crate::result::Error, _>(|conn| {
855 crate::sql_query("INSERT INTO txn_test (value) VALUES (42)")
856 .execute(conn)
857 .unwrap();
858
859 let autocommit = unsafe {
861 conn.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
862 };
863
864 assert_eq!(
866 autocommit, 0,
867 "Autocommit should be disabled inside transaction"
868 );
869
870 Ok(())
871 })
872 .unwrap();
873
874 let autocommit = unsafe {
876 connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
877 };
878 assert_ne!(
879 autocommit, 0,
880 "Autocommit should be enabled after transaction"
881 );
882 }
883
884 #[diesel_test_helper::test]
885 #[allow(unsafe_code)]
886 fn with_raw_connection_can_read_database_filename() {
887 let connection = &mut connection();
888
889 let filename = unsafe {
891 connection.with_raw_connection(|raw_conn| {
892 let db_name = c"main";
893 let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
894 if filename_ptr.is_null() {
895 None
896 } else {
897 let cstr = core::ffi::CStr::from_ptr(filename_ptr);
899 Some(cstr.to_string_lossy().into_owned())
900 }
901 })
902 };
903
904 assert_eq!(
907 filename,
908 Some(String::new()),
909 "In-memory database filename should be an empty string"
910 );
911 }
912
913 #[diesel_test_helper::test]
914 #[allow(unsafe_code)]
915 fn with_raw_connection_changes_count() {
916 let connection = &mut connection();
917
918 crate::sql_query("CREATE TABLE changes_test (id INTEGER PRIMARY KEY, value INTEGER)")
919 .execute(connection)
920 .unwrap();
921
922 crate::sql_query("INSERT INTO changes_test (value) VALUES (1), (2), (3)")
923 .execute(connection)
924 .unwrap();
925
926 let changes = unsafe {
928 connection.with_raw_connection(|raw_conn| {
929 let sql = c"UPDATE changes_test SET value = value + 10";
930 let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
931 let rc = ffi::sqlite3_exec(
932 raw_conn,
933 sql.as_ptr(),
934 None,
935 core::ptr::null_mut(),
936 &mut err_msg,
937 );
938 if rc != ffi::SQLITE_OK && !err_msg.is_null() {
939 ffi::sqlite3_free(err_msg as *mut libc::c_void);
940 return -1;
941 }
942 ffi::sqlite3_changes(raw_conn)
943 })
944 };
945
946 assert_eq!(changes, 3, "Should have updated 3 rows");
947
948 let values: Vec<i32> = sql::<Integer>("SELECT value FROM changes_test ORDER BY id")
950 .load(connection)
951 .unwrap();
952 assert_eq!(values, vec![11, 12, 13]);
953 }
954
955 #[diesel_test_helper::test]
957 #[allow(unsafe_code)]
958 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
959 fn with_raw_connection_recovers_after_panic() {
960 let connection = &mut connection();
961
962 crate::sql_query("CREATE TABLE panic_test (id INTEGER PRIMARY KEY, value TEXT)")
963 .execute(connection)
964 .unwrap();
965
966 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
968 connection.with_raw_connection(|_raw_conn| {
969 panic!("intentional panic inside with_raw_connection");
970 })
971 }));
972 assert!(result.is_err(), "Should have caught the panic");
973
974 crate::sql_query("INSERT INTO panic_test (value) VALUES ('after_panic')")
976 .execute(connection)
977 .unwrap();
978
979 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM panic_test")
980 .get_result(connection)
981 .unwrap();
982 assert_eq!(count, 1, "Connection should work after panic in callback");
983 }
984
985 #[diesel_test_helper::test]
987 #[allow(unsafe_code)]
988 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
989 fn with_raw_connection_can_read_file_database_filename() {
990 let dir = std::env::temp_dir().join("diesel_test_filename.db");
991 let db_path = dir.to_str().unwrap();
992
993 let _ = std::fs::remove_file(db_path);
995
996 let connection = &mut SqliteConnection::establish(db_path).unwrap();
997
998 let filename = unsafe {
1000 connection.with_raw_connection(|raw_conn| {
1001 let db_name = c"main";
1002 let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1003 if filename_ptr.is_null() {
1004 None
1005 } else {
1006 let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1007 Some(cstr.to_string_lossy().into_owned())
1008 }
1009 })
1010 };
1011
1012 let filename = filename.expect("File-based database should have a filename");
1013 assert!(
1014 filename.contains("diesel_test_filename.db"),
1015 "Filename should contain the database name, got: {filename}"
1016 );
1017
1018 let _ = std::fs::remove_file(db_path);
1020 }
1021
1022 #[declare_sql_function]
1023 extern "SQL" {
1024 fn fun_case(x: Text) -> Text;
1025 fn my_add(x: Integer, y: Integer) -> Integer;
1026 fn answer() -> Integer;
1027 fn add_counter(x: Integer) -> Integer;
1028
1029 #[aggregate]
1030 fn my_sum(expr: Integer) -> Integer;
1031 #[aggregate]
1032 fn range_max(expr1: Integer, expr2: Integer, expr3: Integer) -> Nullable<Integer>;
1033 }
1034
1035 #[diesel_test_helper::test]
1036 fn database_serializes_and_deserializes_successfully() {
1037 let expected_users = vec![
1038 (
1039 1,
1040 "John Doe".to_string(),
1041 "john.doe@example.com".to_string(),
1042 ),
1043 (
1044 2,
1045 "Jane Doe".to_string(),
1046 "jane.doe@example.com".to_string(),
1047 ),
1048 ];
1049
1050 let conn1 = &mut connection();
1051 let _ =
1052 crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1053 .execute(conn1);
1054 let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1055 .execute(conn1);
1056
1057 let serialized_database = conn1.serialize_database_to_buffer();
1058
1059 let conn2 = &mut connection();
1060 conn2
1061 .deserialize_readonly_database_from_buffer(serialized_database.as_slice())
1062 .unwrap();
1063
1064 let query = sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1065 let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1066
1067 assert_eq!(expected_users, actual_users);
1068 }
1069
1070 #[diesel_test_helper::test]
1071 fn register_custom_function() {
1072 let connection = &mut connection();
1073 fun_case_utils::register_impl(connection, |x: String| {
1074 x.chars()
1075 .enumerate()
1076 .map(|(i, c)| {
1077 if i % 2 == 0 {
1078 c.to_lowercase().to_string()
1079 } else {
1080 c.to_uppercase().to_string()
1081 }
1082 })
1083 .collect::<String>()
1084 })
1085 .unwrap();
1086
1087 let mapped_string = crate::select(fun_case("foobar"))
1088 .get_result::<String>(connection)
1089 .unwrap();
1090 assert_eq!("fOoBaR", mapped_string);
1091 }
1092
1093 #[diesel_test_helper::test]
1094 fn register_multiarg_function() {
1095 let connection = &mut connection();
1096 my_add_utils::register_impl(connection, |x: i32, y: i32| x + y).unwrap();
1097
1098 let added = crate::select(my_add(1, 2)).get_result::<i32>(connection);
1099 assert_eq!(Ok(3), added);
1100 }
1101
1102 #[diesel_test_helper::test]
1103 fn register_noarg_function() {
1104 let connection = &mut connection();
1105 answer_utils::register_impl(connection, || 42).unwrap();
1106
1107 let answer = crate::select(answer()).get_result::<i32>(connection);
1108 assert_eq!(Ok(42), answer);
1109 }
1110
1111 #[diesel_test_helper::test]
1112 fn register_nondeterministic_noarg_function() {
1113 let connection = &mut connection();
1114 answer_utils::register_nondeterministic_impl(connection, || 42).unwrap();
1115
1116 let answer = crate::select(answer()).get_result::<i32>(connection);
1117 assert_eq!(Ok(42), answer);
1118 }
1119
1120 #[diesel_test_helper::test]
1121 fn register_nondeterministic_function() {
1122 let connection = &mut connection();
1123 let mut y = 0;
1124 add_counter_utils::register_nondeterministic_impl(connection, move |x: i32| {
1125 y += 1;
1126 x + y
1127 })
1128 .unwrap();
1129
1130 let added = crate::select((add_counter(1), add_counter(1), add_counter(1)))
1131 .get_result::<(i32, i32, i32)>(connection);
1132 assert_eq!(Ok((2, 3, 4)), added);
1133 }
1134
1135 #[derive(Default)]
1136 struct MySum {
1137 sum: i32,
1138 }
1139
1140 impl SqliteAggregateFunction<i32> for MySum {
1141 type Output = i32;
1142
1143 fn step(&mut self, expr: i32) {
1144 self.sum += expr;
1145 }
1146
1147 fn finalize(aggregator: Option<Self>) -> Self::Output {
1148 aggregator.map(|a| a.sum).unwrap_or_default()
1149 }
1150 }
1151
1152 table! {
1153 my_sum_example {
1154 id -> Integer,
1155 value -> Integer,
1156 }
1157 }
1158
1159 #[diesel_test_helper::test]
1160 fn register_aggregate_function() {
1161 use self::my_sum_example::dsl::*;
1162
1163 let connection = &mut connection();
1164 crate::sql_query(
1165 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1166 )
1167 .execute(connection)
1168 .unwrap();
1169 crate::sql_query("INSERT INTO my_sum_example (value) VALUES (1), (2), (3)")
1170 .execute(connection)
1171 .unwrap();
1172
1173 my_sum_utils::register_impl::<MySum, _>(connection).unwrap();
1174
1175 let result = my_sum_example
1176 .select(my_sum(value))
1177 .get_result::<i32>(connection);
1178 assert_eq!(Ok(6), result);
1179 }
1180
1181 #[diesel_test_helper::test]
1182 fn register_aggregate_function_returns_finalize_default_on_empty_set() {
1183 use self::my_sum_example::dsl::*;
1184
1185 let connection = &mut connection();
1186 crate::sql_query(
1187 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1188 )
1189 .execute(connection)
1190 .unwrap();
1191
1192 my_sum_utils::register_impl::<MySum, _>(connection).unwrap();
1193
1194 let result = my_sum_example
1195 .select(my_sum(value))
1196 .get_result::<i32>(connection);
1197 assert_eq!(Ok(0), result);
1198 }
1199
1200 #[derive(Default)]
1201 struct RangeMax<T> {
1202 max_value: Option<T>,
1203 }
1204
1205 impl<T: Default + Ord + Copy + Clone> SqliteAggregateFunction<(T, T, T)> for RangeMax<T> {
1206 type Output = Option<T>;
1207
1208 fn step(&mut self, (x0, x1, x2): (T, T, T)) {
1209 let max = if x0 >= x1 && x0 >= x2 {
1210 x0
1211 } else if x1 >= x0 && x1 >= x2 {
1212 x1
1213 } else {
1214 x2
1215 };
1216
1217 self.max_value = match self.max_value {
1218 Some(current_max_value) if max > current_max_value => Some(max),
1219 None => Some(max),
1220 _ => self.max_value,
1221 };
1222 }
1223
1224 fn finalize(aggregator: Option<Self>) -> Self::Output {
1225 aggregator?.max_value
1226 }
1227 }
1228
1229 table! {
1230 range_max_example {
1231 id -> Integer,
1232 value1 -> Integer,
1233 value2 -> Integer,
1234 value3 -> Integer,
1235 }
1236 }
1237
1238 #[diesel_test_helper::test]
1239 fn register_aggregate_multiarg_function() {
1240 use self::range_max_example::dsl::*;
1241
1242 let connection = &mut connection();
1243 crate::sql_query(
1244 r#"CREATE TABLE range_max_example (
1245 id integer primary key autoincrement,
1246 value1 integer,
1247 value2 integer,
1248 value3 integer
1249 )"#,
1250 )
1251 .execute(connection)
1252 .unwrap();
1253 crate::sql_query(
1254 "INSERT INTO range_max_example (value1, value2, value3) VALUES (3, 2, 1), (2, 2, 2)",
1255 )
1256 .execute(connection)
1257 .unwrap();
1258
1259 range_max_utils::register_impl::<RangeMax<i32>, _, _, _>(connection).unwrap();
1260 let result = range_max_example
1261 .select(range_max(value1, value2, value3))
1262 .get_result::<Option<i32>>(connection)
1263 .unwrap();
1264 assert_eq!(Some(3), result);
1265 }
1266
1267 table! {
1268 my_collation_example {
1269 id -> Integer,
1270 value -> Text,
1271 }
1272 }
1273
1274 #[diesel_test_helper::test]
1275 fn register_collation_function() {
1276 use self::my_collation_example::dsl::*;
1277
1278 let connection = &mut connection();
1279
1280 connection
1281 .register_collation("RUSTNOCASE", |rhs, lhs| {
1282 rhs.to_lowercase().cmp(&lhs.to_lowercase())
1283 })
1284 .unwrap();
1285
1286 crate::sql_query(
1287 "CREATE TABLE my_collation_example (id integer primary key autoincrement, value text collate RUSTNOCASE)",
1288 ).execute(connection)
1289 .unwrap();
1290 crate::sql_query(
1291 "INSERT INTO my_collation_example (value) VALUES ('foo'), ('FOo'), ('f00')",
1292 )
1293 .execute(connection)
1294 .unwrap();
1295
1296 let result = my_collation_example
1297 .filter(value.eq("foo"))
1298 .select(value)
1299 .load::<String>(connection);
1300 assert_eq!(
1301 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
1302 result.as_ref().map(|vec| vec.as_ref())
1303 );
1304
1305 let result = my_collation_example
1306 .filter(value.eq("FOO"))
1307 .select(value)
1308 .load::<String>(connection);
1309 assert_eq!(
1310 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
1311 result.as_ref().map(|vec| vec.as_ref())
1312 );
1313
1314 let result = my_collation_example
1315 .filter(value.eq("f00"))
1316 .select(value)
1317 .load::<String>(connection);
1318 assert_eq!(
1319 Ok(&["f00".to_owned()][..]),
1320 result.as_ref().map(|vec| vec.as_ref())
1321 );
1322
1323 let result = my_collation_example
1324 .filter(value.eq("F00"))
1325 .select(value)
1326 .load::<String>(connection);
1327 assert_eq!(
1328 Ok(&["f00".to_owned()][..]),
1329 result.as_ref().map(|vec| vec.as_ref())
1330 );
1331
1332 let result = my_collation_example
1333 .filter(value.eq("oof"))
1334 .select(value)
1335 .load::<String>(connection);
1336 assert_eq!(Ok(&[][..]), result.as_ref().map(|vec| vec.as_ref()));
1337 }
1338
1339 #[diesel_test_helper::test]
1341 fn test_correct_serialization_of_owned_strings() {
1342 use crate::prelude::*;
1343
1344 #[derive(Debug, crate::expression::AsExpression)]
1345 #[diesel(sql_type = diesel::sql_types::Text)]
1346 struct CustomWrapper(String);
1347
1348 impl crate::serialize::ToSql<Text, Sqlite> for CustomWrapper {
1349 fn to_sql<'b>(
1350 &'b self,
1351 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
1352 ) -> crate::serialize::Result {
1353 out.set_value(self.0.to_string());
1354 Ok(crate::serialize::IsNull::No)
1355 }
1356 }
1357
1358 let connection = &mut connection();
1359
1360 let res = crate::select(
1361 CustomWrapper("".into())
1362 .into_sql::<crate::sql_types::Text>()
1363 .nullable(),
1364 )
1365 .get_result::<Option<String>>(connection)
1366 .unwrap();
1367 assert_eq!(res, Some(String::new()));
1368 }
1369
1370 #[diesel_test_helper::test]
1371 fn test_correct_serialization_of_owned_bytes() {
1372 use crate::prelude::*;
1373
1374 #[derive(Debug, crate::expression::AsExpression)]
1375 #[diesel(sql_type = diesel::sql_types::Binary)]
1376 struct CustomWrapper(Vec<u8>);
1377
1378 impl crate::serialize::ToSql<crate::sql_types::Binary, Sqlite> for CustomWrapper {
1379 fn to_sql<'b>(
1380 &'b self,
1381 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
1382 ) -> crate::serialize::Result {
1383 out.set_value(self.0.clone());
1384 Ok(crate::serialize::IsNull::No)
1385 }
1386 }
1387
1388 let connection = &mut connection();
1389
1390 let res = crate::select(
1391 CustomWrapper(Vec::new())
1392 .into_sql::<crate::sql_types::Binary>()
1393 .nullable(),
1394 )
1395 .get_result::<Option<Vec<u8>>>(connection)
1396 .unwrap();
1397 assert_eq!(res, Some(Vec::new()));
1398 }
1399
1400 #[diesel_test_helper::test]
1401 fn correctly_handle_empty_query() {
1402 let check_empty_query_error = |r: crate::QueryResult<usize>| {
1403 assert!(r.is_err());
1404 let err = r.unwrap_err();
1405 assert!(
1406 matches!(err, crate::result::Error::QueryBuilderError(ref b) if b.is::<crate::result::EmptyQuery>()),
1407 "Expected a query builder error, but got {err}"
1408 );
1409 };
1410 let connection = &mut SqliteConnection::establish(":memory:").unwrap();
1411 check_empty_query_error(crate::sql_query("").execute(connection));
1412 check_empty_query_error(crate::sql_query(" ").execute(connection));
1413 check_empty_query_error(crate::sql_query("\n\t").execute(connection));
1414 check_empty_query_error(crate::sql_query("-- SELECT 1;").execute(connection));
1415 }
1416
1417 #[diesel_test_helper::test]
1418 fn last_insert_rowid_returns_none_on_fresh_connection() {
1419 let conn = &mut connection();
1420 assert_eq!(conn.last_insert_rowid(), None);
1421 }
1422
1423 #[diesel_test_helper::test]
1424 fn last_insert_rowid_returns_rowid_after_insert() {
1425 let conn = &mut connection();
1426 crate::sql_query("CREATE TABLE li_test (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1427 .execute(conn)
1428 .unwrap();
1429
1430 crate::sql_query("INSERT INTO li_test (val) VALUES ('a')")
1431 .execute(conn)
1432 .unwrap();
1433 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1434
1435 crate::sql_query("INSERT INTO li_test (val) VALUES ('b')")
1436 .execute(conn)
1437 .unwrap();
1438 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(2));
1439 }
1440
1441 #[diesel_test_helper::test]
1442 fn last_insert_rowid_unchanged_after_failed_insert() {
1443 let conn = &mut connection();
1444 crate::sql_query(
1445 "CREATE TABLE li_test2 (id INTEGER PRIMARY KEY, val TEXT NOT NULL UNIQUE)",
1446 )
1447 .execute(conn)
1448 .unwrap();
1449
1450 crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')")
1451 .execute(conn)
1452 .unwrap();
1453 let rowid = conn.last_insert_rowid();
1454 assert_eq!(rowid, NonZeroI64::new(1));
1455
1456 let result = crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')").execute(conn);
1458 assert!(result.is_err());
1459
1460 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1462 }
1463
1464 #[diesel_test_helper::test]
1465 fn last_insert_rowid_with_explicit_rowid() {
1466 let conn = &mut connection();
1467 crate::sql_query("CREATE TABLE li_test3 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1468 .execute(conn)
1469 .unwrap();
1470
1471 crate::sql_query("INSERT INTO li_test3 (id, val) VALUES (42, 'a')")
1472 .execute(conn)
1473 .unwrap();
1474 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(42));
1475 }
1476
1477 #[diesel_test_helper::test]
1478 fn last_insert_rowid_unchanged_after_delete_and_update() {
1479 let conn = &mut connection();
1480 crate::sql_query("CREATE TABLE li_test4 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1481 .execute(conn)
1482 .unwrap();
1483
1484 crate::sql_query("INSERT INTO li_test4 (val) VALUES ('a')")
1485 .execute(conn)
1486 .unwrap();
1487 let rowid = conn.last_insert_rowid();
1488 assert_eq!(rowid, NonZeroI64::new(1));
1489
1490 crate::sql_query("UPDATE li_test4 SET val = 'b' WHERE id = 1")
1491 .execute(conn)
1492 .unwrap();
1493 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1494
1495 crate::sql_query("DELETE FROM li_test4 WHERE id = 1")
1496 .execute(conn)
1497 .unwrap();
1498 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1499 }
1500}