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 std::os::raw as libc;
23
24use self::raw::RawConnection;
25use self::statement_iterator::*;
26use self::stmt::{Statement, StatementUse};
27use super::SqliteAggregateFunction;
28use crate::connection::instrumentation::{DynInstrumentation, StrQueryHelper};
29use crate::connection::statement_cache::StatementCache;
30use crate::connection::*;
31use crate::deserialize::{FromSqlRow, StaticallySizedRow};
32use crate::expression::QueryMetadata;
33use crate::query_builder::*;
34use crate::result::*;
35use crate::serialize::ToSql;
36use crate::sql_types::{HasSqlType, TypeMetadata};
37use crate::sqlite::Sqlite;
38
39#[allow(missing_debug_implementations)]
162#[cfg(feature = "sqlite")]
163pub struct SqliteConnection {
164 statement_cache: StatementCache<Sqlite, Statement>,
168 raw_connection: RawConnection,
169 transaction_state: AnsiTransactionManager,
170 metadata_lookup: (),
173 instrumentation: DynInstrumentation,
174}
175
176#[allow(unsafe_code)]
180unsafe impl Send for SqliteConnection {}
181
182impl SimpleConnection for SqliteConnection {
183 fn batch_execute(&mut self, query: &str) -> QueryResult<()> {
184 self.instrumentation
185 .on_connection_event(InstrumentationEvent::StartQuery {
186 query: &StrQueryHelper::new(query),
187 });
188 let resp = self.raw_connection.exec(query);
189 self.instrumentation
190 .on_connection_event(InstrumentationEvent::FinishQuery {
191 query: &StrQueryHelper::new(query),
192 error: resp.as_ref().err(),
193 });
194 resp
195 }
196}
197
198impl ConnectionSealed for SqliteConnection {}
199
200impl Connection for SqliteConnection {
201 type Backend = Sqlite;
202 type TransactionManager = AnsiTransactionManager;
203
204 fn establish(database_url: &str) -> ConnectionResult<Self> {
220 let mut instrumentation = DynInstrumentation::default_instrumentation();
221 instrumentation.on_connection_event(InstrumentationEvent::StartEstablishConnection {
222 url: database_url,
223 });
224
225 let establish_result = Self::establish_inner(database_url);
226 instrumentation.on_connection_event(InstrumentationEvent::FinishEstablishConnection {
227 url: database_url,
228 error: establish_result.as_ref().err(),
229 });
230 let mut conn = establish_result?;
231 conn.instrumentation = instrumentation;
232 Ok(conn)
233 }
234
235 fn execute_returning_count<T>(&mut self, source: &T) -> QueryResult<usize>
236 where
237 T: QueryFragment<Self::Backend> + QueryId,
238 {
239 let statement_use = self.prepared_query(source)?;
240 statement_use.run().and_then(|_| {
241 self.raw_connection
242 .rows_affected_by_last_query()
243 .map_err(Error::DeserializationError)
244 })
245 }
246
247 fn transaction_state(&mut self) -> &mut AnsiTransactionManager
248 where
249 Self: Sized,
250 {
251 &mut self.transaction_state
252 }
253
254 fn instrumentation(&mut self) -> &mut dyn Instrumentation {
255 &mut *self.instrumentation
256 }
257
258 fn set_instrumentation(&mut self, instrumentation: impl Instrumentation) {
259 self.instrumentation = instrumentation.into();
260 }
261
262 fn set_prepared_statement_cache_size(&mut self, size: CacheSize) {
263 self.statement_cache.set_cache_size(size);
264 }
265}
266
267impl LoadConnection<DefaultLoadingMode> for SqliteConnection {
268 type Cursor<'conn, 'query> = StatementIterator<'conn, 'query>;
269 type Row<'conn, 'query> = self::row::SqliteRow<'conn, 'query>;
270
271 fn load<'conn, 'query, T>(
272 &'conn mut self,
273 source: T,
274 ) -> QueryResult<Self::Cursor<'conn, 'query>>
275 where
276 T: Query + QueryFragment<Self::Backend> + QueryId + 'query,
277 Self::Backend: QueryMetadata<T::SqlType>,
278 {
279 let statement = self.prepared_query(source)?;
280
281 Ok(StatementIterator::new(statement))
282 }
283}
284
285impl WithMetadataLookup for SqliteConnection {
286 fn metadata_lookup(&mut self) -> &mut <Sqlite as TypeMetadata>::MetadataLookup {
287 &mut self.metadata_lookup
288 }
289}
290
291#[cfg(feature = "r2d2")]
292impl crate::r2d2::R2D2Connection for crate::sqlite::SqliteConnection {
293 fn ping(&mut self) -> QueryResult<()> {
294 use crate::RunQueryDsl;
295
296 crate::r2d2::CheckConnectionQuery.execute(self).map(|_| ())
297 }
298
299 fn is_broken(&mut self) -> bool {
300 AnsiTransactionManager::is_broken_transaction_manager(self)
301 }
302}
303
304impl MultiConnectionHelper for SqliteConnection {
305 fn to_any<'a>(
306 lookup: &mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup,
307 ) -> &mut (dyn std::any::Any + 'a) {
308 lookup
309 }
310
311 fn from_any(
312 lookup: &mut dyn std::any::Any,
313 ) -> Option<&mut <Self::Backend as crate::sql_types::TypeMetadata>::MetadataLookup> {
314 lookup.downcast_mut()
315 }
316}
317
318impl SqliteConnection {
319 pub fn immediate_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
341 where
342 F: FnOnce(&mut Self) -> Result<T, E>,
343 E: From<Error>,
344 {
345 self.transaction_sql(f, "BEGIN IMMEDIATE")
346 }
347
348 pub fn exclusive_transaction<T, E, F>(&mut self, f: F) -> Result<T, E>
370 where
371 F: FnOnce(&mut Self) -> Result<T, E>,
372 E: From<Error>,
373 {
374 self.transaction_sql(f, "BEGIN EXCLUSIVE")
375 }
376
377 fn transaction_sql<T, E, F>(&mut self, f: F, sql: &str) -> Result<T, E>
378 where
379 F: FnOnce(&mut Self) -> Result<T, E>,
380 E: From<Error>,
381 {
382 AnsiTransactionManager::begin_transaction_sql(&mut *self, sql)?;
383 match f(&mut *self) {
384 Ok(value) => {
385 AnsiTransactionManager::commit_transaction(&mut *self)?;
386 Ok(value)
387 }
388 Err(e) => {
389 AnsiTransactionManager::rollback_transaction(&mut *self)?;
390 Err(e)
391 }
392 }
393 }
394
395 fn prepared_query<'conn, 'query, T>(
396 &'conn mut self,
397 source: T,
398 ) -> QueryResult<StatementUse<'conn, 'query>>
399 where
400 T: QueryFragment<Sqlite> + QueryId + 'query,
401 {
402 self.instrumentation
403 .on_connection_event(InstrumentationEvent::StartQuery {
404 query: &crate::debug_query(&source),
405 });
406 let raw_connection = &self.raw_connection;
407 let cache = &mut self.statement_cache;
408 let statement = match cache.cached_statement(
409 &source,
410 &Sqlite,
411 &[],
412 raw_connection,
413 Statement::prepare,
414 &mut *self.instrumentation,
415 ) {
416 Ok(statement) => statement,
417 Err(e) => {
418 self.instrumentation
419 .on_connection_event(InstrumentationEvent::FinishQuery {
420 query: &crate::debug_query(&source),
421 error: Some(&e),
422 });
423
424 return Err(e);
425 }
426 };
427
428 StatementUse::bind(statement, source, &mut *self.instrumentation)
429 }
430
431 #[doc(hidden)]
432 pub fn register_sql_function<ArgsSqlType, RetSqlType, Args, Ret, F>(
433 &mut self,
434 fn_name: &str,
435 deterministic: bool,
436 mut f: F,
437 ) -> QueryResult<()>
438 where
439 F: FnMut(Args) -> Ret + std::panic::UnwindSafe + Send + 'static,
440 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
441 Ret: ToSql<RetSqlType, Sqlite>,
442 Sqlite: HasSqlType<RetSqlType>,
443 {
444 functions::register(
445 &self.raw_connection,
446 fn_name,
447 deterministic,
448 move |_, args| f(args),
449 )
450 }
451
452 #[doc(hidden)]
453 pub fn register_noarg_sql_function<RetSqlType, Ret, F>(
454 &self,
455 fn_name: &str,
456 deterministic: bool,
457 f: F,
458 ) -> QueryResult<()>
459 where
460 F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
461 Ret: ToSql<RetSqlType, Sqlite>,
462 Sqlite: HasSqlType<RetSqlType>,
463 {
464 functions::register_noargs(&self.raw_connection, fn_name, deterministic, f)
465 }
466
467 #[doc(hidden)]
468 pub fn register_aggregate_function<ArgsSqlType, RetSqlType, Args, Ret, A>(
469 &mut self,
470 fn_name: &str,
471 ) -> QueryResult<()>
472 where
473 A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + std::panic::UnwindSafe,
474 Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
475 Ret: ToSql<RetSqlType, Sqlite>,
476 Sqlite: HasSqlType<RetSqlType>,
477 {
478 functions::register_aggregate::<_, _, _, _, A>(&self.raw_connection, fn_name)
479 }
480
481 pub fn register_collation<F>(&mut self, collation_name: &str, collation: F) -> QueryResult<()>
517 where
518 F: Fn(&str, &str) -> std::cmp::Ordering + Send + 'static + std::panic::UnwindSafe,
519 {
520 self.raw_connection
521 .register_collation_function(collation_name, collation)
522 }
523
524 pub fn serialize_database_to_buffer(&mut self) -> SerializedDatabase {
533 self.raw_connection.serialize()
534 }
535
536 pub fn deserialize_readonly_database_from_buffer(&mut self, data: &[u8]) -> QueryResult<()> {
573 self.raw_connection.deserialize(data)
574 }
575
576 fn register_diesel_sql_functions(&self) -> QueryResult<()> {
577 use crate::sql_types::{Integer, Text};
578
579 functions::register::<Text, Integer, _, _, _>(
580 &self.raw_connection,
581 "diesel_manage_updated_at",
582 false,
583 |conn, table_name: String| {
584 conn.exec(&format!(
585 include_str!("diesel_manage_updated_at.sql"),
586 table_name = table_name
587 ))
588 .expect("Failed to create trigger");
589 0 },
591 )
592 }
593
594 fn establish_inner(database_url: &str) -> Result<SqliteConnection, ConnectionError> {
595 use crate::result::ConnectionError::CouldntSetupConfiguration;
596 let raw_connection = RawConnection::establish(database_url)?;
597 let conn = Self {
598 statement_cache: StatementCache::new(),
599 raw_connection,
600 transaction_state: AnsiTransactionManager::default(),
601 metadata_lookup: (),
602 instrumentation: DynInstrumentation::none(),
603 };
604 conn.register_diesel_sql_functions()
605 .map_err(CouldntSetupConfiguration)?;
606 Ok(conn)
607 }
608}
609
610fn error_message(err_code: libc::c_int) -> &'static str {
611 ffi::code_to_str(err_code)
612}
613
614#[cfg(test)]
615mod tests {
616 use super::*;
617 use crate::dsl::sql;
618 use crate::prelude::*;
619 use crate::sql_types::{Integer, Text};
620
621 fn connection() -> SqliteConnection {
622 SqliteConnection::establish(":memory:").unwrap()
623 }
624
625 #[declare_sql_function]
626 extern "SQL" {
627 fn fun_case(x: Text) -> Text;
628 fn my_add(x: Integer, y: Integer) -> Integer;
629 fn answer() -> Integer;
630 fn add_counter(x: Integer) -> Integer;
631
632 #[aggregate]
633 fn my_sum(expr: Integer) -> Integer;
634 #[aggregate]
635 fn range_max(expr1: Integer, expr2: Integer, expr3: Integer) -> Nullable<Integer>;
636 }
637
638 #[diesel_test_helper::test]
639 fn database_serializes_and_deserializes_successfully() {
640 let expected_users = vec![
641 (
642 1,
643 "John Doe".to_string(),
644 "john.doe@example.com".to_string(),
645 ),
646 (
647 2,
648 "Jane Doe".to_string(),
649 "jane.doe@example.com".to_string(),
650 ),
651 ];
652
653 let conn1 = &mut connection();
654 let _ =
655 crate::sql_query("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)")
656 .execute(conn1);
657 let _ = crate::sql_query("INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com'), ('Jane Doe', 'jane.doe@example.com')")
658 .execute(conn1);
659
660 let serialized_database = conn1.serialize_database_to_buffer();
661
662 let conn2 = &mut connection();
663 conn2
664 .deserialize_readonly_database_from_buffer(serialized_database.as_slice())
665 .unwrap();
666
667 let query = sql::<(Integer, Text, Text)>("SELECT id, name, email FROM users ORDER BY id");
668 let actual_users = query.load::<(i32, String, String)>(conn2).unwrap();
669
670 assert_eq!(expected_users, actual_users);
671 }
672
673 #[diesel_test_helper::test]
674 fn register_custom_function() {
675 let connection = &mut connection();
676 fun_case_utils::register_impl(connection, |x: String| {
677 x.chars()
678 .enumerate()
679 .map(|(i, c)| {
680 if i % 2 == 0 {
681 c.to_lowercase().to_string()
682 } else {
683 c.to_uppercase().to_string()
684 }
685 })
686 .collect::<String>()
687 })
688 .unwrap();
689
690 let mapped_string = crate::select(fun_case("foobar"))
691 .get_result::<String>(connection)
692 .unwrap();
693 assert_eq!("fOoBaR", mapped_string);
694 }
695
696 #[diesel_test_helper::test]
697 fn register_multiarg_function() {
698 let connection = &mut connection();
699 my_add_utils::register_impl(connection, |x: i32, y: i32| x + y).unwrap();
700
701 let added = crate::select(my_add(1, 2)).get_result::<i32>(connection);
702 assert_eq!(Ok(3), added);
703 }
704
705 #[diesel_test_helper::test]
706 fn register_noarg_function() {
707 let connection = &mut connection();
708 answer_utils::register_impl(connection, || 42).unwrap();
709
710 let answer = crate::select(answer()).get_result::<i32>(connection);
711 assert_eq!(Ok(42), answer);
712 }
713
714 #[diesel_test_helper::test]
715 fn register_nondeterministic_noarg_function() {
716 let connection = &mut connection();
717 answer_utils::register_nondeterministic_impl(connection, || 42).unwrap();
718
719 let answer = crate::select(answer()).get_result::<i32>(connection);
720 assert_eq!(Ok(42), answer);
721 }
722
723 #[diesel_test_helper::test]
724 fn register_nondeterministic_function() {
725 let connection = &mut connection();
726 let mut y = 0;
727 add_counter_utils::register_nondeterministic_impl(connection, move |x: i32| {
728 y += 1;
729 x + y
730 })
731 .unwrap();
732
733 let added = crate::select((add_counter(1), add_counter(1), add_counter(1)))
734 .get_result::<(i32, i32, i32)>(connection);
735 assert_eq!(Ok((2, 3, 4)), added);
736 }
737
738 #[derive(Default)]
739 struct MySum {
740 sum: i32,
741 }
742
743 impl SqliteAggregateFunction<i32> for MySum {
744 type Output = i32;
745
746 fn step(&mut self, expr: i32) {
747 self.sum += expr;
748 }
749
750 fn finalize(aggregator: Option<Self>) -> Self::Output {
751 aggregator.map(|a| a.sum).unwrap_or_default()
752 }
753 }
754
755 table! {
756 my_sum_example {
757 id -> Integer,
758 value -> Integer,
759 }
760 }
761
762 #[diesel_test_helper::test]
763 fn register_aggregate_function() {
764 use self::my_sum_example::dsl::*;
765
766 let connection = &mut connection();
767 crate::sql_query(
768 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
769 )
770 .execute(connection)
771 .unwrap();
772 crate::sql_query("INSERT INTO my_sum_example (value) VALUES (1), (2), (3)")
773 .execute(connection)
774 .unwrap();
775
776 my_sum_utils::register_impl::<MySum, _>(connection).unwrap();
777
778 let result = my_sum_example
779 .select(my_sum(value))
780 .get_result::<i32>(connection);
781 assert_eq!(Ok(6), result);
782 }
783
784 #[diesel_test_helper::test]
785 fn register_aggregate_function_returns_finalize_default_on_empty_set() {
786 use self::my_sum_example::dsl::*;
787
788 let connection = &mut connection();
789 crate::sql_query(
790 "CREATE TABLE my_sum_example (id integer primary key autoincrement, value integer)",
791 )
792 .execute(connection)
793 .unwrap();
794
795 my_sum_utils::register_impl::<MySum, _>(connection).unwrap();
796
797 let result = my_sum_example
798 .select(my_sum(value))
799 .get_result::<i32>(connection);
800 assert_eq!(Ok(0), result);
801 }
802
803 #[derive(Default)]
804 struct RangeMax<T> {
805 max_value: Option<T>,
806 }
807
808 impl<T: Default + Ord + Copy + Clone> SqliteAggregateFunction<(T, T, T)> for RangeMax<T> {
809 type Output = Option<T>;
810
811 fn step(&mut self, (x0, x1, x2): (T, T, T)) {
812 let max = if x0 >= x1 && x0 >= x2 {
813 x0
814 } else if x1 >= x0 && x1 >= x2 {
815 x1
816 } else {
817 x2
818 };
819
820 self.max_value = match self.max_value {
821 Some(current_max_value) if max > current_max_value => Some(max),
822 None => Some(max),
823 _ => self.max_value,
824 };
825 }
826
827 fn finalize(aggregator: Option<Self>) -> Self::Output {
828 aggregator?.max_value
829 }
830 }
831
832 table! {
833 range_max_example {
834 id -> Integer,
835 value1 -> Integer,
836 value2 -> Integer,
837 value3 -> Integer,
838 }
839 }
840
841 #[diesel_test_helper::test]
842 fn register_aggregate_multiarg_function() {
843 use self::range_max_example::dsl::*;
844
845 let connection = &mut connection();
846 crate::sql_query(
847 r#"CREATE TABLE range_max_example (
848 id integer primary key autoincrement,
849 value1 integer,
850 value2 integer,
851 value3 integer
852 )"#,
853 )
854 .execute(connection)
855 .unwrap();
856 crate::sql_query(
857 "INSERT INTO range_max_example (value1, value2, value3) VALUES (3, 2, 1), (2, 2, 2)",
858 )
859 .execute(connection)
860 .unwrap();
861
862 range_max_utils::register_impl::<RangeMax<i32>, _, _, _>(connection).unwrap();
863 let result = range_max_example
864 .select(range_max(value1, value2, value3))
865 .get_result::<Option<i32>>(connection)
866 .unwrap();
867 assert_eq!(Some(3), result);
868 }
869
870 table! {
871 my_collation_example {
872 id -> Integer,
873 value -> Text,
874 }
875 }
876
877 #[diesel_test_helper::test]
878 fn register_collation_function() {
879 use self::my_collation_example::dsl::*;
880
881 let connection = &mut connection();
882
883 connection
884 .register_collation("RUSTNOCASE", |rhs, lhs| {
885 rhs.to_lowercase().cmp(&lhs.to_lowercase())
886 })
887 .unwrap();
888
889 crate::sql_query(
890 "CREATE TABLE my_collation_example (id integer primary key autoincrement, value text collate RUSTNOCASE)",
891 ).execute(connection)
892 .unwrap();
893 crate::sql_query(
894 "INSERT INTO my_collation_example (value) VALUES ('foo'), ('FOo'), ('f00')",
895 )
896 .execute(connection)
897 .unwrap();
898
899 let result = my_collation_example
900 .filter(value.eq("foo"))
901 .select(value)
902 .load::<String>(connection);
903 assert_eq!(
904 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
905 result.as_ref().map(|vec| vec.as_ref())
906 );
907
908 let result = my_collation_example
909 .filter(value.eq("FOO"))
910 .select(value)
911 .load::<String>(connection);
912 assert_eq!(
913 Ok(&["foo".to_owned(), "FOo".to_owned()][..]),
914 result.as_ref().map(|vec| vec.as_ref())
915 );
916
917 let result = my_collation_example
918 .filter(value.eq("f00"))
919 .select(value)
920 .load::<String>(connection);
921 assert_eq!(
922 Ok(&["f00".to_owned()][..]),
923 result.as_ref().map(|vec| vec.as_ref())
924 );
925
926 let result = my_collation_example
927 .filter(value.eq("F00"))
928 .select(value)
929 .load::<String>(connection);
930 assert_eq!(
931 Ok(&["f00".to_owned()][..]),
932 result.as_ref().map(|vec| vec.as_ref())
933 );
934
935 let result = my_collation_example
936 .filter(value.eq("oof"))
937 .select(value)
938 .load::<String>(connection);
939 assert_eq!(Ok(&[][..]), result.as_ref().map(|vec| vec.as_ref()));
940 }
941
942 #[diesel_test_helper::test]
944 fn test_correct_seralization_of_owned_strings() {
945 use crate::prelude::*;
946
947 #[derive(Debug, crate::expression::AsExpression)]
948 #[diesel(sql_type = diesel::sql_types::Text)]
949 struct CustomWrapper(String);
950
951 impl crate::serialize::ToSql<Text, Sqlite> for CustomWrapper {
952 fn to_sql<'b>(
953 &'b self,
954 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
955 ) -> crate::serialize::Result {
956 out.set_value(self.0.to_string());
957 Ok(crate::serialize::IsNull::No)
958 }
959 }
960
961 let connection = &mut connection();
962
963 let res = crate::select(
964 CustomWrapper("".into())
965 .into_sql::<crate::sql_types::Text>()
966 .nullable(),
967 )
968 .get_result::<Option<String>>(connection)
969 .unwrap();
970 assert_eq!(res, Some(String::new()));
971 }
972
973 #[diesel_test_helper::test]
974 fn test_correct_seralization_of_owned_bytes() {
975 use crate::prelude::*;
976
977 #[derive(Debug, crate::expression::AsExpression)]
978 #[diesel(sql_type = diesel::sql_types::Binary)]
979 struct CustomWrapper(Vec<u8>);
980
981 impl crate::serialize::ToSql<crate::sql_types::Binary, Sqlite> for CustomWrapper {
982 fn to_sql<'b>(
983 &'b self,
984 out: &mut crate::serialize::Output<'b, '_, Sqlite>,
985 ) -> crate::serialize::Result {
986 out.set_value(self.0.clone());
987 Ok(crate::serialize::IsNull::No)
988 }
989 }
990
991 let connection = &mut connection();
992
993 let res = crate::select(
994 CustomWrapper(Vec::new())
995 .into_sql::<crate::sql_types::Binary>()
996 .nullable(),
997 )
998 .get_result::<Option<Vec<u8>>>(connection)
999 .unwrap();
1000 assert_eq!(res, Some(Vec::new()));
1001 }
1002
1003 #[diesel_test_helper::test]
1004 fn correctly_handle_empty_query() {
1005 let check_empty_query_error = |r: crate::QueryResult<usize>| {
1006 assert!(r.is_err());
1007 let err = r.unwrap_err();
1008 assert!(
1009 matches!(err, crate::result::Error::QueryBuilderError(ref b) if b.is::<crate::result::EmptyQuery>()),
1010 "Expected a query builder error, but got {err}"
1011 );
1012 };
1013 let connection = &mut SqliteConnection::establish(":memory:").unwrap();
1014 check_empty_query_error(crate::sql_query("").execute(connection));
1015 check_empty_query_error(crate::sql_query(" ").execute(connection));
1016 check_empty_query_error(crate::sql_query("\n\t").execute(connection));
1017 check_empty_query_error(crate::sql_query("-- SELECT 1;").execute(connection));
1018 }
1019}