1use std::{convert, ffi::c_void, fmt, mem, os::raw::c_char, ptr, str};
2
3use arrow::{array::StructArray, datatypes::SchemaRef};
4
5use super::{ffi, AndThenRows, Connection, Error, MappedRows, Params, RawStatement, Result, Row, Rows, ValueRef};
6#[cfg(feature = "polars")]
7use crate::{arrow2, polars_dataframe::Polars};
8use crate::{
9 arrow_batch::{Arrow, ArrowStream},
10 error::result_from_duckdb_prepare,
11 types::{TimeUnit, ToSql, ToSqlOutput},
12};
13
14pub struct Statement<'conn> {
24 conn: &'conn Connection,
25 pub(crate) stmt: RawStatement,
26}
27
28impl Statement<'_> {
29 #[inline]
71 pub fn execute<P: Params>(&mut self, params: P) -> Result<usize> {
72 params.__bind_in(self)?;
73 self.execute_with_bound_parameters()
74 }
75
76 #[inline]
90 pub fn insert<P: Params>(&mut self, params: P) -> Result<()> {
91 let changes = self.execute(params)?;
92 match changes {
93 1 => Ok(()),
94 _ => Err(Error::StatementChangedRows(changes)),
95 }
96 }
97
98 #[inline]
115 pub fn query_arrow<P: Params>(&mut self, params: P) -> Result<Arrow<'_>> {
116 self.execute(params)?;
117 Ok(Arrow::new(self))
118 }
119
120 #[inline]
138 pub fn stream_arrow<P: Params>(&mut self, params: P, schema: SchemaRef) -> Result<ArrowStream<'_>> {
139 params.__bind_in(self)?;
140 self.stmt.execute_streaming()?;
141 Ok(ArrowStream::new(self, schema))
142 }
143
144 #[cfg(feature = "polars")]
182 #[inline]
183 pub fn query_polars<P: Params>(&mut self, params: P) -> Result<Polars<'_>> {
184 self.execute(params)?;
185 Ok(Polars::new(self))
186 }
187
188 #[inline]
247 pub fn query<P: Params>(&mut self, params: P) -> Result<Rows<'_>> {
248 self.execute(params)?;
249 Ok(Rows::new(self))
250 }
251
252 pub fn query_map<T, P, F>(&mut self, params: P, f: F) -> Result<MappedRows<'_, F>>
283 where
284 P: Params,
285 F: FnMut(&Row<'_>) -> Result<T>,
286 {
287 self.query(params).map(|rows| rows.mapped(f))
288 }
289
290 #[inline]
319 pub fn query_and_then<T, E, P, F>(&mut self, params: P, f: F) -> Result<AndThenRows<'_, F>>
320 where
321 P: Params,
322 E: convert::From<Error>,
323 F: FnMut(&Row<'_>) -> Result<T, E>,
324 {
325 self.query(params).map(|rows| rows.and_then(f))
326 }
327
328 #[inline]
331 pub fn exists<P: Params>(&mut self, params: P) -> Result<bool> {
332 let mut rows = self.query(params)?;
333 let exists = rows.next()?.is_some();
334 Ok(exists)
335 }
336
337 pub fn query_row<T, P, F>(&mut self, params: P, f: F) -> Result<T>
353 where
354 P: Params,
355 F: FnOnce(&Row<'_>) -> Result<T>,
356 {
357 self.query(params)?.get_expected_row().and_then(f)
358 }
359
360 pub fn query_one<T, P, F>(&mut self, params: P, f: F) -> Result<T>
375 where
376 P: Params,
377 F: FnOnce(&Row<'_>) -> Result<T>,
378 {
379 let mut rows = self.query(params)?;
380 let row = rows.get_expected_row().and_then(f)?;
381 if rows.next()?.is_some() {
382 return Err(Error::QueryReturnedMoreThanOneRow);
383 }
384 Ok(row)
385 }
386
387 #[inline]
389 pub fn row_count(&self) -> usize {
390 self.stmt.row_count()
391 }
392
393 #[inline]
395 pub fn step(&self) -> Option<StructArray> {
396 self.stmt.step()
397 }
398
399 #[inline]
401 pub fn stream_step(&self, schema: SchemaRef) -> Option<StructArray> {
402 self.stmt.streaming_step(schema)
403 }
404
405 #[cfg(feature = "polars")]
406 #[inline]
408 pub fn step2(&self) -> Option<arrow2::array::StructArray> {
409 self.stmt.step2()
410 }
411
412 #[inline]
413 pub(crate) fn bind_parameters<P>(&mut self, params: P) -> Result<()>
414 where
415 P: IntoIterator,
416 P::Item: ToSql,
417 {
418 let expected = self.stmt.bind_parameter_count();
419 let mut index = 0;
420 for p in params.into_iter() {
421 index += 1; if index > expected {
423 break;
424 }
425 self.bind_parameter(&p, index)?;
426 }
427 if index != expected {
428 Err(Error::InvalidParameterCount(index, expected))
429 } else {
430 Ok(())
431 }
432 }
433
434 #[inline]
436 pub fn parameter_count(&self) -> usize {
437 self.stmt.bind_parameter_count()
438 }
439
440 #[inline]
469 pub fn parameter_name(&self, idx: usize) -> Result<String> {
470 self.stmt.parameter_name(idx)
471 }
472
473 #[inline]
511 pub fn raw_bind_parameter<T: ToSql>(&mut self, one_based_col_index: usize, param: T) -> Result<()> {
512 self.bind_parameter(¶m, one_based_col_index)
515 }
516
517 #[inline]
532 pub fn raw_execute(&mut self) -> Result<usize> {
533 self.execute_with_bound_parameters()
534 }
535
536 #[inline]
549 pub fn raw_query(&self) -> Rows<'_> {
550 Rows::new(self)
551 }
552
553 #[inline]
558 pub fn schema(&self) -> SchemaRef {
559 self.stmt.schema()
560 }
561
562 fn bind_parameter<P: ?Sized + ToSql>(&self, param: &P, col: usize) -> Result<()> {
564 let value = param.to_sql()?;
565
566 let ptr = unsafe { self.stmt.ptr() };
567 let value = match value {
568 ToSqlOutput::Borrowed(v) => v,
569 ToSqlOutput::Owned(ref v) => ValueRef::from(v),
570 };
571 let rc = match value {
573 ValueRef::Null => unsafe { ffi::duckdb_bind_null(ptr, col as u64) },
574 ValueRef::Boolean(i) => unsafe { ffi::duckdb_bind_boolean(ptr, col as u64, i) },
575 ValueRef::TinyInt(i) => unsafe { ffi::duckdb_bind_int8(ptr, col as u64, i) },
576 ValueRef::SmallInt(i) => unsafe { ffi::duckdb_bind_int16(ptr, col as u64, i) },
577 ValueRef::Int(i) => unsafe { ffi::duckdb_bind_int32(ptr, col as u64, i) },
578 ValueRef::BigInt(i) => unsafe { ffi::duckdb_bind_int64(ptr, col as u64, i) },
579 ValueRef::HugeInt(i) => unsafe {
580 let hi = ffi::duckdb_hugeint {
581 lower: i as u64,
582 upper: (i >> 64) as i64,
583 };
584 ffi::duckdb_bind_hugeint(ptr, col as u64, hi)
585 },
586 ValueRef::UTinyInt(i) => unsafe { ffi::duckdb_bind_uint8(ptr, col as u64, i) },
587 ValueRef::USmallInt(i) => unsafe { ffi::duckdb_bind_uint16(ptr, col as u64, i) },
588 ValueRef::UInt(i) => unsafe { ffi::duckdb_bind_uint32(ptr, col as u64, i) },
589 ValueRef::UBigInt(i) => unsafe { ffi::duckdb_bind_uint64(ptr, col as u64, i) },
590 ValueRef::Float(r) => unsafe { ffi::duckdb_bind_float(ptr, col as u64, r) },
591 ValueRef::Double(r) => unsafe { ffi::duckdb_bind_double(ptr, col as u64, r) },
592 ValueRef::Text(s) => unsafe {
593 ffi::duckdb_bind_varchar_length(ptr, col as u64, s.as_ptr() as *const c_char, s.len() as u64)
594 },
595 ValueRef::Blob(b) => unsafe {
596 ffi::duckdb_bind_blob(ptr, col as u64, b.as_ptr() as *const c_void, b.len() as u64)
597 },
598 ValueRef::Timestamp(u, i) => unsafe {
599 let micros = match u {
600 TimeUnit::Second => i * 1_000_000,
601 TimeUnit::Millisecond => i * 1_000,
602 TimeUnit::Microsecond => i,
603 TimeUnit::Nanosecond => i / 1_000,
604 };
605 ffi::duckdb_bind_timestamp(ptr, col as u64, ffi::duckdb_timestamp { micros })
606 },
607 ValueRef::Interval { months, days, nanos } => unsafe {
608 let micros = nanos / 1_000;
609 ffi::duckdb_bind_interval(ptr, col as u64, ffi::duckdb_interval { months, days, micros })
610 },
611 _ => unreachable!("not supported: {}", value.data_type()),
612 };
613 result_from_duckdb_prepare(rc, ptr)
614 }
615
616 #[inline]
617 fn execute_with_bound_parameters(&mut self) -> Result<usize> {
618 self.stmt.execute()
619 }
620
621 #[inline]
625 pub(crate) unsafe fn into_raw(mut self) -> RawStatement {
626 let mut stmt = RawStatement::new(ptr::null_mut());
627 mem::swap(&mut stmt, &mut self.stmt);
628 stmt
629 }
630}
631
632impl fmt::Debug for Statement<'_> {
633 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
634 let sql = if self.stmt.is_null() {
635 Ok("")
636 } else {
637 str::from_utf8(self.stmt.sql().unwrap().to_bytes())
638 };
639 f.debug_struct("Statement")
640 .field("conn", self.conn)
641 .field("stmt", &self.stmt)
642 .field("sql", &sql)
643 .finish()
644 }
645}
646
647impl Statement<'_> {
648 #[inline]
649 pub(super) fn new(conn: &Connection, stmt: RawStatement) -> Statement<'_> {
650 Statement { conn, stmt }
651 }
652}
653
654#[cfg(test)]
655mod test {
656 use crate::{params_from_iter, types::ToSql, Connection, Error, Result};
657
658 #[test]
659 fn test_execute() -> Result<()> {
660 let db = Connection::open_in_memory()?;
661 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
662
663 assert_eq!(db.execute("INSERT INTO foo(x) VALUES (?)", [&2i32])?, 1);
664 assert_eq!(db.execute("INSERT INTO foo(x) VALUES (?)", [&3i32])?, 1);
665
666 assert_eq!(
668 5i32,
669 db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo WHERE x > ?", [&0i32], |r| r.get(0))?
670 );
671 assert_eq!(
672 3i32,
673 db.query_row::<i32, _, _>("SELECT SUM(x) FROM foo WHERE x > ?", [&2i32], |r| r.get(0))?
674 );
675 Ok(())
676 }
677
678 #[test]
679 fn test_stmt_execute() -> Result<()> {
680 let db = Connection::open_in_memory()?;
681 let sql = r#"
682 CREATE SEQUENCE seq;
683 CREATE TABLE test (id INTEGER DEFAULT NEXTVAL('seq'), name TEXT NOT NULL, flag INTEGER);
684 "#;
685 db.execute_batch(sql)?;
686
687 let mut stmt = db.prepare("INSERT INTO test (name) VALUES (?)")?;
688 stmt.execute([&"one"])?;
689
690 let mut stmt = db.prepare("SELECT COUNT(*) FROM test WHERE name = ?")?;
691 assert_eq!(1i32, stmt.query_row::<i32, _, _>([&"one"], |r| r.get(0))?);
692 Ok(())
693 }
694
695 #[test]
696 fn test_query() -> Result<()> {
697 let db = Connection::open_in_memory()?;
698 let sql = r#"
699 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
700 INSERT INTO test(id, name) VALUES (1, 'one');
701 "#;
702 db.execute_batch(sql)?;
703
704 let mut stmt = db.prepare("SELECT id FROM test where name = ?")?;
705 {
706 let id: i32 = stmt.query_one([&"one"], |r| r.get(0))?;
707 assert_eq!(id, 1);
708 }
709 Ok(())
710 }
711
712 #[test]
713 fn test_query_and_then() -> Result<()> {
714 let db = Connection::open_in_memory()?;
715 let sql = r#"
716 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
717 INSERT INTO test(id, name) VALUES (1, 'one');
718 INSERT INTO test(id, name) VALUES (2, 'one');
719 "#;
720 db.execute_batch(sql)?;
721
722 let mut stmt = db.prepare("SELECT id FROM test where name = ? ORDER BY id ASC")?;
723 let mut rows = stmt.query_and_then([&"one"], |row| {
724 let id: i32 = row.get(0)?;
725 if id == 1 {
726 Ok(id)
727 } else {
728 Err(Error::ExecuteReturnedResults)
729 }
730 })?;
731
732 let doubled_id: i32 = rows.next().unwrap()?;
734 assert_eq!(1, doubled_id);
735
736 #[allow(clippy::match_wild_err_arm)]
738 match rows.next().unwrap() {
739 Ok(_) => panic!("invalid Ok"),
740 Err(Error::ExecuteReturnedResults) => (),
741 Err(_) => panic!("invalid Err"),
742 }
743 Ok(())
744 }
745
746 #[test]
747 fn test_unbound_parameters_are_error() -> Result<()> {
748 let db = Connection::open_in_memory()?;
749 let sql = "CREATE TABLE test (x TEXT, y TEXT)";
750 db.execute_batch(sql)?;
751
752 let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (?, ?)")?;
753 assert!(stmt.execute([&"one"]).is_err());
754 Ok(())
755 }
756
757 #[test]
758 fn test_insert_empty_text_is_none() -> Result<()> {
759 let db = Connection::open_in_memory()?;
760 let sql = "CREATE TABLE test (x TEXT, y TEXT)";
761 db.execute_batch(sql)?;
762
763 let mut stmt = db.prepare("INSERT INTO test (x) VALUES (?)")?;
764 stmt.execute([&"one"])?;
765
766 let result: Option<String> = db.query_row("SELECT y FROM test WHERE x = 'one'", [], |row| row.get(0))?;
767 assert!(result.is_none());
768 Ok(())
769 }
770
771 #[test]
772 fn test_raw_binding() -> Result<()> {
773 let db = Connection::open_in_memory()?;
774 db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?;
775 {
776 let mut stmt = db.prepare("INSERT INTO test (name, value) VALUES (?, ?)")?;
777
778 stmt.raw_bind_parameter(2, 50i32)?;
779 stmt.raw_bind_parameter(1, "example")?;
780 let n = stmt.raw_execute()?;
781 assert_eq!(n, 1);
782 }
783
784 {
785 let mut stmt = db.prepare("SELECT name, value FROM test WHERE value = ?")?;
786 stmt.raw_bind_parameter(1, 50)?;
787 stmt.raw_execute()?;
788 let mut rows = stmt.raw_query();
789 {
790 let row = rows.next()?.unwrap();
791 let name: String = row.get(0)?;
792 assert_eq!(name, "example");
793 let value: i32 = row.get(1)?;
794 assert_eq!(value, 50);
795 }
796 assert!(rows.next()?.is_none());
797 }
798
799 {
800 let db = Connection::open_in_memory()?;
801 db.execute_batch("CREATE TABLE test (name TEXT, value UINTEGER)")?;
802 let mut stmt = db.prepare("INSERT INTO test(name, value) VALUES (?, ?)")?;
803 stmt.raw_bind_parameter(1, "negative")?;
804 stmt.raw_bind_parameter(2, u32::MAX)?;
805 let n = stmt.raw_execute()?;
806 assert_eq!(n, 1);
807 assert_eq!(
808 u32::MAX,
809 db.query_row::<u32, _, _>("SELECT value FROM test", [], |r| r.get(0))?
810 );
811 }
812
813 {
814 let db = Connection::open_in_memory()?;
815 db.execute_batch("CREATE TABLE test (name TEXT, value UBIGINT)")?;
816 let mut stmt = db.prepare("INSERT INTO test(name, value) VALUES (?, ?)")?;
817 stmt.raw_bind_parameter(1, "negative")?;
818 stmt.raw_bind_parameter(2, u64::MAX)?;
819 let n = stmt.raw_execute()?;
820 assert_eq!(n, 1);
821 assert_eq!(
822 u64::MAX,
823 db.query_row::<u64, _, _>("SELECT value FROM test", [], |r| r.get(0))?
824 );
825 }
826
827 Ok(())
828 }
829
830 #[test]
831 #[cfg_attr(windows, ignore = "Windows doesn't allow concurrent writes to a file")]
832 fn test_insert_duplicate() -> Result<()> {
833 let db = Connection::open_in_memory()?;
834 db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)")?;
835 let mut stmt = db.prepare("INSERT INTO foo (x) VALUES (?)")?;
836 stmt.insert([1i32])?;
838 stmt.insert([2i32])?;
839 assert!(stmt.insert([1i32]).is_err());
840 let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")?;
841 match multi.insert([]).unwrap_err() {
842 Error::StatementChangedRows(2) => (),
843 err => panic!("Unexpected error {err}"),
844 }
845 Ok(())
846 }
847
848 #[test]
849 fn test_insert_different_tables() -> Result<()> {
850 let db = Connection::open_in_memory()?;
852 db.execute_batch(
853 r"
854 CREATE TABLE foo(x INTEGER);
855 CREATE TABLE bar(x INTEGER);
856 ",
857 )?;
858
859 db.prepare("INSERT INTO foo VALUES (10)")?.insert([])?;
860 db.prepare("INSERT INTO bar VALUES (10)")?.insert([])?;
861 Ok(())
862 }
863
864 #[test]
868 fn test_insert_with_returning_clause() -> Result<()> {
869 let db = Connection::open_in_memory()?;
870 db.execute_batch(
871 "CREATE SEQUENCE location_id_seq START WITH 1 INCREMENT BY 1;
872 CREATE TABLE location (
873 id INTEGER PRIMARY KEY DEFAULT nextval('location_id_seq'),
874 name TEXT NOT NULL
875 )",
876 )?;
877
878 let changes = db.execute("INSERT INTO location (name) VALUES (?)", ["test1"])?;
880 assert_eq!(changes, 1);
881
882 let changes = db.execute("INSERT INTO location (name) VALUES (?) RETURNING id", ["test2"])?;
884 assert_eq!(changes, 0);
885
886 let count: i64 = db.query_row("SELECT COUNT(*) FROM location", [], |r| r.get(0))?;
888 assert_eq!(count, 2);
889
890 let mut stmt = db.prepare("INSERT INTO location (name) VALUES (?)")?;
892 stmt.insert(["test3"])?;
893
894 let mut stmt = db.prepare("INSERT INTO location (name) VALUES (?) RETURNING id")?;
896 let result = stmt.insert(["test4"]);
897 assert!(matches!(result, Err(Error::StatementChangedRows(0))));
898
899 let count: i64 = db.query_row("SELECT COUNT(*) FROM location", [], |r| r.get(0))?;
901 assert_eq!(count, 4);
902
903 let id: i64 = db.query_row("INSERT INTO location (name) VALUES (?) RETURNING id", ["test5"], |r| {
905 r.get(0)
906 })?;
907 assert_eq!(id, 5);
908
909 let mut stmt = db.prepare("INSERT INTO location (name) VALUES (?) RETURNING id")?;
911 let ids: Vec<i64> = stmt
912 .query_map(["test6"], |row| row.get(0))?
913 .collect::<Result<Vec<_>>>()?;
914 assert_eq!(ids.len(), 1);
915 assert_eq!(ids[0], 6);
916
917 let id: i64 = db
919 .prepare("INSERT INTO location (name) VALUES (?) RETURNING id")?
920 .query_one(["test7"], |r| r.get(0))?;
921 assert_eq!(id, 7);
922
923 let (id, name): (i64, String) = db.query_row(
925 "INSERT INTO location (name) VALUES (?) RETURNING id, name",
926 ["test8"],
927 |r| Ok((r.get(0)?, r.get(1)?)),
928 )?;
929 assert_eq!(id, 8);
930 assert_eq!(name, "test8");
931
932 Ok(())
933 }
934
935 #[test]
936 fn test_exists() -> Result<()> {
937 let db = Connection::open_in_memory()?;
938 let sql = "BEGIN;
939 CREATE TABLE foo(x INTEGER);
940 INSERT INTO foo VALUES(1);
941 INSERT INTO foo VALUES(2);
942 END;";
943 db.execute_batch(sql)?;
944 let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?")?;
945 assert!(stmt.exists([1i32])?);
946 assert!(stmt.exists([2i32])?);
947 assert!(!stmt.exists([0i32])?);
948 Ok(())
949 }
950
951 #[test]
952 fn test_query_row() -> Result<()> {
953 let db = Connection::open_in_memory()?;
954 let sql = "BEGIN;
955 CREATE TABLE foo(x INTEGER, y INTEGER);
956 INSERT INTO foo VALUES(1, 3);
957 INSERT INTO foo VALUES(2, 4);
958 END;";
959 db.execute_batch(sql)?;
960 let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?")?;
961 let y: Result<i32> = stmt.query_row([1i32], |r| r.get(0));
962 assert_eq!(3i32, y?);
963 Ok(())
964 }
965
966 #[test]
967 fn test_query_one() -> Result<()> {
968 let db = Connection::open_in_memory()?;
969 let sql = "BEGIN;
970 CREATE TABLE foo(x INTEGER, y INTEGER);
971 INSERT INTO foo VALUES(1, 3);
972 INSERT INTO foo VALUES(2, 4);
973 END;";
974 db.execute_batch(sql)?;
975
976 let y: i32 = db
978 .prepare("SELECT y FROM foo WHERE x = ?")?
979 .query_one([1], |r| r.get(0))?;
980 assert_eq!(y, 3);
981
982 let res: Result<i32> = db
984 .prepare("SELECT y FROM foo WHERE x = ?")?
985 .query_one([99], |r| r.get(0));
986 assert_eq!(res.unwrap_err(), Error::QueryReturnedNoRows);
987
988 let res: Result<i32> = db.prepare("SELECT y FROM foo")?.query_one([], |r| r.get(0));
990 assert_eq!(res.unwrap_err(), Error::QueryReturnedMoreThanOneRow);
991
992 Ok(())
993 }
994
995 #[test]
996 fn test_query_one_optional() -> Result<()> {
997 use crate::OptionalExt;
998
999 let db = Connection::open_in_memory()?;
1000 let sql = "BEGIN;
1001 CREATE TABLE foo(x INTEGER, y INTEGER);
1002 INSERT INTO foo VALUES(1, 3);
1003 INSERT INTO foo VALUES(2, 4);
1004 END;";
1005 db.execute_batch(sql)?;
1006
1007 let y: Option<i32> = db
1009 .prepare("SELECT y FROM foo WHERE x = ?")?
1010 .query_one([1], |r| r.get(0))
1011 .optional()?;
1012 assert_eq!(y, Some(3));
1013
1014 let y: Option<i32> = db
1016 .prepare("SELECT y FROM foo WHERE x = ?")?
1017 .query_one([99], |r| r.get(0))
1018 .optional()?;
1019 assert_eq!(y, None);
1020
1021 let res = db
1023 .prepare("SELECT y FROM foo")?
1024 .query_one([], |r| r.get::<_, i32>(0))
1025 .optional();
1026 assert_eq!(res.unwrap_err(), Error::QueryReturnedMoreThanOneRow);
1027
1028 Ok(())
1029 }
1030
1031 #[test]
1032 fn test_query_by_column_name() -> Result<()> {
1033 let db = Connection::open_in_memory()?;
1034 let sql = "BEGIN;
1035 CREATE TABLE foo(x INTEGER, y INTEGER);
1036 INSERT INTO foo VALUES(1, 3);
1037 END;";
1038 db.execute_batch(sql)?;
1039 let mut stmt = db.prepare("SELECT y FROM foo")?;
1040 let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
1041 assert_eq!(3i64, y?);
1042 Ok(())
1043 }
1044
1045 #[test]
1046 fn test_get_schema_of_executed_result() -> Result<()> {
1047 use arrow::datatypes::{DataType, Field, Schema};
1048 let db = Connection::open_in_memory()?;
1049 let sql = "BEGIN;
1050 CREATE TABLE foo(x STRING, y INTEGER);
1051 INSERT INTO foo VALUES('hello', 3);
1052 END;";
1053 db.execute_batch(sql)?;
1054 let mut stmt = db.prepare("SELECT x, y FROM foo")?;
1055 let _ = stmt.execute([]);
1056 let schema = stmt.schema();
1057 assert_eq!(
1058 *schema,
1059 Schema::new(vec![
1060 Field::new("x", DataType::Utf8, true),
1061 Field::new("y", DataType::Int32, true)
1062 ])
1063 );
1064 Ok(())
1065 }
1066
1067 #[test]
1068 #[should_panic(expected = "called `Option::unwrap()` on a `None` value")]
1069 fn test_unexecuted_schema_panics() {
1070 let db = Connection::open_in_memory().unwrap();
1071 let sql = "BEGIN;
1072 CREATE TABLE foo(x STRING, y INTEGER);
1073 INSERT INTO foo VALUES('hello', 3);
1074 END;";
1075 db.execute_batch(sql).unwrap();
1076 let stmt = db.prepare("SELECT x, y FROM foo").unwrap();
1077 let _ = stmt.schema();
1078 }
1079
1080 #[test]
1081 fn test_query_by_column_name_ignore_case() -> Result<()> {
1082 let db = Connection::open_in_memory()?;
1083 let sql = "BEGIN;
1084 CREATE TABLE foo(x INTEGER, y INTEGER);
1085 INSERT INTO foo VALUES(1, 3);
1086 END;";
1087 db.execute_batch(sql)?;
1088 let mut stmt = db.prepare("SELECT y as Y FROM foo")?;
1089 let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
1090 assert_eq!(3i64, y?);
1091 Ok(())
1092 }
1093
1094 #[test]
1095 fn test_bind_parameters() -> Result<()> {
1096 let db = Connection::open_in_memory()?;
1097 db.query_row("SELECT ?1, ?2, ?3", [&1u8 as &dyn ToSql, &"one", &Some("one")], |row| {
1099 row.get::<_, u8>(0)
1100 })?;
1101 let data = vec![1, 2, 3];
1103 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| row.get::<_, u8>(0))?;
1104 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data.as_slice()), |row| {
1105 row.get::<_, u8>(0)
1106 })?;
1107 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data), |row| row.get::<_, u8>(0))?;
1108
1109 let data: std::collections::BTreeSet<String> =
1110 ["one", "two", "three"].iter().map(|s| (*s).to_string()).collect();
1111 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1112 row.get::<_, String>(0)
1113 })?;
1114
1115 let data = [0; 3];
1116 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| row.get::<_, u8>(0))?;
1117 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data.iter()), |row| {
1118 row.get::<_, u8>(0)
1119 })?;
1120 Ok(())
1121 }
1122
1123 #[test]
1124 fn test_empty_stmt() -> Result<()> {
1125 let conn = Connection::open_in_memory()?;
1126 let stmt = conn.prepare("");
1127 assert!(stmt.is_err());
1128
1129 Ok(())
1130 }
1131
1132 #[test]
1133 fn test_comment_empty_stmt() -> Result<()> {
1134 let conn = Connection::open_in_memory()?;
1135 assert!(conn.prepare("/*SELECT 1;*/").is_err());
1136 Ok(())
1137 }
1138
1139 #[test]
1140 fn test_comment_and_sql_stmt() -> Result<()> {
1141 let conn = Connection::open_in_memory()?;
1142 let mut stmt = conn.prepare("/*...*/ SELECT 1;")?;
1143 stmt.execute([])?;
1144 assert_eq!(1, stmt.column_count());
1145 Ok(())
1146 }
1147
1148 #[test]
1149 fn test_nul_byte() -> Result<()> {
1150 let db = Connection::open_in_memory()?;
1151 let expected = "a\x00b";
1152 let actual: String = db.query_row("SELECT CAST(? AS VARCHAR)", [expected], |row| row.get(0))?;
1153 assert_eq!(expected, actual);
1154 Ok(())
1155 }
1156
1157 #[test]
1158 fn test_parameter_name() -> Result<()> {
1159 let db = Connection::open_in_memory()?;
1160
1161 {
1162 let stmt = db.prepare("SELECT $foo, $bar")?;
1163
1164 assert_eq!(stmt.parameter_count(), 2);
1165 assert_eq!(stmt.parameter_name(1)?, "foo");
1166 assert_eq!(stmt.parameter_name(2)?, "bar");
1167
1168 assert!(matches!(stmt.parameter_name(0), Err(Error::InvalidParameterIndex(0))));
1169 assert!(matches!(
1170 stmt.parameter_name(100),
1171 Err(Error::InvalidParameterIndex(100))
1172 ));
1173 }
1174
1175 {
1177 let stmt = db.prepare("SELECT ?, ?")?;
1178 assert_eq!(stmt.parameter_count(), 2);
1179 assert_eq!(stmt.parameter_name(1)?, "1");
1180 assert_eq!(stmt.parameter_name(2)?, "2");
1181 }
1182
1183 {
1185 let stmt = db.prepare("SELECT ?1, ?2")?;
1186 assert_eq!(stmt.parameter_count(), 2);
1187 assert_eq!(stmt.parameter_name(1)?, "1");
1188 assert_eq!(stmt.parameter_name(2)?, "2");
1189 }
1190
1191 Ok(())
1192 }
1193
1194 #[test]
1195 fn test_bind_named_parameters_manually() -> Result<()> {
1196 use std::collections::HashMap;
1197
1198 let db = Connection::open_in_memory()?;
1199 let mut stmt = db.prepare("SELECT $foo > $bar")?;
1200
1201 let mut params: HashMap<String, i32> = HashMap::new();
1202 params.insert("foo".to_string(), 42);
1203 params.insert("bar".to_string(), 23);
1204
1205 for idx in 1..=stmt.parameter_count() {
1206 let name = stmt.parameter_name(idx)?;
1207 if let Some(value) = params.get(&name) {
1208 stmt.raw_bind_parameter(idx, value)?;
1209 }
1210 }
1211
1212 stmt.raw_execute()?;
1213
1214 let mut rows = stmt.raw_query();
1215 let row = rows.next()?.unwrap();
1216 let result: bool = row.get(0)?;
1217 assert!(result);
1218
1219 Ok(())
1220 }
1221}