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;
13pub(in crate::sqlite) mod sqlite_blob;
14mod sqlite_value;
15mod statement_iterator;
16mod stmt;
17
18pub(in crate::sqlite) use self::bind_collector::SqliteBindCollector;
19pub use self::bind_collector::SqliteBindValue;
20pub use self::serialized_database::SerializedDatabase;
21pub use self::sqlite_value::SqliteValue;
22
23use self::raw::RawConnection;
24use self::statement_iterator::*;
25use self::stmt::{Statement, StatementUse};
26use super::SqliteAggregateFunction;
27use crate::connection::instrumentation::{DynInstrumentation, StrQueryHelper};
28use crate::connection::statement_cache::StatementCache;
29use crate::connection::*;
30use crate::deserialize::{FromSqlRow, StaticallySizedRow};
31use crate::expression::QueryMetadata;
32use crate::query_builder::*;
33use crate::result::*;
34use crate::serialize::ToSql;
35use crate::sql_types::{HasSqlType, TypeMetadata};
36use crate::sqlite::Sqlite;
37use alloc::string::String;
38use alloc::vec::Vec;
39use core::ffi as libc;
40use core::num::NonZeroI64;
41
42#[allow(missing_debug_implementations)]
165#[cfg(feature = "__sqlite-shared")]
166pub struct SqliteConnection {
167 statement_cache: StatementCache<Sqlite, Statement>,
171 raw_connection: RawConnection,
172 transaction_state: AnsiTransactionManager,
173 metadata_lookup: (),
176 instrumentation: DynInstrumentation,
177 serialized_data: Vec<u8>,
186}
187
188#[allow(unsafe_code)]
192unsafe impl Send for SqliteConnection {}
193
194impl SimpleConnection for SqliteConnection {
195 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
196 self.instrumentation
197 .on_connection_event(InstrumentationEvent::StartQuery {
198 query: &StrQueryHelper::new(query),
199 });
200 let resp = self.raw_connection.exec(query);
201 self.instrumentation
202 .on_connection_event(InstrumentationEvent::FinishQuery {
203 query: &StrQueryHelper::new(query),
204 error: resp.as_ref().err(),
205 });
206 resp
207 }
208}
209
210impl ConnectionSealed for SqliteConnection {}
211
212impl Connection for SqliteConnection {
213 type Backend = Sqlite;
214 type TransactionManager = AnsiTransactionManager;
215
216 fn establish(database_url: &str) -> ConnectionResult<Self> {
232 let mut instrumentation = DynInstrumentation::default_instrumentation();
233 instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
234 url: database_url,
235 });
236
237 let establish_result = Self::establish_inner(database_url);
238 instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
239 url: database_url,
240 error: establish_result.as_ref().err(),
241 });
242 let mut conn = establish_result?;
243 conn.instrumentation = instrumentation;
244 Ok(conn)
245 }
246
247 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
248 where
249 T: QueryFragment<Self::Backend> + QueryId,
250 {
251 let statement_use = self.prepared_query(source)?;
252 statement_use.run().and_then(|_| {
253 self.raw_connection
254 .rows_affected_by_last_query()
255 .map_err(Error::DeserializationError)
256 })
257 }
258
259 fn transaction_state(&mut self) -> &mut AnsiTransactionManager
260 where
261 Self: Sized,
262 {
263 &mut self.transaction_state
264 }
265
266 fn instrumentation(&mut self) -> &mut dyn Instrumentation {
267 &mut *self.instrumentation
268 }
269
270 fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
271 self.instrumentation = instrumentation.into();
272 }
273
274 fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
275 self.statement_cache.set_cache_size(size);
276 }
277}
278
279impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
280 type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>;
281 type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>;
282
283 fn load<'conn, 'query, T>(
284 &'conn mut self,
285 source: T,
286 ) -> QueryResult<Self::Cursor<'conn, 'query>>
287 where
288 T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
289 Self::Backend: QueryMetadata<T::SqlType>,
290 {
291 let statement = self.prepared_query(source)?;
292
293 Ok(StatementIterator::new(statement))
294 }
295}
296
297impl WithMetadataLookup for SqliteConnection {
298 fn metadata_lookup(&mut self) -> &mut <Sqlite as TypeMetadata>::MetadataLookup {
299 &mut self.metadata_lookup
300 }
301}
302
303#[cfg(feature = "r2d2")]
304impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
305 fn ping(&mut self) -> QueryResult<()> {
306 use crate::RunQueryDsl;
307
308 crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
309 }
310
311 fn is_broken(&mut self) -> bool {
312 AnsiTransactionManager::is_broken_transaction_manager(self)
313 }
314}
315
316impl MultiConnectionHelper for SqliteConnection {
317 fn to_any<'a>(
318 lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
319 ) -> &mut (dyn core::any::Any + 'a) {
320 lookup
321 }
322
323 fn from_any(
324 lookup: &mut dyn core::any::Any,
325 ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
326 lookup.downcast_mut()
327 }
328}
329
330impl SqliteConnection {
331 pub fn immediate_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
353 where
354 F: FnOnce(&mut Self) -> Result<T, E>,
355 E: From<Error>,
356 {
357 self.transaction_sql(f, "BEGIN IMMEDIATE")
358 }
359
360 pub fn exclusive_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
382 where
383 F: FnOnce(&mut Self) -> Result<T, E>,
384 E: From<Error>,
385 {
386 self.transaction_sql(f, "BEGIN EXCLUSIVE")
387 }
388
389 pub fn last_insert_rowid(&self) -> Option<NonZeroI64> {
425 NonZeroI64::new(self.raw_connection.last_insert_rowid())
426 }
427
428 pub fn get_read_only_blob<'conn, 'query, U>(
457 &'conn self,
458 blob_column: U,
459 row_id: i64,
460 ) -> Result<sqlite_blob::SqliteReadOnlyBlob<'conn>, Error>
461 where
462 'query: 'conn,
463 U: crate::Column,
464 U::Table: nodes::StaticQueryFragment,
465 <U::Table as nodes::StaticQueryFragment>::Component: HasDatabaseAndTableName,
466 {
467 use crate::query_builder::nodes::StaticQueryFragment;
468 let _ = blob_column;
470
471 let database_name = U::Table::STATIC_COMPONENT.database_name().unwrap_or("main");
472 let column_name = U::NAME;
473 let table_name = U::Table::STATIC_COMPONENT.table_name();
474
475 self.raw_connection
476 .blob_open(database_name, table_name, column_name, row_id)
477 }
478
479 fn transaction_sql<T, E, F>(&mut self, f: F, sql: &str) -> Result<T, E>
480 where
481 F: FnOnce(&mut Self) -> Result<T, E>,
482 E: From<Error>,
483 {
484 AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?;
485 match f(&mut *self) {
486 Ok(value) => {
487 AnsiTransactionManager::commit_transaction(&mut *self)?;
488 Ok(value)
489 }
490 Err(e) => {
491 AnsiTransactionManager::rollback_transaction(&mut *self)?;
492 Err(e)
493 }
494 }
495 }
496
497 fn prepared_query<'conn, 'query, T>(
498 &'conn mut self,
499 source: T,
500 ) -> QueryResult<StatementUse<'conn, 'query>>
501 where
502 T: QueryFragment<Sqlite> + QueryId + 'query,
503 {
504 self.instrumentation
505 .on_connection_event(InstrumentationEvent::StartQuery {
506 query: &crate::debug_query(&source),
507 });
508 let raw_connection = &self.raw_connection;
509 let cache = &mut self.statement_cache;
510 let statement = match cache.cached_statement(
511 &source,
512 &Sqlite,
513 &[],
514 raw_connection,
515 Statement::prepare,
516 &mut *self.instrumentation,
517 ) {
518 Ok(statement) => statement,
519 Err(e) => {
520 self.instrumentation
521 .on_connection_event(InstrumentationEvent::FinishQuery {
522 query: &crate::debug_query(&source),
523 error: Some(&e),
524 });
525
526 return Err(e);
527 }
528 };
529
530 StatementUse::bind(statement, source, &mut *self.instrumentation)
531 }
532
533 #[doc(hidden)]
534 pub fn register_sql_function<ArgsSqlType, RetSqlType, Args, Ret, F>(
535 &mut self,
536 fn_name: &str,
537 deterministic: bool,
538 mut f: F,
539 ) -> QueryResult<()>
540 where
541 F: FnMut(Args) -> Ret + core::panic::UnwindSafe + Send + 'static,
542 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
543 Ret: ToSql<RetSqlType, Sqlite>,
544 Sqlite: HasSqlType<RetSqlType>,
545 {
546 functions::register(
547 &self.raw_connection,
548 fn_name,
549 deterministic,
550 move |_, args| f(args),
551 )
552 }
553
554 #[doc(hidden)]
555 pub fn register_noarg_sql_function<RetSqlType, Ret, F>(
556 &self,
557 fn_name: &str,
558 deterministic: bool,
559 f: F,
560 ) -> QueryResult<()>
561 where
562 F: FnMut() -> Ret + core::panic::UnwindSafe + Send + 'static,
563 Ret: ToSql<RetSqlType, Sqlite>,
564 Sqlite: HasSqlType<RetSqlType>,
565 {
566 functions::register_noargs(&self.raw_connection, fn_name, deterministic, f)
567 }
568
569 #[doc(hidden)]
570 pub fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
571 &mut self,
572 fn_name: &str,
573 ) -> QueryResult<()>
574 where
575 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + core::panic::UnwindSafe,
576 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
577 Ret: ToSql<RetSqlType, Sqlite>,
578 Sqlite: HasSqlType<RetSqlType>,
579 {
580 functions::register_aggregate::<_, _, _, _, A>(&self.raw_connection, fn_name)
581 }
582
583 pub fn register_collation<F>(&mut self, collation_name: &str, collation: F) -> QueryResult<()>
619 where
620 F: Fn(&str, &str) -> core::cmp::Ordering + Send + 'static + core::panic::UnwindSafe,
621 {
622 self.raw_connection
623 .register_collation_function(collation_name, collation)
624 }
625
626 pub fn serialize_database_to_buffer(&mut self) -> SerializedDatabase {
635 self.raw_connection.serialize()
636 }
637
638 pub fn deserialize_readonly_database_from_buffer(&mut self, data: &[u8]) -> QueryResult<()> {
675 self.serialized_data = data.to_vec();
678 self.raw_connection.deserialize(&self.serialized_data)
679 }
680
681 #[allow(unsafe_code)]
768 pub unsafe fn with_raw_connection<R, F>(&mut self, f: F) -> R
769 where
770 F: FnOnce(*mut ffi::sqlite3) -> R,
771 {
772 f(self.raw_connection.internal_connection.as_ptr())
773 }
774
775 #[allow(unsafe_code)]
784 pub(crate) unsafe fn with_borrowed_connection<R>(
785 db: core::ptr::NonNull<ffi::sqlite3>,
786 f: impl FnOnce(&mut SqliteConnection) -> R,
787 ) -> R {
788 struct Borrowed(core::mem::ManuallyDrop<SqliteConnection>);
791
792 impl Drop for Borrowed {
793 fn drop(&mut self) {
794 let conn = unsafe { core::mem::ManuallyDrop::take(&mut self.0) };
796 let SqliteConnection {
797 statement_cache,
798 raw_connection,
799 ..
800 } = conn;
801 drop(statement_cache);
804 core::mem::forget(raw_connection);
805 }
806 }
807
808 let mut conn = Borrowed(core::mem::ManuallyDrop::new(SqliteConnection {
809 statement_cache: StatementCache::new(),
810 raw_connection: RawConnection {
811 internal_connection: db,
812 },
813 transaction_state: AnsiTransactionManager::default(),
814 metadata_lookup: (),
815 instrumentation: DynInstrumentation::default_instrumentation(),
816 serialized_data: Vec::new(),
817 }));
818
819 let result = f(&mut conn.0);
820
821 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!(
824 matches!(
825 AnsiTransactionManager::transaction_manager_status_mut(&mut *conn.0)
826 .transaction_depth(),
827 Ok(None)
828 ),
829 "callback must not leave an open transaction on the borrowed connection"
830 );
831
832 result
833 }
834
835 fn register_diesel_sql_functions(&self) -> QueryResult<()> {
836 use crate::sql_types::{Integer, Text};
837
838 functions::register::<Text, Integer, _, _, _>(
839 &self.raw_connection,
840 "diesel_manage_updated_at",
841 false,
842 |conn, table_name: String| {
843 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!(
844 include_str!("diesel_manage_updated_at.sql"),
845 table_name = table_name
846 ))
847 .expect("Failed to create trigger");
848 0 },
850 )
851 }
852
853 fn establish_inner(database_url: &str) -> Result<SqliteConnection, ConnectionError> {
854 use crate::result::ConnectionError::CouldntSetupConfiguration;
855 let raw_connection = RawConnection::establish(database_url)?;
856 let conn = Self {
857 statement_cache: StatementCache::new(),
858 raw_connection,
859 transaction_state: AnsiTransactionManager::default(),
860 metadata_lookup: (),
861 instrumentation: DynInstrumentation::none(),
862 serialized_data: Vec::new(),
863 };
864 conn.register_diesel_sql_functions()
865 .map_err(CouldntSetupConfiguration)?;
866 Ok(conn)
867 }
868}
869
870fn error_message(err_code: libc::c_int) -> &'static str {
871 ffi::code_to_str(err_code)
872}
873
874mod private {
875 #[doc(hidden)]
876 pub trait HasDatabaseAndTableName {
877 fn database_name(&self) -> Option<&'static str>;
878 fn table_name(&self) -> &'static str;
879 }
880
881 impl HasDatabaseAndTableName for crate::query_builder::nodes::Identifier<'static> {
882 fn database_name(&self) -> Option<&'static str> {
883 None
884 }
885
886 fn table_name(&self) -> &'static str {
887 self.0
888 }
889 }
890
891 impl<M> HasDatabaseAndTableName
892 for crate::query_builder::nodes::InfixNode<
893 crate::query_builder::nodes::Identifier<'static>,
894 crate::query_builder::nodes::Identifier<'static>,
895 M,
896 >
897 {
898 fn database_name(&self) -> Option<&'static str> {
899 Some(self.lhs.0)
900 }
901
902 fn table_name(&self) -> &'static str {
903 self.rhs.0
904 }
905 }
906}
907pub(crate) use self::private::HasDatabaseAndTableName;
908
909#[cfg(test)]
910mod tests {
911 use super::*;
912 use crate::dsl::sql;
913 use crate::prelude::*;
914 use crate::sql_types::{Integer, Text};
915
916 fn connection() -> SqliteConnection {
917 SqliteConnection::establish(":memory:").unwrap()
918 }
919
920 #[diesel_test_helper::test]
921 #[allow(unsafe_code)]
922 fn with_raw_connection_can_return_values() {
923 let connection = &mut connection();
924
925 let autocommit_status = unsafe {
927 connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
928 };
929
930 assert_ne!(autocommit_status, 0, "Expected autocommit to be enabled");
932 }
933
934 #[diesel_test_helper::test]
935 #[allow(unsafe_code)]
936 fn with_raw_connection_works_after_diesel_operations() {
937 let connection = &mut connection();
938
939 crate::sql_query("CREATE TABLE test_table (id INTEGER PRIMARY KEY, value TEXT)")
941 .execute(connection)
942 .unwrap();
943 crate::sql_query("INSERT INTO test_table (value) VALUES ('hello')")
944 .execute(connection)
945 .unwrap();
946
947 let last_rowid = unsafe {
949 connection.with_raw_connection(|raw_conn| ffi::sqlite3_last_insert_rowid(raw_conn))
950 };
951
952 assert_eq!(last_rowid, 1, "Last insert rowid should be 1");
953
954 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM test_table")
956 .get_result(connection)
957 .unwrap();
958 assert_eq!(count, 1);
959 }
960
961 #[diesel_test_helper::test]
962 #[allow(unsafe_code)]
963 fn with_raw_connection_can_execute_raw_sql() {
964 let connection = &mut connection();
965
966 crate::sql_query("CREATE TABLE raw_test (id INTEGER PRIMARY KEY, name TEXT)")
968 .execute(connection)
969 .unwrap();
970
971 let result = unsafe {
974 connection.with_raw_connection(|raw_conn| {
975 let sql = c"INSERT INTO raw_test (name) VALUES ('from_raw')";
976 let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
977 let rc = ffi::sqlite3_exec(
978 raw_conn,
979 sql.as_ptr(),
980 None,
981 core::ptr::null_mut(),
982 &mut err_msg,
983 );
984 if rc != ffi::SQLITE_OK && !err_msg.is_null() {
985 ffi::sqlite3_free(err_msg as *mut libc::c_void);
986 }
987 rc
988 })
989 };
990
991 assert_eq!(result, ffi::SQLITE_OK, "Raw SQL execution should succeed");
992
993 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM raw_test")
995 .get_result(connection)
996 .unwrap();
997 assert_eq!(count, 1);
998
999 let name: String = sql::<Text>("SELECT name FROM raw_test WHERE id = 1")
1000 .get_result(connection)
1001 .unwrap();
1002 assert_eq!(name, "from_raw");
1003 }
1004
1005 #[diesel_test_helper::test]
1006 #[allow(unsafe_code)]
1007 fn with_raw_connection_works_within_transaction() {
1008 let connection = &mut connection();
1009
1010 crate::sql_query("CREATE TABLE txn_test (id INTEGER PRIMARY KEY, value INTEGER)")
1011 .execute(connection)
1012 .unwrap();
1013
1014 connection
1015 .transaction::<_, crate::result::Error, _>(|conn| {
1016 crate::sql_query("INSERT INTO txn_test (value) VALUES (42)")
1017 .execute(conn)
1018 .unwrap();
1019
1020 let autocommit = unsafe {
1022 conn.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1023 };
1024
1025 assert_eq!(
1027 autocommit, 0,
1028 "Autocommit should be disabled inside transaction"
1029 );
1030
1031 Ok(())
1032 })
1033 .unwrap();
1034
1035 let autocommit = unsafe {
1037 connection.with_raw_connection(|raw_conn| ffi::sqlite3_get_autocommit(raw_conn))
1038 };
1039 assert_ne!(
1040 autocommit, 0,
1041 "Autocommit should be enabled after transaction"
1042 );
1043 }
1044
1045 #[diesel_test_helper::test]
1046 #[allow(unsafe_code)]
1047 fn with_raw_connection_can_read_database_filename() {
1048 let connection = &mut connection();
1049
1050 let filename = unsafe {
1052 connection.with_raw_connection(|raw_conn| {
1053 let db_name = c"main";
1054 let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1055 if filename_ptr.is_null() {
1056 None
1057 } else {
1058 let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1060 Some(cstr.to_string_lossy().into_owned())
1061 }
1062 })
1063 };
1064
1065 assert_eq!(
1068 filename,
1069 Some(String::new()),
1070 "In-memory database filename should be an empty string"
1071 );
1072 }
1073
1074 #[diesel_test_helper::test]
1075 #[allow(unsafe_code)]
1076 fn with_raw_connection_changes_count() {
1077 let connection = &mut connection();
1078
1079 crate::sql_query("CREATE TABLE changes_test (id INTEGER PRIMARY KEY, value INTEGER)")
1080 .execute(connection)
1081 .unwrap();
1082
1083 crate::sql_query("INSERT INTO changes_test (value) VALUES (1), (2), (3)")
1084 .execute(connection)
1085 .unwrap();
1086
1087 let changes = unsafe {
1089 connection.with_raw_connection(|raw_conn| {
1090 let sql = c"UPDATE changes_test SET value = value + 10";
1091 let mut err_msg: *mut libc::c_char = core::ptr::null_mut();
1092 let rc = ffi::sqlite3_exec(
1093 raw_conn,
1094 sql.as_ptr(),
1095 None,
1096 core::ptr::null_mut(),
1097 &mut err_msg,
1098 );
1099 if rc != ffi::SQLITE_OK && !err_msg.is_null() {
1100 ffi::sqlite3_free(err_msg as *mut libc::c_void);
1101 return -1;
1102 }
1103 ffi::sqlite3_changes(raw_conn)
1104 })
1105 };
1106
1107 assert_eq!(changes, 3, "Should have updated 3 rows");
1108
1109 let values: Vec<i32> = sql::<Integer>("SELECT value FROM changes_test ORDER BY id")
1111 .load(connection)
1112 .unwrap();
1113 assert_eq!(values, vec![11, 12, 13]);
1114 }
1115
1116 #[diesel_test_helper::test]
1118 #[allow(unsafe_code)]
1119 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1120 fn with_raw_connection_recovers_after_panic() {
1121 let connection = &mut connection();
1122
1123 crate::sql_query("CREATE TABLE panic_test (id INTEGER PRIMARY KEY, value TEXT)")
1124 .execute(connection)
1125 .unwrap();
1126
1127 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
1129 connection.with_raw_connection(|_raw_conn| {
1130 panic!("intentional panic inside with_raw_connection");
1131 })
1132 }));
1133 assert!(result.is_err(), "Should have caught the panic");
1134
1135 crate::sql_query("INSERT INTO panic_test (value) VALUES ('after_panic')")
1137 .execute(connection)
1138 .unwrap();
1139
1140 let count: i64 = sql::<crate::sql_types::BigInt>("SELECT COUNT(*) FROM panic_test")
1141 .get_result(connection)
1142 .unwrap();
1143 assert_eq!(count, 1, "Connection should work after panic in callback");
1144 }
1145
1146 #[diesel_test_helper::test]
1148 #[allow(unsafe_code)]
1149 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
1150 fn with_raw_connection_can_read_file_database_filename() {
1151 let dir = std::env::temp_dir().join("diesel_test_filename.db");
1152 let db_path = dir.to_str().unwrap();
1153
1154 let _ = std::fs::remove_file(db_path);
1156
1157 let connection = &mut SqliteConnection::establish(db_path).unwrap();
1158
1159 let filename = unsafe {
1161 connection.with_raw_connection(|raw_conn| {
1162 let db_name = c"main";
1163 let filename_ptr = ffi::sqlite3_db_filename(raw_conn, db_name.as_ptr());
1164 if filename_ptr.is_null() {
1165 None
1166 } else {
1167 let cstr = core::ffi::CStr::from_ptr(filename_ptr);
1168 Some(cstr.to_string_lossy().into_owned())
1169 }
1170 })
1171 };
1172
1173 let filename = filename.expect("File-based database should have a filename");
1174 assert!(
1175 filename.contains("diesel_test_filename.db"),
1176 "Filename should contain the database name, got: {filename}"
1177 );
1178
1179 let _ = std::fs::remove_file(db_path);
1181 }
1182
1183 #[declare_sql_function]
1184 extern "SQL" {
1185 fn fun_case(x: Text) -> Text;
1186 fn my_add(x: Integer, y: Integer) -> Integer;
1187 fn answer() -> Integer;
1188 fn add_counter(x: Integer) -> Integer;
1189
1190 #[aggregate]
1191 fn my_sum(expr: Integer) -> Integer;
1192 #[aggregate]
1193 fn range_max(expr1: Integer, expr2: Integer, expr3: Integer) -> Nullable<Integer>;
1194 }
1195
1196 #[diesel_test_helper::test]
1197 fn database_serializes_and_deserializes_successfully() {
1198 let expected_users = vec![
1199 (
1200 1,
1201 "John Doe".to_string(),
1202 "john.doe@example.com".to_string(),
1203 ),
1204 (
1205 2,
1206 "Jane Doe".to_string(),
1207 "jane.doe@example.com".to_string(),
1208 ),
1209 ];
1210
1211 let conn1 = &mut connection();
1212 let _ =
1213 crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
1214 .execute(conn1);
1215 let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
1216 .execute(conn1);
1217
1218 let serialized_database = conn1.serialize_database_to_buffer();
1219
1220 let conn2 = &mut connection();
1221 conn2
1222 .deserialize_readonly_database_from_buffer(serialized_database.as_slice())
1223 .unwrap();
1224
1225 let query = sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1226 let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1227
1228 assert_eq!(expected_users, actual_users);
1229 std::mem::drop(serialized_database);
1233 let query = sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
1234 let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
1235
1236 assert_eq!(expected_users, actual_users);
1237 }
1238
1239 #[diesel_test_helper::test]
1240 fn register_custom_function() {
1241 let connection = &mut connection();
1242 fun_case_utils::register_impl(connection, |x: String| {
1243 x.chars()
1244 .enumerate()
1245 .map(|(i, c)| {
1246 if i % 2 == 0 {
1247 c.to_lowercase().to_string()
1248 } else {
1249 c.to_uppercase().to_string()
1250 }
1251 })
1252 .collect::<String>()
1253 })
1254 .unwrap();
1255
1256 let mapped_string = crate::select(fun_case("foobar"))
1257 .get_result::<String>(connection)
1258 .unwrap();
1259 assert_eq!("fOoBaR", mapped_string);
1260 }
1261
1262 #[diesel_test_helper::test]
1263 fn register_multiarg_function() {
1264 let connection = &mut connection();
1265 my_add_utils::register_impl(connection, |x: i32, y: i32| x + y).unwrap();
1266
1267 let added = crate::select(my_add(1, 2)).get_result::<i32>(connection);
1268 assert_eq!(Ok(3), added);
1269 }
1270
1271 #[diesel_test_helper::test]
1272 fn register_noarg_function() {
1273 let connection = &mut connection();
1274 answer_utils::register_impl(connection, || 42).unwrap();
1275
1276 let answer = crate::select(answer()).get_result::<i32>(connection);
1277 assert_eq!(Ok(42), answer);
1278 }
1279
1280 #[diesel_test_helper::test]
1281 fn register_nondeterministic_noarg_function() {
1282 let connection = &mut connection();
1283 answer_utils::register_nondeterministic_impl(connection, || 42).unwrap();
1284
1285 let answer = crate::select(answer()).get_result::<i32>(connection);
1286 assert_eq!(Ok(42), answer);
1287 }
1288
1289 #[diesel_test_helper::test]
1290 fn register_nondeterministic_function() {
1291 let connection = &mut connection();
1292 let mut y = 0;
1293 add_counter_utils::register_nondeterministic_impl(connection, move |x: i32| {
1294 y += 1;
1295 x + y
1296 })
1297 .unwrap();
1298
1299 let added = crate::select((add_counter(1), add_counter(1), add_counter(1)))
1300 .get_result::<(i32, i32, i32)>(connection);
1301 assert_eq!(Ok((2, 3, 4)), added);
1302 }
1303
1304 #[derive(Default)]
1305 struct MySum {
1306 sum: i32,
1307 }
1308
1309 impl SqliteAggregateFunction<i32> for MySum {
1310 type Output = i32;
1311
1312 fn step(&mut self, expr: i32) {
1313 self.sum += expr;
1314 }
1315
1316 fn finalize(aggregator: Option<Self>) -> Self::Output {
1317 aggregator.map(|a| a.sum).unwrap_or_default()
1318 }
1319 }
1320
1321 table! {
1322 my_sum_example {
1323 id -> Integer,
1324 value -> Integer,
1325 }
1326 }
1327
1328 #[diesel_test_helper::test]
1329 fn register_aggregate_function() {
1330 use self::my_sum_example::dsl::*;
1331
1332 let connection = &mut connection();
1333 crate::sql_query(
1334 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1335 )
1336 .execute(connection)
1337 .unwrap();
1338 crate::sql_query("INSERT INTO my_sum_example (value) VALUES (1), (2), (3)")
1339 .execute(connection)
1340 .unwrap();
1341
1342 my_sum_utils::register_impl::<MySum, _>(connection).unwrap();
1343
1344 let result = my_sum_example
1345 .select(my_sum(value))
1346 .get_result::<i32>(connection);
1347 assert_eq!(Ok(6), result);
1348 }
1349
1350 #[diesel_test_helper::test]
1351 fn register_aggregate_function_returns_finalize_default_on_empty_set() {
1352 use self::my_sum_example::dsl::*;
1353
1354 let connection = &mut connection();
1355 crate::sql_query(
1356 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
1357 )
1358 .execute(connection)
1359 .unwrap();
1360
1361 my_sum_utils::register_impl::<MySum, _>(connection).unwrap();
1362
1363 let result = my_sum_example
1364 .select(my_sum(value))
1365 .get_result::<i32>(connection);
1366 assert_eq!(Ok(0), result);
1367 }
1368
1369 #[derive(Default)]
1370 struct RangeMax<T> {
1371 max_value: Option<T>,
1372 }
1373
1374 impl<T: Default + Ord + Copy + Clone> SqliteAggregateFunction<(T, T, T)> for RangeMax<T> {
1375 type Output = Option<T>;
1376
1377 fn step(&mut self, (x0, x1, x2): (T, T, T)) {
1378 let max = if x0 >= x1 && x0 >= x2 {
1379 x0
1380 } else if x1 >= x0 && x1 >= x2 {
1381 x1
1382 } else {
1383 x2
1384 };
1385
1386 self.max_value = match self.max_value {
1387 Some(current_max_value) if max > current_max_value => Some(max),
1388 None => Some(max),
1389 _ => self.max_value,
1390 };
1391 }
1392
1393 fn finalize(aggregator: Option<Self>) -> Self::Output {
1394 aggregator?.max_value
1395 }
1396 }
1397
1398 table! {
1399 range_max_example {
1400 id -> Integer,
1401 value1 -> Integer,
1402 value2 -> Integer,
1403 value3 -> Integer,
1404 }
1405 }
1406
1407 #[diesel_test_helper::test]
1408 fn register_aggregate_multiarg_function() {
1409 use self::range_max_example::dsl::*;
1410
1411 let connection = &mut connection();
1412 crate::sql_query(
1413 r#"CREATE TABLE range_max_example (
1414 id integer primary key autoincrement,
1415 value1 integer,
1416 value2 integer,
1417 value3 integer
1418 )"#,
1419 )
1420 .execute(connection)
1421 .unwrap();
1422 crate::sql_query(
1423 "INSERT INTO range_max_example (value1, value2, value3) VALUES (3, 2, 1), (2, 2, 2)",
1424 )
1425 .execute(connection)
1426 .unwrap();
1427
1428 range_max_utils::register_impl::<RangeMax<i32>, _, _, _>(connection).unwrap();
1429 let result = range_max_example
1430 .select(range_max(value1, value2, value3))
1431 .get_result::<Option<i32>>(connection)
1432 .unwrap();
1433 assert_eq!(Some(3), result);
1434 }
1435
1436 table! {
1437 my_collation_example {
1438 id -> Integer,
1439 value -> Text,
1440 }
1441 }
1442
1443 #[diesel_test_helper::test]
1444 fn register_collation_function() {
1445 use self::my_collation_example::dsl::*;
1446
1447 let connection = &mut connection();
1448
1449 connection
1450 .register_collation("RUSTNOCASE", |rhs, lhs| {
1451 rhs.to_lowercase().cmp(&lhs.to_lowercase())
1452 })
1453 .unwrap();
1454
1455 crate::sql_query(
1456 "CREATE TABLE my_collation_example (id integer primary key autoincrement, value text collate RUSTNOCASE)",
1457 ).execute(connection)
1458 .unwrap();
1459 crate::sql_query(
1460 "INSERT INTO my_collation_example (value) VALUES ('foo'), ('FOo'), ('f00')",
1461 )
1462 .execute(connection)
1463 .unwrap();
1464
1465 let result = my_collation_example
1466 .filter(value.eq("foo"))
1467 .select(value)
1468 .load::<String>(connection);
1469 assert_eq!(
1470 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
1471 result.as_ref().map(|vec| vec.as_ref())
1472 );
1473
1474 let result = my_collation_example
1475 .filter(value.eq("FOO"))
1476 .select(value)
1477 .load::<String>(connection);
1478 assert_eq!(
1479 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
1480 result.as_ref().map(|vec| vec.as_ref())
1481 );
1482
1483 let result = my_collation_example
1484 .filter(value.eq("f00"))
1485 .select(value)
1486 .load::<String>(connection);
1487 assert_eq!(
1488 Ok(&["f00".to_owned()][..]),
1489 result.as_ref().map(|vec| vec.as_ref())
1490 );
1491
1492 let result = my_collation_example
1493 .filter(value.eq("F00"))
1494 .select(value)
1495 .load::<String>(connection);
1496 assert_eq!(
1497 Ok(&["f00".to_owned()][..]),
1498 result.as_ref().map(|vec| vec.as_ref())
1499 );
1500
1501 let result = my_collation_example
1502 .filter(value.eq("oof"))
1503 .select(value)
1504 .load::<String>(connection);
1505 assert_eq!(Ok(&[][..]), result.as_ref().map(|vec| vec.as_ref()));
1506 }
1507
1508 #[diesel_test_helper::test]
1510 fn test_correct_serialization_of_owned_strings() {
1511 use crate::prelude::*;
1512
1513 #[derive(Debug, crate::expression::AsExpression)]
1514 #[diesel(sql_type = diesel::sql_types::Text)]
1515 struct CustomWrapper(String);
1516
1517 impl crate::serialize::ToSql<Text, Sqlite> for CustomWrapper {
1518 fn to_sql<'b>(
1519 &'b self,
1520 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
1521 ) -> crate::serialize::Result {
1522 out.set_value(self.0.to_string());
1523 Ok(crate::serialize::IsNull::No)
1524 }
1525 }
1526
1527 let connection = &mut connection();
1528
1529 let res = crate::select(
1530 CustomWrapper("".into())
1531 .into_sql::<crate::sql_types::Text>()
1532 .nullable(),
1533 )
1534 .get_result::<Option<String>>(connection)
1535 .unwrap();
1536 assert_eq!(res, Some(String::new()));
1537 }
1538
1539 #[diesel_test_helper::test]
1540 fn test_correct_serialization_of_owned_bytes() {
1541 use crate::prelude::*;
1542
1543 #[derive(Debug, crate::expression::AsExpression)]
1544 #[diesel(sql_type = diesel::sql_types::Binary)]
1545 struct CustomWrapper(Vec<u8>);
1546
1547 impl crate::serialize::ToSql<crate::sql_types::Binary, Sqlite> for CustomWrapper {
1548 fn to_sql<'b>(
1549 &'b self,
1550 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
1551 ) -> crate::serialize::Result {
1552 out.set_value(self.0.clone());
1553 Ok(crate::serialize::IsNull::No)
1554 }
1555 }
1556
1557 let connection = &mut connection();
1558
1559 let res = crate::select(
1560 CustomWrapper(Vec::new())
1561 .into_sql::<crate::sql_types::Binary>()
1562 .nullable(),
1563 )
1564 .get_result::<Option<Vec<u8>>>(connection)
1565 .unwrap();
1566 assert_eq!(res, Some(Vec::new()));
1567 }
1568
1569 #[diesel_test_helper::test]
1570 fn correctly_handle_empty_query() {
1571 let check_empty_query_error = |r: crate::QueryResult<usize>| {
1572 assert!(r.is_err());
1573 let err = r.unwrap_err();
1574 assert!(
1575 matches!(err, crate::result::Error::QueryBuilderError(ref b) if b.is::<crate::result::EmptyQuery>()),
1576 "Expected a query builder error, but got {err}"
1577 );
1578 };
1579 let connection = &mut SqliteConnection::establish(":memory:").unwrap();
1580 check_empty_query_error(crate::sql_query("").execute(connection));
1581 check_empty_query_error(crate::sql_query(" ").execute(connection));
1582 check_empty_query_error(crate::sql_query("\n\t").execute(connection));
1583 check_empty_query_error(crate::sql_query("-- SELECT 1;").execute(connection));
1584 }
1585
1586 #[diesel_test_helper::test]
1587 fn last_insert_rowid_returns_none_on_fresh_connection() {
1588 let conn = &mut connection();
1589 assert_eq!(conn.last_insert_rowid(), None);
1590 }
1591
1592 #[diesel_test_helper::test]
1593 fn last_insert_rowid_returns_rowid_after_insert() {
1594 let conn = &mut connection();
1595 crate::sql_query("CREATE TABLE li_test (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1596 .execute(conn)
1597 .unwrap();
1598
1599 crate::sql_query("INSERT INTO li_test (val) VALUES ('a')")
1600 .execute(conn)
1601 .unwrap();
1602 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1603
1604 crate::sql_query("INSERT INTO li_test (val) VALUES ('b')")
1605 .execute(conn)
1606 .unwrap();
1607 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(2));
1608 }
1609
1610 #[diesel_test_helper::test]
1611 fn last_insert_rowid_unchanged_after_failed_insert() {
1612 let conn = &mut connection();
1613 crate::sql_query(
1614 "CREATE TABLE li_test2 (id INTEGER PRIMARY KEY, val TEXT NOT NULL UNIQUE)",
1615 )
1616 .execute(conn)
1617 .unwrap();
1618
1619 crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')")
1620 .execute(conn)
1621 .unwrap();
1622 let rowid = conn.last_insert_rowid();
1623 assert_eq!(rowid, NonZeroI64::new(1));
1624
1625 let result = crate::sql_query("INSERT INTO li_test2 (val) VALUES ('a')").execute(conn);
1627 assert!(result.is_err());
1628
1629 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1631 }
1632
1633 #[diesel_test_helper::test]
1634 fn last_insert_rowid_with_explicit_rowid() {
1635 let conn = &mut connection();
1636 crate::sql_query("CREATE TABLE li_test3 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1637 .execute(conn)
1638 .unwrap();
1639
1640 crate::sql_query("INSERT INTO li_test3 (id, val) VALUES (42, 'a')")
1641 .execute(conn)
1642 .unwrap();
1643 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(42));
1644 }
1645
1646 #[diesel_test_helper::test]
1647 fn last_insert_rowid_unchanged_after_delete_and_update() {
1648 let conn = &mut connection();
1649 crate::sql_query("CREATE TABLE li_test4 (id INTEGER PRIMARY KEY, val TEXT NOT NULL)")
1650 .execute(conn)
1651 .unwrap();
1652
1653 crate::sql_query("INSERT INTO li_test4 (val) VALUES ('a')")
1654 .execute(conn)
1655 .unwrap();
1656 let rowid = conn.last_insert_rowid();
1657 assert_eq!(rowid, NonZeroI64::new(1));
1658
1659 crate::sql_query("UPDATE li_test4 SET val = 'b' WHERE id = 1")
1660 .execute(conn)
1661 .unwrap();
1662 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1663
1664 crate::sql_query("DELETE FROM li_test4 WHERE id = 1")
1665 .execute(conn)
1666 .unwrap();
1667 assert_eq!(conn.last_insert_rowid(), NonZeroI64::new(1));
1668 }
1669
1670 #[diesel_test_helper::test]
1671 fn read_bytes_from_blob() {
1672 table! {
1673 blobs {
1674 id -> Integer,
1675 data -> Blob,
1676 data2 -> Blob,
1677 }
1678 }
1679
1680 use std::io::Read;
1681
1682 let conn = &mut connection();
1683
1684 let _ =
1685 crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB, data2 BLOB)")
1686 .execute(conn);
1687
1688 let _ = crate::sql_query(
1689 "INSERT INTO blobs (data, data2) VALUES ('abc', 'def'), ('123', '456')",
1690 )
1691 .execute(conn);
1692
1693 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
1694 let mut buf = vec![];
1695 data.read_to_end(&mut buf).unwrap();
1696
1697 assert_eq!(buf, b"abc");
1698
1699 let mut data2 = conn.get_read_only_blob(blobs::data2, 1).unwrap();
1700 let mut buf = vec![];
1701 data2.read_to_end(&mut buf).unwrap();
1702
1703 assert_eq!(buf, b"def");
1704 }
1705
1706 #[diesel_test_helper::test]
1707 fn read_seek_bytes() {
1708 table! {
1709 blobs {
1710 id -> Integer,
1711 data -> Blob,
1712 }
1713 }
1714
1715 use std::io::Read;
1716 use std::io::Seek;
1717 use std::io::SeekFrom;
1718
1719 let conn = &mut connection();
1720
1721 let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
1722 .execute(conn);
1723
1724 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abcdefghi')").execute(conn);
1725
1726 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
1727
1728 let mut buf = [0; 1];
1729 assert_eq!(data.read(&mut buf).unwrap(), 1);
1730 assert_eq!(&buf, b"a");
1731
1732 assert_eq!(data.seek(SeekFrom::Current(1)).unwrap(), 2);
1734
1735 let mut buf = [0; 1];
1736 assert_eq!(data.read(&mut buf).unwrap(), 1);
1737 assert_eq!(&buf, b"c");
1738
1739 assert_eq!(data.seek(SeekFrom::Start(0)).unwrap(), 0);
1741
1742 let mut buf = [0; 1];
1743 assert_eq!(data.read(&mut buf).unwrap(), 1);
1744 assert_eq!(&buf, b"a");
1745
1746 assert_eq!(data.seek(SeekFrom::Current(-10)).unwrap(), 0);
1748
1749 let mut buf = [0; 1];
1750 assert_eq!(data.read(&mut buf).unwrap(), 1);
1751 assert_eq!(&buf, b"a");
1752
1753 data.seek(SeekFrom::Current(100)).unwrap();
1755
1756 let mut buf = [0; 1];
1758 assert_eq!(data.read(&mut buf).unwrap(), 0);
1759 }
1760
1761 #[diesel_test_helper::test]
1762 fn use_conn_after_blob_drop() {
1763 table! {
1764 blobs {
1765 id -> Integer,
1766 data -> Blob,
1767 }
1768 }
1769
1770 let conn = &mut connection();
1771
1772 let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
1773 .execute(conn);
1774
1775 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abc')").execute(conn);
1776
1777 let data = conn.get_read_only_blob(blobs::data, 1).unwrap();
1778 drop(data);
1779
1780 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('def')").execute(conn);
1781 }
1782
1783 #[diesel_test_helper::test]
1784 fn blob_transaction() {
1785 table! {
1786 blobs {
1787 id -> Integer,
1788 data -> Blob,
1789 }
1790 }
1791
1792 use std::io::Read;
1793
1794 let conn = &mut connection();
1795
1796 let _ = crate::sql_query("CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB)")
1797 .execute(conn);
1798
1799 let _ = crate::sql_query("INSERT INTO blobs (data) VALUES ('abc')").execute(conn);
1800
1801 {
1802 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
1803 let mut buf = vec![];
1804 data.read_to_end(&mut buf).unwrap();
1805 assert_eq!(buf, b"abc");
1806 }
1807
1808 let res = conn.exclusive_transaction(|conn| {
1809 crate::sql_query("UPDATE blobs SET data = 'def' WHERE id = 1").execute(conn)?;
1810
1811 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
1812 let mut buf = vec![];
1813 data.read_to_end(&mut buf).unwrap();
1814 assert_eq!(buf, b"def");
1815
1816 Result::<(), _>::Err(Error::RollbackTransaction)
1817 });
1818
1819 assert_eq!(res.unwrap_err(), Error::RollbackTransaction);
1820
1821 let mut data = conn.get_read_only_blob(blobs::data, 1).unwrap();
1822 let mut buf = vec![];
1823 data.read_to_end(&mut buf).unwrap();
1824 assert_eq!(buf, b"abc");
1825 }
1826
1827 #[diesel_test_helper::test]
1828 fn aggregate_function_works_with_aligned_data() {
1829 #[derive(Debug, Default)]
1830 #[repr(align(64))]
1831 struct OverAligned;
1832
1833 impl SqliteAggregateFunction<i32> for OverAligned {
1834 type Output = i64;
1835
1836 fn step(&mut self, _value: i32) {
1837 let need = core::mem::align_of::<Self>();
1838 let got = core::mem::align_of_val(self);
1839 assert_eq!(need, got);
1840 }
1841
1842 fn finalize(_agg: Option<Self>) -> i64 {
1843 0
1844 }
1845 }
1846 #[declare_sql_function]
1847 extern "SQL" {
1848 #[aggregate]
1849 fn over_aligned_sum(x: Integer) -> diesel::sql_types::BigInt;
1850 }
1851
1852 let mut conn = SqliteConnection::establish(":memory:").unwrap();
1853 over_aligned_sum_utils::register_impl::<OverAligned, _>(&mut conn).unwrap();
1854
1855 diesel::select(over_aligned_sum(1))
1856 .execute(&mut conn)
1857 .unwrap();
1858 }
1859
1860 #[diesel_test_helper::test]
1861 fn sum_twice() {
1862 #[derive(Default)]
1863 struct Sum(i32);
1864
1865 impl SqliteAggregateFunction<i32> for Sum {
1866 type Output = i32;
1867
1868 fn step(&mut self, value: i32) {
1869 self.0 += value;
1870 }
1871
1872 fn finalize(agg: Option<Self>) -> i32 {
1873 agg.map(|s| s.0).unwrap_or_default()
1874 }
1875 }
1876
1877 #[declare_sql_function]
1878 extern "SQL" {
1879 #[aggregate]
1880 fn my_sum(x: Integer) -> Integer;
1881 }
1882
1883 let mut conn = SqliteConnection::establish(":memory:").unwrap();
1884 my_sum_utils::register_impl::<Sum, _>(&mut conn).unwrap();
1885
1886 conn.batch_execute(
1887 "
1888 CREATE TABLE test(key1 INTEGER, key2 INTEGER);
1889 INSERT INTO test(key1, key2) VALUES (1, 2), (2, 4), (3, 6);
1890",
1891 )
1892 .unwrap();
1893
1894 table! {
1895 test (key1, key2) {
1896 key1 -> Integer,
1897 key2 -> Integer,
1898 }
1899 }
1900
1901 let (first_res, second_res) = test::table
1902 .select((my_sum(test::key1), my_sum(test::key2)))
1903 .get_result::<(i32, i32)>(&mut conn)
1904 .unwrap();
1905
1906 assert_eq!(first_res, 6);
1907 assert_eq!(second_res, 12);
1908
1909 conn.batch_execute("DELETE FROM test").unwrap();
1910 let (first_res, second_res) = test::table
1911 .select((my_sum(test::key1), my_sum(test::key2)))
1912 .get_result::<(i32, i32)>(&mut conn)
1913 .unwrap();
1914
1915 assert_eq!(first_res, 0);
1916 assert_eq!(second_res, 0);
1917 }
1918
1919 #[diesel_test_helper::test]
1920 fn test_injection() {
1921 diesel::table! {
1922 #[sql_name = "quote'table"]
1923 quote_table (id) {
1924 id -> Nullable<Integer>,
1925 name -> Nullable<Text>,
1926 }
1927 }
1928
1929 let mut conn = SqliteConnection::establish(":memory:").unwrap();
1930
1931 conn.batch_execute("CREATE TABLE \"quote'table\" (id INTEGER PRIMARY KEY, name TEXT);")
1932 .unwrap();
1933
1934 diesel::insert_into(quote_table::table)
1935 .values((quote_table::id.eq(1), quote_table::name.eq("Jane")))
1936 .execute(&mut conn)
1937 .unwrap();
1938
1939 let data = quote_table::table
1940 .load::<(Option<i32>, Option<String>)>(&mut conn)
1941 .unwrap();
1942 assert_eq!(data, [(Some(1), Some("Jane".to_owned()))]);
1943 }
1944}