rusqlite/statement.rs
1use std::ffi::{c_int, c_void};
2use std::{fmt, mem, ptr, str};
3
4use super::ffi::{self, sqlite3_stmt};
5use super::str_for_sqlite;
6use super::{
7 AndThenRows, Connection, Error, MappedRows, Params, RawStatement, Result, Row, Rows, ValueRef,
8};
9use crate::bind::BindIndex;
10use crate::types::{ToSql, ToSqlOutput, Value};
11use crate::util::from_raw_parts;
12
13/// A prepared statement.
14pub struct Statement<'conn> {
15 pub(crate) conn: &'conn Connection,
16 pub(crate) stmt: RawStatement,
17}
18
19impl Statement<'_> {
20 /// Execute the prepared statement.
21 ///
22 /// On success, returns the number of rows that were changed or inserted or
23 /// deleted (via `sqlite3_changes`).
24 ///
25 /// ## Example
26 ///
27 /// ### Use with positional parameters
28 ///
29 /// ```rust,no_run
30 /// # use rusqlite::{Connection, Result, params};
31 /// fn update_rows(conn: &Connection) -> Result<()> {
32 /// let mut stmt = conn.prepare("UPDATE foo SET bar = ?1 WHERE qux = ?2")?;
33 /// // For a single parameter, or a parameter where all the values have
34 /// // the same type, just passing an array is simplest.
35 /// stmt.execute([2i32])?;
36 /// // The `rusqlite::params!` macro is mostly useful when the parameters do not
37 /// // all have the same type, or if there are more than 32 parameters
38 /// // at once, but it can be used in other cases.
39 /// stmt.execute(params![1i32])?;
40 /// // However, it's not required, many cases are fine as:
41 /// stmt.execute(&[&2i32])?;
42 /// // Or even:
43 /// stmt.execute([2i32])?;
44 /// // If you really want to, this is an option as well.
45 /// stmt.execute((2i32,))?;
46 /// Ok(())
47 /// }
48 /// ```
49 ///
50 /// #### Heterogeneous positional parameters
51 ///
52 /// ```
53 /// use rusqlite::{Connection, Result};
54 /// fn store_file(conn: &Connection, path: &str, data: &[u8]) -> Result<()> {
55 /// # // no need to do it for real.
56 /// # fn sha256(_: &[u8]) -> [u8; 32] { [0; 32] }
57 /// let query = "INSERT OR REPLACE INTO files(path, hash, data) VALUES (?1, ?2, ?3)";
58 /// let mut stmt = conn.prepare_cached(query)?;
59 /// let hash: [u8; 32] = sha256(data);
60 /// // The easiest way to pass positional parameters of have several
61 /// // different types is by using a tuple.
62 /// stmt.execute((path, hash, data))?;
63 /// // Using the `params!` macro also works, and supports longer parameter lists:
64 /// stmt.execute(rusqlite::params![path, hash, data])?;
65 /// Ok(())
66 /// }
67 /// # let c = Connection::open_in_memory().unwrap();
68 /// # c.execute_batch("CREATE TABLE files(path TEXT PRIMARY KEY, hash BLOB, data BLOB)").unwrap();
69 /// # store_file(&c, "foo/bar.txt", b"bibble").unwrap();
70 /// # store_file(&c, "foo/baz.txt", b"bobble").unwrap();
71 /// ```
72 ///
73 /// ### Use with named parameters
74 ///
75 /// ```rust,no_run
76 /// # use rusqlite::{Connection, Result, named_params};
77 /// fn insert(conn: &Connection) -> Result<()> {
78 /// let mut stmt = conn.prepare("INSERT INTO test (key, value) VALUES (:key, :value)")?;
79 /// // The `rusqlite::named_params!` macro (like `params!`) is useful for heterogeneous
80 /// // sets of parameters (where all parameters are not the same type), or for queries
81 /// // with many (more than 32) statically known parameters.
82 /// stmt.execute(named_params! { ":key": "one", ":val": 2 })?;
83 /// // However, named parameters can also be passed like:
84 /// stmt.execute(&[(":key", "three"), (":val", "four")])?;
85 /// // Or even: (note that a &T is required for the value type, currently)
86 /// stmt.execute(&[(":key", &100), (":val", &200)])?;
87 /// Ok(())
88 /// }
89 /// ```
90 ///
91 /// ### Use without parameters
92 ///
93 /// ```rust,no_run
94 /// # use rusqlite::{Connection, Result, params};
95 /// fn delete_all(conn: &Connection) -> Result<()> {
96 /// let mut stmt = conn.prepare("DELETE FROM users")?;
97 /// stmt.execute([])?;
98 /// Ok(())
99 /// }
100 /// ```
101 ///
102 /// # Failure
103 ///
104 /// Will return `Err` if binding parameters fails, the executed statement
105 /// returns rows (in which case `query` should be used instead), or the
106 /// underlying SQLite call fails.
107 #[inline]
108 pub fn execute<P: Params>(&mut self, params: P) -> Result<usize> {
109 params.__bind_in(self)?;
110 self.execute_with_bound_parameters()
111 }
112
113 /// Execute an INSERT and return the ROWID.
114 ///
115 /// # Note
116 ///
117 /// This function is a convenience wrapper around
118 /// [`execute()`](Statement::execute) intended for queries that insert a
119 /// single item. It is possible to misuse this function in a way that it
120 /// cannot detect, such as by calling it on a statement which _updates_
121 /// a single item rather than inserting one. Please don't do that.
122 ///
123 /// # Failure
124 ///
125 /// Will return `Err` if no row is inserted or many rows are inserted.
126 #[inline]
127 pub fn insert<P: Params>(&mut self, params: P) -> Result<i64> {
128 let changes = self.execute(params)?;
129 match changes {
130 1 => Ok(self.conn.last_insert_rowid()),
131 _ => Err(Error::StatementChangedRows(changes)),
132 }
133 }
134
135 /// Execute the prepared statement, returning a handle to the resulting
136 /// rows.
137 ///
138 /// Due to lifetime restrictions, the rows handle returned by `query` does
139 /// not implement the `Iterator` trait. Consider using
140 /// [`query_map`](Statement::query_map) or
141 /// [`query_and_then`](Statement::query_and_then) instead, which do.
142 ///
143 /// ## Example
144 ///
145 /// ### Use without parameters
146 ///
147 /// ```rust,no_run
148 /// # use rusqlite::{Connection, Result};
149 /// fn get_names(conn: &Connection) -> Result<Vec<String>> {
150 /// let mut stmt = conn.prepare("SELECT name FROM people")?;
151 /// let mut rows = stmt.query([])?;
152 ///
153 /// let mut names = Vec::new();
154 /// while let Some(row) = rows.next()? {
155 /// names.push(row.get(0)?);
156 /// }
157 ///
158 /// Ok(names)
159 /// }
160 /// ```
161 ///
162 /// ### Use with positional parameters
163 ///
164 /// ```rust,no_run
165 /// # use rusqlite::{Connection, Result};
166 /// fn query(conn: &Connection, name: &str) -> Result<()> {
167 /// let mut stmt = conn.prepare("SELECT * FROM test where name = ?1")?;
168 /// let mut rows = stmt.query(rusqlite::params![name])?;
169 /// while let Some(row) = rows.next()? {
170 /// // ...
171 /// }
172 /// Ok(())
173 /// }
174 /// ```
175 ///
176 /// Or, equivalently (but without the [`crate::params!`] macro).
177 ///
178 /// ```rust,no_run
179 /// # use rusqlite::{Connection, Result};
180 /// fn query(conn: &Connection, name: &str) -> Result<()> {
181 /// let mut stmt = conn.prepare("SELECT * FROM test where name = ?1")?;
182 /// let mut rows = stmt.query([name])?;
183 /// while let Some(row) = rows.next()? {
184 /// // ...
185 /// }
186 /// Ok(())
187 /// }
188 /// ```
189 ///
190 /// ### Use with named parameters
191 ///
192 /// ```rust,no_run
193 /// # use rusqlite::{Connection, Result};
194 /// fn query(conn: &Connection) -> Result<()> {
195 /// let mut stmt = conn.prepare("SELECT * FROM test where name = :name")?;
196 /// let mut rows = stmt.query(&[(":name", "one")])?;
197 /// while let Some(row) = rows.next()? {
198 /// // ...
199 /// }
200 /// Ok(())
201 /// }
202 /// ```
203 ///
204 /// Note, the `named_params!` macro is provided for syntactic convenience,
205 /// and so the above example could also be written as:
206 ///
207 /// ```rust,no_run
208 /// # use rusqlite::{Connection, Result, named_params};
209 /// fn query(conn: &Connection) -> Result<()> {
210 /// let mut stmt = conn.prepare("SELECT * FROM test where name = :name")?;
211 /// let mut rows = stmt.query(named_params! { ":name": "one" })?;
212 /// while let Some(row) = rows.next()? {
213 /// // ...
214 /// }
215 /// Ok(())
216 /// }
217 /// ```
218 ///
219 /// ## Failure
220 ///
221 /// Will return `Err` if binding parameters fails.
222 #[inline]
223 pub fn query<P: Params>(&mut self, params: P) -> Result<Rows<'_>> {
224 params.__bind_in(self)?;
225 Ok(Rows::new(self))
226 }
227
228 /// Executes the prepared statement and maps a function over the resulting
229 /// rows, returning an iterator over the mapped function results.
230 ///
231 /// `f` is used to transform the _streaming_ iterator into a _standard_
232 /// iterator.
233 ///
234 /// This is equivalent to `stmt.query(params)?.mapped(f)`.
235 ///
236 /// ## Example
237 ///
238 /// ### Use with positional params
239 ///
240 /// ```rust,no_run
241 /// # use rusqlite::{Connection, Result};
242 /// fn get_names(conn: &Connection) -> Result<Vec<String>> {
243 /// let mut stmt = conn.prepare("SELECT name FROM people")?;
244 /// let rows = stmt.query_map([], |row| row.get(0))?;
245 ///
246 /// let mut names = Vec::new();
247 /// for name_result in rows {
248 /// names.push(name_result?);
249 /// }
250 ///
251 /// Ok(names)
252 /// }
253 /// ```
254 ///
255 /// ### Use with named params
256 ///
257 /// ```rust,no_run
258 /// # use rusqlite::{Connection, Result};
259 /// fn get_names(conn: &Connection) -> Result<Vec<String>> {
260 /// let mut stmt = conn.prepare("SELECT name FROM people WHERE id = :id")?;
261 /// let rows = stmt.query_map(&[(":id", &"one")], |row| row.get(0))?;
262 ///
263 /// let mut names = Vec::new();
264 /// for name_result in rows {
265 /// names.push(name_result?);
266 /// }
267 ///
268 /// Ok(names)
269 /// }
270 /// ```
271 /// ## Failure
272 ///
273 /// Will return `Err` if binding parameters fails.
274 pub fn query_map<T, P, F>(&mut self, params: P, f: F) -> Result<MappedRows<'_, F>>
275 where
276 P: Params,
277 F: FnMut(&Row<'_>) -> Result<T>,
278 {
279 self.query(params).map(|rows| rows.mapped(f))
280 }
281
282 /// Executes the prepared statement and maps a function over the resulting
283 /// rows, where the function returns a `Result` with `Error` type
284 /// implementing `std::convert::From<Error>` (so errors can be unified).
285 ///
286 /// This is equivalent to `stmt.query(params)?.and_then(f)`.
287 ///
288 /// ## Example
289 ///
290 /// ### Use with named params
291 ///
292 /// ```rust,no_run
293 /// # use rusqlite::{Connection, Result};
294 /// struct Person {
295 /// name: String,
296 /// };
297 ///
298 /// fn name_to_person(name: String) -> Result<Person> {
299 /// // ... check for valid name
300 /// Ok(Person { name })
301 /// }
302 ///
303 /// fn get_names(conn: &Connection) -> Result<Vec<Person>> {
304 /// let mut stmt = conn.prepare("SELECT name FROM people WHERE id = :id")?;
305 /// let rows = stmt.query_and_then(&[(":id", "one")], |row| name_to_person(row.get(0)?))?;
306 ///
307 /// let mut persons = Vec::new();
308 /// for person_result in rows {
309 /// persons.push(person_result?);
310 /// }
311 ///
312 /// Ok(persons)
313 /// }
314 /// ```
315 ///
316 /// ### Use with positional params
317 ///
318 /// ```rust,no_run
319 /// # use rusqlite::{Connection, Result};
320 /// fn get_names(conn: &Connection) -> Result<Vec<String>> {
321 /// let mut stmt = conn.prepare("SELECT name FROM people WHERE id = ?1")?;
322 /// let rows = stmt.query_and_then(["one"], |row| row.get::<_, String>(0))?;
323 ///
324 /// let mut persons = Vec::new();
325 /// for person_result in rows {
326 /// persons.push(person_result?);
327 /// }
328 ///
329 /// Ok(persons)
330 /// }
331 /// ```
332 ///
333 /// # Failure
334 ///
335 /// Will return `Err` if binding parameters fails.
336 #[inline]
337 pub fn query_and_then<T, E, P, F>(&mut self, params: P, f: F) -> Result<AndThenRows<'_, F>>
338 where
339 P: Params,
340 E: From<Error>,
341 F: FnMut(&Row<'_>) -> Result<T, E>,
342 {
343 self.query(params).map(|rows| rows.and_then(f))
344 }
345
346 /// Return `true` if a query in the SQL statement it executes returns one
347 /// or more rows and `false` if the SQL returns an empty set.
348 #[inline]
349 pub fn exists<P: Params>(&mut self, params: P) -> Result<bool> {
350 let mut rows = self.query(params)?;
351 let exists = rows.next()?.is_some();
352 Ok(exists)
353 }
354
355 /// Convenience method to execute a query that is expected to return a
356 /// single row.
357 ///
358 /// If the query returns more than one row, all rows except the first are
359 /// ignored.
360 ///
361 /// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
362 /// query truly is optional, you can call
363 /// [`.optional()`](crate::OptionalExtension::optional) on the result of
364 /// this to get a `Result<Option<T>>` (requires that the trait
365 /// `rusqlite::OptionalExtension` is imported).
366 ///
367 /// # Failure
368 ///
369 /// Will return `Err` if the underlying SQLite call fails.
370 pub fn query_row<T, P, F>(&mut self, params: P, f: F) -> Result<T>
371 where
372 P: Params,
373 F: FnOnce(&Row<'_>) -> Result<T>,
374 {
375 let mut rows = self.query(params)?;
376
377 rows.get_expected_row().and_then(f)
378 }
379
380 /// Convenience method to execute a query that is expected to return exactly
381 /// one row.
382 ///
383 /// Returns `Err(QueryReturnedMoreThanOneRow)` if the query returns more than one row.
384 ///
385 /// Returns `Err(QueryReturnedNoRows)` if no results are returned. If the
386 /// query truly is optional, you can call
387 /// [`.optional()`](crate::OptionalExtension::optional) on the result of
388 /// this to get a `Result<Option<T>>` (requires that the trait
389 /// `rusqlite::OptionalExtension` is imported).
390 ///
391 /// # Failure
392 ///
393 /// Will return `Err` if the underlying SQLite call fails.
394 pub fn query_one<T, P, F>(&mut self, params: P, f: F) -> Result<T>
395 where
396 P: Params,
397 F: FnOnce(&Row<'_>) -> Result<T>,
398 {
399 let mut rows = self.query(params)?;
400 let row = rows.get_expected_row().and_then(f)?;
401 if rows.next()?.is_some() {
402 return Err(Error::QueryReturnedMoreThanOneRow);
403 }
404 Ok(row)
405 }
406
407 /// Consumes the statement.
408 ///
409 /// Functionally equivalent to the `Drop` implementation, but allows
410 /// callers to see any errors that occur.
411 ///
412 /// # Failure
413 ///
414 /// Will return `Err` if the underlying SQLite call fails.
415 #[inline]
416 pub fn finalize(mut self) -> Result<()> {
417 self.finalize_()
418 }
419
420 /// Return the (one-based) index of an SQL parameter given its name.
421 ///
422 /// Note that the initial ":" or "$" or "@" or "?" used to specify the
423 /// parameter is included as part of the name.
424 ///
425 /// ```rust,no_run
426 /// # use rusqlite::{Connection, Result};
427 /// fn example(conn: &Connection) -> Result<()> {
428 /// let stmt = conn.prepare("SELECT * FROM test WHERE name = :example")?;
429 /// let index = stmt.parameter_index(":example")?;
430 /// assert_eq!(index, Some(1));
431 /// Ok(())
432 /// }
433 /// ```
434 ///
435 /// # Failure
436 ///
437 /// Will return Err if `name` is invalid. Will return Ok(None) if the name
438 /// is valid but not a bound parameter of this statement.
439 #[inline]
440 pub fn parameter_index(&self, name: &str) -> Result<Option<usize>> {
441 Ok(self.stmt.bind_parameter_index(name))
442 }
443
444 /// Return the SQL parameter name given its (one-based) index (the inverse
445 /// of [`Statement::parameter_index`]).
446 ///
447 /// ```rust,no_run
448 /// # use rusqlite::{Connection, Result};
449 /// fn example(conn: &Connection) -> Result<()> {
450 /// let stmt = conn.prepare("SELECT * FROM test WHERE name = :example")?;
451 /// let index = stmt.parameter_name(1);
452 /// assert_eq!(index, Some(":example"));
453 /// Ok(())
454 /// }
455 /// ```
456 ///
457 /// # Failure
458 ///
459 /// Will return `None` if the column index is out of bounds or if the
460 /// parameter is positional.
461 ///
462 /// # Panics
463 ///
464 /// Panics when parameter name is not valid UTF-8.
465 #[inline]
466 pub fn parameter_name(&self, index: usize) -> Option<&'_ str> {
467 self.stmt.bind_parameter_name(index as i32).map(|name| {
468 name.to_str()
469 .expect("Invalid UTF-8 sequence in parameter name")
470 })
471 }
472
473 #[inline]
474 pub(crate) fn bind_parameters<P>(&mut self, params: P) -> Result<()>
475 where
476 P: IntoIterator,
477 P::Item: ToSql,
478 {
479 let expected = self.stmt.bind_parameter_count();
480 let mut index = 0;
481 for p in params {
482 index += 1; // The leftmost SQL parameter has an index of 1.
483 if index > expected {
484 break;
485 }
486 self.bind_parameter(&p, index)?;
487 }
488 if index == expected {
489 Ok(())
490 } else {
491 Err(Error::InvalidParameterCount(index, expected))
492 }
493 }
494
495 #[inline]
496 pub(crate) fn ensure_parameter_count(&self, n: usize) -> Result<()> {
497 let count = self.parameter_count();
498 if count == n {
499 Ok(())
500 } else {
501 Err(Error::InvalidParameterCount(n, count))
502 }
503 }
504
505 #[inline]
506 pub(crate) fn bind_parameters_named<S: BindIndex, T: ToSql>(
507 &mut self,
508 params: &[(S, T)],
509 ) -> Result<()> {
510 for (name, value) in params {
511 let i = name.idx(self)?;
512 let ts: &dyn ToSql = &value;
513 self.bind_parameter(ts, i)?;
514 }
515 Ok(())
516 }
517
518 /// Return the number of parameters that can be bound to this statement.
519 #[inline]
520 pub fn parameter_count(&self) -> usize {
521 self.stmt.bind_parameter_count()
522 }
523
524 /// Low level API to directly bind a parameter to a given index.
525 ///
526 /// Note that the index is one-based, that is, the first parameter index is
527 /// 1 and not 0. This is consistent with the SQLite API and the values given
528 /// to parameters bound as `?NNN`.
529 ///
530 /// The valid values for `one_based_col_index` begin at `1`, and end at
531 /// [`Statement::parameter_count`], inclusive.
532 ///
533 /// # Caveats
534 ///
535 /// This should not generally be used, but is available for special cases
536 /// such as:
537 ///
538 /// - binding parameters where a gap exists.
539 /// - binding named and positional parameters in the same query.
540 /// - separating parameter binding from query execution.
541 ///
542 /// In general, statements that have had *any* parameters bound this way
543 /// should have *all* parameters bound this way, and be queried or executed
544 /// by [`Statement::raw_query`] or [`Statement::raw_execute`], other usage
545 /// is unsupported and will likely, probably in surprising ways.
546 ///
547 /// That is: Do not mix the "raw" statement functions with the rest of the
548 /// API, or the results may be surprising, and may even change in future
549 /// versions without comment.
550 ///
551 /// # Example
552 ///
553 /// ```rust,no_run
554 /// # use rusqlite::{Connection, Result};
555 /// fn query(conn: &Connection) -> Result<()> {
556 /// let mut stmt = conn.prepare("SELECT * FROM test WHERE name = :name AND value > ?2")?;
557 /// stmt.raw_bind_parameter(c":name", "foo")?;
558 /// stmt.raw_bind_parameter(2, 100)?;
559 /// let mut rows = stmt.raw_query();
560 /// while let Some(row) = rows.next()? {
561 /// // ...
562 /// }
563 /// Ok(())
564 /// }
565 /// ```
566 #[inline]
567 pub fn raw_bind_parameter<I: BindIndex, T: ToSql>(
568 &mut self,
569 one_based_index: I,
570 param: T,
571 ) -> Result<()> {
572 // This is the same as `bind_parameter` but slightly more ergonomic and
573 // correctly takes `&mut self`.
574 self.bind_parameter(¶m, one_based_index.idx(self)?)
575 }
576
577 /// Low level API to execute a statement given that all parameters were
578 /// bound explicitly with the [`Statement::raw_bind_parameter`] API.
579 ///
580 /// # Caveats
581 ///
582 /// Any unbound parameters will have `NULL` as their value.
583 ///
584 /// This should not generally be used outside special cases, and
585 /// functions in the [`Statement::execute`] family should be preferred.
586 ///
587 /// # Failure
588 ///
589 /// Will return `Err` if the executed statement returns rows (in which case
590 /// `query` should be used instead), or the underlying SQLite call fails.
591 #[inline]
592 pub fn raw_execute(&mut self) -> Result<usize> {
593 self.execute_with_bound_parameters()
594 }
595
596 /// Low level API to get `Rows` for this query given that all parameters
597 /// were bound explicitly with the [`Statement::raw_bind_parameter`] API.
598 ///
599 /// # Caveats
600 ///
601 /// Any unbound parameters will have `NULL` as their value.
602 ///
603 /// This should not generally be used outside special cases, and
604 /// functions in the [`Statement::query`] family should be preferred.
605 ///
606 /// Note that if the SQL does not return results, [`Statement::raw_execute`]
607 /// should be used instead.
608 #[inline]
609 pub fn raw_query(&mut self) -> Rows<'_> {
610 Rows::new(self)
611 }
612
613 // generic because many of these branches can constant fold away.
614 fn bind_parameter<P: ?Sized + ToSql>(&self, param: &P, ndx: usize) -> Result<()> {
615 let value = param.to_sql()?;
616
617 let ptr = unsafe { self.stmt.ptr() };
618 self.conn.decode_result(match value {
619 ToSqlOutput::Borrowed(ValueRef::Null) | ToSqlOutput::Owned(Value::Null) => {
620 unsafe { ffi::sqlite3_bind_null(ptr, ndx as c_int) }
621 },
622 ToSqlOutput::Borrowed(ValueRef::Integer(i)) | ToSqlOutput::Owned(Value::Integer(i)) => {
623 unsafe { ffi::sqlite3_bind_int64(ptr, ndx as c_int, i) }
624 },
625 ToSqlOutput::Borrowed(ValueRef::Real(r)) | ToSqlOutput::Owned(Value::Real(r)) => {
626 unsafe { ffi::sqlite3_bind_double(ptr, ndx as c_int, r) }
627 },
628 ToSqlOutput::Borrowed(ValueRef::Text(s)) => {
629 Self::bind_text(ptr, ndx, s)
630 },
631 ToSqlOutput::Owned(Value::Text(s)) => {
632 Self::bind_text(ptr, ndx, s.as_bytes())
633 },
634 ToSqlOutput::Borrowed(ValueRef::Blob(b)) => {
635 Self::bind_blob(ptr, ndx, b)
636 },
637 ToSqlOutput::Owned(Value::Blob(b)) => {
638 Self::bind_blob(ptr, ndx, b.as_slice())
639 },
640 #[cfg(feature = "blob")]
641 ToSqlOutput::ZeroBlob(len) => {
642 unsafe {
643 ffi::sqlite3_bind_zeroblob64(ptr, ndx as c_int, len)
644 }
645 }
646 #[cfg(feature = "functions")]
647 ToSqlOutput::Arg(_) => {
648 return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
649 }
650 #[cfg(feature = "pointer")]
651 ToSqlOutput::Pointer(p) => {
652 unsafe {
653 ffi::sqlite3_bind_pointer(ptr, ndx as c_int, p.0.cast_mut(), p.1.as_ptr(), p.2)
654 }
655 }
656 })
657 }
658
659 fn bind_text(stmt: *mut sqlite3_stmt, ndx: usize, s: &[u8]) -> c_int {
660 unsafe {
661 let (c_str, len, destructor) = str_for_sqlite(s);
662 ffi::sqlite3_bind_text64(
663 stmt,
664 ndx as c_int,
665 c_str,
666 len,
667 destructor,
668 ffi::SQLITE_UTF8 as _, // TODO SQLITE_UTF8_ZT
669 )
670 }
671 }
672
673 fn bind_blob(stmt: *mut sqlite3_stmt, ndx: usize, b: &[u8]) -> c_int {
674 unsafe {
675 let length = b.len();
676 if length == 0 {
677 ffi::sqlite3_bind_zeroblob64(stmt, ndx as c_int, 0)
678 } else {
679 ffi::sqlite3_bind_blob64(
680 stmt,
681 ndx as c_int,
682 b.as_ptr().cast::<c_void>(),
683 length as ffi::sqlite3_uint64,
684 ffi::SQLITE_TRANSIENT(),
685 )
686 }
687 }
688 }
689
690 #[inline]
691 fn execute_with_bound_parameters(&mut self) -> Result<usize> {
692 self.check_update()?;
693 let r = self.stmt.step();
694 let rr = self.stmt.reset();
695 match r {
696 ffi::SQLITE_DONE => match rr {
697 ffi::SQLITE_OK => Ok(self.conn.changes() as usize),
698 _ => Err(self.conn.decode_result(rr).unwrap_err()),
699 },
700 ffi::SQLITE_ROW => Err(Error::ExecuteReturnedResults),
701 _ => Err(self.conn.decode_result(r).unwrap_err()),
702 }
703 }
704
705 #[inline]
706 fn finalize_(&mut self) -> Result<()> {
707 let mut stmt = unsafe { RawStatement::new(ptr::null_mut()) };
708 mem::swap(&mut stmt, &mut self.stmt);
709 self.conn.decode_result(stmt.finalize())
710 }
711
712 #[inline]
713 #[allow(clippy::unnecessary_wraps)]
714 fn check_update(&self) -> Result<()> {
715 cfg_select! {
716 feature = "extra_check" => {
717 if self.column_count() > 0 && self.stmt.readonly() {
718 return Err(Error::ExecuteReturnedResults);
719 }
720 }
721 _ => {}
722 }
723 Ok(())
724 }
725
726 /// Returns a string containing the SQL text of prepared statement with
727 /// bound parameters expanded.
728 pub fn expanded_sql(&self) -> Option<String> {
729 self.stmt
730 .expanded_sql()
731 .map(|s| s.to_string_lossy().to_string())
732 }
733
734 /// Get the value for one of the status counters for this statement.
735 #[inline]
736 pub fn get_status(&self, status: StatementStatus) -> i32 {
737 self.stmt.get_status(status, false)
738 }
739
740 /// Reset the value of one of the status counters for this statement,
741 #[inline]
742 /// returning the value it had before resetting.
743 pub fn reset_status(&self, status: StatementStatus) -> i32 {
744 self.stmt.get_status(status, true)
745 }
746
747 /// Returns 1 if the prepared statement is an EXPLAIN statement,
748 /// or 2 if the statement is an EXPLAIN QUERY PLAN,
749 /// or 0 if it is an ordinary statement or a NULL pointer.
750 #[inline]
751 pub fn is_explain(&self) -> i32 {
752 self.stmt.is_explain()
753 }
754
755 /// Returns true if the statement is read only.
756 #[inline]
757 pub fn readonly(&self) -> bool {
758 self.stmt.readonly()
759 }
760
761 /// Safety: This is unsafe, because using `sqlite3_stmt` after the
762 /// connection has closed is illegal, but `RawStatement` does not enforce
763 /// this, as it loses our protective `'conn` lifetime bound.
764 #[inline]
765 #[cfg(feature = "cache")]
766 pub(crate) unsafe fn into_raw(mut self) -> RawStatement {
767 unsafe {
768 let mut stmt = RawStatement::new(ptr::null_mut());
769 mem::swap(&mut stmt, &mut self.stmt);
770 stmt
771 }
772 }
773
774 /// Reset all bindings
775 pub fn clear_bindings(&mut self) {
776 self.stmt.clear_bindings();
777 }
778
779 pub(crate) unsafe fn ptr(&self) -> *mut ffi::sqlite3_stmt {
780 unsafe { self.stmt.ptr() }
781 }
782}
783
784impl fmt::Debug for Statement<'_> {
785 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786 let sql = if self.stmt.is_null() {
787 Ok("")
788 } else {
789 self.stmt.sql().unwrap().to_str()
790 };
791 f.debug_struct("Statement")
792 .field("conn", self.conn)
793 .field("stmt", &self.stmt)
794 .field("sql", &sql)
795 .finish()
796 }
797}
798
799impl Drop for Statement<'_> {
800 #[expect(unused_must_use)]
801 #[inline]
802 fn drop(&mut self) {
803 self.finalize_();
804 }
805}
806
807impl Statement<'_> {
808 #[inline]
809 pub(super) fn new(conn: &Connection, stmt: RawStatement) -> Statement<'_> {
810 Statement { conn, stmt }
811 }
812
813 pub(super) fn value_ref(&self, col: usize) -> ValueRef<'_> {
814 let raw = unsafe { self.stmt.ptr() };
815
816 match self.stmt.column_type(col) {
817 ffi::SQLITE_NULL => ValueRef::Null,
818 ffi::SQLITE_INTEGER => {
819 ValueRef::Integer(unsafe { ffi::sqlite3_column_int64(raw, col as c_int) })
820 }
821 ffi::SQLITE_FLOAT => {
822 ValueRef::Real(unsafe { ffi::sqlite3_column_double(raw, col as c_int) })
823 }
824 ffi::SQLITE_TEXT => {
825 let s = unsafe {
826 // Quoting from "Using SQLite" book:
827 // To avoid problems, an application should first extract the desired type using
828 // a sqlite3_column_xxx() function, and then call the
829 // appropriate sqlite3_column_bytes() function.
830 let text = ffi::sqlite3_column_text(raw, col as c_int);
831 let len = ffi::sqlite3_column_bytes(raw, col as c_int);
832 assert!(
833 !text.is_null(),
834 "unexpected SQLITE_TEXT column type with NULL data"
835 );
836 from_raw_parts(text.cast::<u8>(), len)
837 };
838
839 ValueRef::Text(s)
840 }
841 ffi::SQLITE_BLOB => {
842 let (blob, len) = unsafe {
843 (
844 ffi::sqlite3_column_blob(raw, col as c_int),
845 ffi::sqlite3_column_bytes(raw, col as c_int),
846 )
847 };
848
849 assert!(
850 len >= 0,
851 "unexpected negative return from sqlite3_column_bytes"
852 );
853 if len > 0 {
854 assert!(
855 !blob.is_null(),
856 "unexpected SQLITE_BLOB column type with NULL data"
857 );
858 ValueRef::Blob(unsafe { from_raw_parts(blob.cast::<u8>(), len) })
859 } else {
860 // The return value from sqlite3_column_blob() for a zero-length BLOB
861 // is a NULL pointer.
862 ValueRef::Blob(&[])
863 }
864 }
865 _ => unreachable!("sqlite3_column_type returned invalid value"),
866 }
867 }
868
869 #[inline]
870 pub(super) fn step(&self) -> Result<bool> {
871 match self.stmt.step() {
872 ffi::SQLITE_ROW => Ok(true),
873 ffi::SQLITE_DONE => Ok(false),
874 code => Err(self.conn.decode_result(code).unwrap_err()),
875 }
876 }
877
878 #[inline]
879 pub(super) fn reset(&self) -> Result<()> {
880 match self.stmt.reset() {
881 ffi::SQLITE_OK => Ok(()),
882 code => Err(self.conn.decode_result(code).unwrap_err()),
883 }
884 }
885}
886
887/// Prepared statement status counters.
888///
889/// See `https://www.sqlite.org/c3ref/c_stmtstatus_counter.html`
890/// for explanations of each.
891///
892/// Note that depending on your version of SQLite, all of these
893/// may not be available.
894#[repr(i32)]
895#[derive(Clone, Copy, PartialEq, Eq)]
896#[non_exhaustive]
897pub enum StatementStatus {
898 /// Equivalent to `SQLITE_STMTSTATUS_FULLSCAN_STEP`
899 FullscanStep = 1,
900 /// Equivalent to `SQLITE_STMTSTATUS_SORT`
901 Sort = 2,
902 /// Equivalent to `SQLITE_STMTSTATUS_AUTOINDEX`
903 AutoIndex = 3,
904 /// Equivalent to `SQLITE_STMTSTATUS_VM_STEP`
905 VmStep = 4,
906 /// Equivalent to `SQLITE_STMTSTATUS_REPREPARE` (3.20.0)
907 RePrepare = 5,
908 /// Equivalent to `SQLITE_STMTSTATUS_RUN` (3.20.0)
909 Run = 6,
910 /// Equivalent to `SQLITE_STMTSTATUS_FILTER_MISS`
911 FilterMiss = 7,
912 /// Equivalent to `SQLITE_STMTSTATUS_FILTER_HIT`
913 FilterHit = 8,
914 /// Equivalent to `SQLITE_STMTSTATUS_MEMUSED` (3.20.0)
915 MemUsed = 99,
916}
917
918#[cfg(all(test, not(miri)))]
919mod test {
920 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
921 use wasm_bindgen_test::wasm_bindgen_test as test;
922
923 use crate::types::ToSql;
924 use crate::{Connection, Error, Result, params_from_iter};
925
926 #[test]
927 fn test_execute_named() -> Result<()> {
928 let db = Connection::open_in_memory()?;
929 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
930
931 assert_eq!(
932 db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)])?,
933 1
934 );
935 assert_eq!(
936 db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)])?,
937 1
938 );
939 assert_eq!(
940 db.execute(
941 "INSERT INTO foo(x) VALUES (:x)",
942 crate::named_params! {":x": 3i32}
943 )?,
944 1
945 );
946
947 assert_eq!(
948 6i32,
949 db.query_row::<i32, _, _>(
950 "SELECT SUM(x) FROM foo WHERE x > :x",
951 &[(":x", &0i32)],
952 |r| r.get(0)
953 )?
954 );
955 assert_eq!(
956 5i32,
957 db.query_row::<i32, _, _>(
958 "SELECT SUM(x) FROM foo WHERE x > :x",
959 &[(":x", &1i32)],
960 |r| r.get(0)
961 )?
962 );
963 Ok(())
964 }
965
966 #[test]
967 fn test_stmt_execute_named() -> Result<()> {
968 let db = Connection::open_in_memory()?;
969 let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
970 INTEGER)";
971 db.execute_batch(sql)?;
972
973 let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)")?;
974 stmt.execute(&[(":name", "one")])?;
975 stmt.execute(vec![(":name", "one")].as_slice())?;
976
977 let mut stmt = db.prepare("SELECT COUNT(*) FROM test WHERE name = :name")?;
978 assert_eq!(
979 2i32,
980 stmt.query_row::<i32, _, _>(&[(":name", "one")], |r| r.get(0))?
981 );
982 Ok(())
983 }
984
985 #[test]
986 fn test_query_named() -> Result<()> {
987 let db = Connection::open_in_memory()?;
988 let sql = r#"
989 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
990 INSERT INTO test(id, name) VALUES (1, "one");
991 "#;
992 db.execute_batch(sql)?;
993
994 let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
995 let mut rows = stmt.query(&[(":name", "one")])?;
996 let id: Result<i32> = rows.next()?.unwrap().get(0);
997 assert_eq!(Ok(1), id);
998 Ok(())
999 }
1000
1001 #[test]
1002 fn test_query_map_named() -> Result<()> {
1003 let db = Connection::open_in_memory()?;
1004 let sql = r#"
1005 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
1006 INSERT INTO test(id, name) VALUES (1, "one");
1007 "#;
1008 db.execute_batch(sql)?;
1009
1010 let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
1011 let mut rows = stmt.query_map(&[(":name", "one")], |row| {
1012 let id: Result<i32> = row.get(0);
1013 id.map(|i| 2 * i)
1014 })?;
1015
1016 let doubled_id: i32 = rows.next().unwrap()?;
1017 assert_eq!(2, doubled_id);
1018 Ok(())
1019 }
1020
1021 #[test]
1022 fn test_query_and_then_by_name() -> Result<()> {
1023 let db = Connection::open_in_memory()?;
1024 let sql = r#"
1025 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
1026 INSERT INTO test(id, name) VALUES (1, "one");
1027 INSERT INTO test(id, name) VALUES (2, "one");
1028 "#;
1029 db.execute_batch(sql)?;
1030
1031 let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC")?;
1032 let mut rows = stmt.query_and_then(&[(":name", "one")], |row| {
1033 let id: i32 = row.get(0)?;
1034 if id == 1 {
1035 Ok(id)
1036 } else {
1037 Err(Error::SqliteSingleThreadedMode)
1038 }
1039 })?;
1040
1041 // first row should be Ok
1042 let doubled_id: i32 = rows.next().unwrap()?;
1043 assert_eq!(1, doubled_id);
1044
1045 // second row should be an `Err`
1046 #[expect(clippy::match_wild_err_arm)]
1047 match rows.next().unwrap() {
1048 Ok(_) => panic!("invalid Ok"),
1049 Err(Error::SqliteSingleThreadedMode) => (),
1050 Err(_) => panic!("invalid Err"),
1051 }
1052 Ok(())
1053 }
1054
1055 #[test]
1056 fn test_unbound_parameters_are_null() -> Result<()> {
1057 let db = Connection::open_in_memory()?;
1058 let sql = "CREATE TABLE test (x TEXT, y TEXT)";
1059 db.execute_batch(sql)?;
1060
1061 let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
1062 stmt.execute(&[(":x", "one")])?;
1063
1064 let result: Option<String> = db.one_column("SELECT y FROM test WHERE x = 'one'", [])?;
1065 assert!(result.is_none());
1066 Ok(())
1067 }
1068
1069 #[test]
1070 fn test_raw_binding() -> Result<()> {
1071 let db = Connection::open_in_memory()?;
1072 db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?;
1073 {
1074 let mut stmt = db.prepare("INSERT INTO test (name, value) VALUES (:name, ?3)")?;
1075
1076 stmt.raw_bind_parameter(c":name", "example")?;
1077 stmt.raw_bind_parameter(":name", "example")?;
1078 stmt.raw_bind_parameter(3, 50i32)?;
1079 let n = stmt.raw_execute()?;
1080 assert_eq!(n, 1);
1081 }
1082
1083 {
1084 let mut stmt = db.prepare("SELECT name, value FROM test WHERE value = ?2")?;
1085 stmt.raw_bind_parameter(2, 50)?;
1086 let mut rows = stmt.raw_query();
1087 {
1088 let row = rows.next()?.unwrap();
1089 let name: String = row.get(0)?;
1090 assert_eq!(name, "example");
1091 let value: i32 = row.get(1)?;
1092 assert_eq!(value, 50);
1093 }
1094 assert!(rows.next()?.is_none());
1095 }
1096
1097 Ok(())
1098 }
1099
1100 #[test]
1101 fn test_unbound_parameters_are_reused() -> Result<()> {
1102 let db = Connection::open_in_memory()?;
1103 let sql = "CREATE TABLE test (x TEXT, y TEXT)";
1104 db.execute_batch(sql)?;
1105
1106 let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
1107 stmt.execute(&[(":x", "one")])?;
1108 stmt.execute(&[(c":y", "two")])?;
1109
1110 let result: String = db.one_column("SELECT x FROM test WHERE y = 'two'", [])?;
1111 assert_eq!(result, "one");
1112 Ok(())
1113 }
1114
1115 #[test]
1116 fn test_insert() -> Result<()> {
1117 let db = Connection::open_in_memory()?;
1118 db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)")?;
1119 let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?1)")?;
1120 assert_eq!(stmt.insert([1i32])?, 1);
1121 assert_eq!(stmt.insert([2i32])?, 2);
1122 match stmt.insert([1i32]).unwrap_err() {
1123 Error::StatementChangedRows(0) => (),
1124 err => panic!("Unexpected error {err}"),
1125 }
1126 let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")?;
1127 match multi.insert([]).unwrap_err() {
1128 Error::StatementChangedRows(2) => (),
1129 err => panic!("Unexpected error {err}"),
1130 }
1131 Ok(())
1132 }
1133
1134 #[test]
1135 fn test_insert_different_tables() -> Result<()> {
1136 // Test for https://github.com/rusqlite/rusqlite/issues/171
1137 let db = Connection::open_in_memory()?;
1138 db.execute_batch(
1139 r"
1140 CREATE TABLE foo(x INTEGER);
1141 CREATE TABLE bar(x INTEGER);
1142 ",
1143 )?;
1144
1145 assert_eq!(db.prepare("INSERT INTO foo VALUES (10)")?.insert([])?, 1);
1146 assert_eq!(db.prepare("INSERT INTO bar VALUES (10)")?.insert([])?, 1);
1147 Ok(())
1148 }
1149
1150 #[test]
1151 fn test_exists() -> Result<()> {
1152 let db = Connection::open_in_memory()?;
1153 let sql = "BEGIN;
1154 CREATE TABLE foo(x INTEGER);
1155 INSERT INTO foo VALUES(1);
1156 INSERT INTO foo VALUES(2);
1157 END;";
1158 db.execute_batch(sql)?;
1159 let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?1")?;
1160 assert!(stmt.exists([1i32])?);
1161 assert!(stmt.exists([2i32])?);
1162 assert!(!stmt.exists([0i32])?);
1163 Ok(())
1164 }
1165 #[test]
1166 fn test_tuple_params() -> Result<()> {
1167 let db = Connection::open_in_memory()?;
1168 let s = db.query_row("SELECT printf('[%s]', ?1)", ("abc",), |r| {
1169 r.get::<_, String>(0)
1170 })?;
1171 assert_eq!(s, "[abc]");
1172 let s = db.query_row(
1173 "SELECT printf('%d %s %d', ?1, ?2, ?3)",
1174 (1i32, "abc", 2i32),
1175 |r| r.get::<_, String>(0),
1176 )?;
1177 assert_eq!(s, "1 abc 2");
1178 let s = db.query_row(
1179 "SELECT printf('%d %s %d %d', ?1, ?2, ?3, ?4)",
1180 (1, "abc", 2i32, 4i64),
1181 |r| r.get::<_, String>(0),
1182 )?;
1183 assert_eq!(s, "1 abc 2 4");
1184 #[rustfmt::skip]
1185 let bigtup = (
1186 0, "a", 1, "b", 2, "c", 3, "d",
1187 4, "e", 5, "f", 6, "g", 7, "h",
1188 );
1189 let query = "SELECT printf(
1190 '%d %s | %d %s | %d %s | %d %s || %d %s | %d %s | %d %s | %d %s',
1191 ?1, ?2, ?3, ?4,
1192 ?5, ?6, ?7, ?8,
1193 ?9, ?10, ?11, ?12,
1194 ?13, ?14, ?15, ?16
1195 )";
1196 let s = db.query_row(query, bigtup, |r| r.get::<_, String>(0))?;
1197 assert_eq!(s, "0 a | 1 b | 2 c | 3 d || 4 e | 5 f | 6 g | 7 h");
1198 Ok(())
1199 }
1200
1201 #[test]
1202 fn test_query_row() -> Result<()> {
1203 let db = Connection::open_in_memory()?;
1204 let sql = "BEGIN;
1205 CREATE TABLE foo(x INTEGER, y INTEGER);
1206 INSERT INTO foo VALUES(1, 3);
1207 INSERT INTO foo VALUES(2, 4);
1208 END;";
1209 db.execute_batch(sql)?;
1210 let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?1")?;
1211 let y: Result<i64> = stmt.query_row([1i32], |r| r.get(0));
1212 assert_eq!(3i64, y?);
1213 Ok(())
1214 }
1215
1216 #[test]
1217 fn query_one() -> Result<()> {
1218 let db = Connection::open_in_memory()?;
1219 db.execute_batch("CREATE TABLE foo(x INTEGER, y INTEGER);")?;
1220 let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?1")?;
1221 let y: Result<i64> = stmt.query_one([1i32], |r| r.get(0));
1222 assert_eq!(Error::QueryReturnedNoRows, y.unwrap_err());
1223 db.execute_batch("INSERT INTO foo VALUES(1, 3);")?;
1224 let y: Result<i64> = stmt.query_one([1i32], |r| r.get(0));
1225 assert_eq!(3i64, y?);
1226 db.execute_batch("INSERT INTO foo VALUES(1, 3);")?;
1227 let y: Result<i64> = stmt.query_one([1i32], |r| r.get(0));
1228 assert_eq!(Error::QueryReturnedMoreThanOneRow, y.unwrap_err());
1229 Ok(())
1230 }
1231
1232 #[test]
1233 fn test_query_by_column_name() -> Result<()> {
1234 let db = Connection::open_in_memory()?;
1235 let sql = "BEGIN;
1236 CREATE TABLE foo(x INTEGER, y INTEGER);
1237 INSERT INTO foo VALUES(1, 3);
1238 END;";
1239 db.execute_batch(sql)?;
1240 let mut stmt = db.prepare("SELECT y FROM foo")?;
1241 let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
1242 assert_eq!(3i64, y?);
1243 Ok(())
1244 }
1245
1246 #[test]
1247 fn test_query_by_column_name_ignore_case() -> Result<()> {
1248 let db = Connection::open_in_memory()?;
1249 let sql = "BEGIN;
1250 CREATE TABLE foo(x INTEGER, y INTEGER);
1251 INSERT INTO foo VALUES(1, 3);
1252 END;";
1253 db.execute_batch(sql)?;
1254 let mut stmt = db.prepare("SELECT y as Y FROM foo")?;
1255 let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
1256 assert_eq!(3i64, y?);
1257 Ok(())
1258 }
1259
1260 #[test]
1261 fn test_expanded_sql() -> Result<()> {
1262 let db = Connection::open_in_memory()?;
1263 let stmt = db.prepare("SELECT ?1")?;
1264 stmt.bind_parameter(&1, 1)?;
1265 assert_eq!(Some("SELECT 1".to_owned()), stmt.expanded_sql());
1266 Ok(())
1267 }
1268
1269 #[test]
1270 fn test_bind_parameters() -> Result<()> {
1271 let db = Connection::open_in_memory()?;
1272 // dynamic slice:
1273 db.query_row(
1274 "SELECT ?1, ?2, ?3",
1275 [&1u8 as &dyn ToSql, &"one", &Some("one")],
1276 |row| row.get::<_, u8>(0),
1277 )?;
1278 // existing collection:
1279 let data = vec![1, 2, 3];
1280 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1281 row.get::<_, u8>(0)
1282 })?;
1283 db.query_row(
1284 "SELECT ?1, ?2, ?3",
1285 params_from_iter(data.as_slice()),
1286 |row| row.get::<_, u8>(0),
1287 )?;
1288 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data), |row| {
1289 row.get::<_, u8>(0)
1290 })?;
1291
1292 use std::collections::BTreeSet;
1293 let data: BTreeSet<String> = ["one", "two", "three"]
1294 .iter()
1295 .map(|s| (*s).to_string())
1296 .collect();
1297 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1298 row.get::<_, String>(0)
1299 })?;
1300
1301 let data = [0; 3];
1302 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1303 row.get::<_, u8>(0)
1304 })?;
1305 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data.iter()), |row| {
1306 row.get::<_, u8>(0)
1307 })?;
1308 Ok(())
1309 }
1310
1311 #[test]
1312 fn test_parameter_name() -> Result<()> {
1313 let db = Connection::open_in_memory()?;
1314 db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?;
1315 let stmt = db.prepare("INSERT INTO test (name, value) VALUES (:name, ?3)")?;
1316 assert_eq!(stmt.parameter_name(0), None);
1317 assert_eq!(stmt.parameter_name(1), Some(":name"));
1318 assert_eq!(stmt.parameter_name(2), None);
1319 Ok(())
1320 }
1321
1322 #[test]
1323 fn test_empty_stmt() -> Result<()> {
1324 let conn = Connection::open_in_memory()?;
1325 let mut stmt = conn.prepare("")?;
1326 assert_eq!(0, stmt.column_count());
1327 stmt.parameter_index("test")?;
1328 let err = stmt.step().unwrap_err();
1329 assert_eq!(err.sqlite_error_code(), Some(crate::ErrorCode::ApiMisuse));
1330 assert_eq!(
1331 err.sqlite_extended_error_code(),
1332 Some(crate::ffi::SQLITE_MISUSE)
1333 );
1334 // error msg is different with sqlcipher, so we use assert_ne:
1335 assert_ne!(err.to_string(), "not an error".to_owned());
1336 stmt.reset()?; // SQLITE_OMIT_AUTORESET = false
1337 stmt.execute([]).unwrap_err();
1338 Ok(())
1339 }
1340
1341 #[test]
1342 fn test_comment_stmt() -> Result<()> {
1343 let conn = Connection::open_in_memory()?;
1344 conn.prepare("/*SELECT 1;*/")?;
1345 Ok(())
1346 }
1347
1348 #[test]
1349 fn test_comment_and_sql_stmt() -> Result<()> {
1350 let conn = Connection::open_in_memory()?;
1351 let stmt = conn.prepare("/*...*/ SELECT 1;")?;
1352 assert_eq!(1, stmt.column_count());
1353 Ok(())
1354 }
1355
1356 #[test]
1357 fn test_semi_colon_stmt() -> Result<()> {
1358 let conn = Connection::open_in_memory()?;
1359 let stmt = conn.prepare(";")?;
1360 assert_eq!(0, stmt.column_count());
1361 Ok(())
1362 }
1363
1364 #[test]
1365 fn test_utf16_conversion() -> Result<()> {
1366 let db = Connection::open_in_memory()?;
1367 db.pragma_update(None, "encoding", "UTF-16le")?;
1368 let encoding: String = db.pragma_query_one(None, "encoding")?;
1369 assert_eq!("UTF-16le", encoding);
1370 db.execute_batch("CREATE TABLE foo(x TEXT)")?;
1371 let expected = "ใในใ";
1372 db.execute("INSERT INTO foo(x) VALUES (?1)", [&expected])?;
1373 let actual: String = db.one_column("SELECT x FROM foo", [])?;
1374 assert_eq!(expected, actual);
1375 Ok(())
1376 }
1377
1378 #[test]
1379 fn test_nul_byte() -> Result<()> {
1380 let db = Connection::open_in_memory()?;
1381 let expected = "a\x00b";
1382 let actual: String = db.one_column("SELECT ?1", [expected])?;
1383 assert_eq!(expected, actual);
1384 Ok(())
1385 }
1386
1387 #[test]
1388 fn is_explain() -> Result<()> {
1389 let db = Connection::open_in_memory()?;
1390 let stmt = db.prepare("SELECT 1;")?;
1391 assert_eq!(0, stmt.is_explain());
1392 Ok(())
1393 }
1394
1395 #[test]
1396 fn readonly() -> Result<()> {
1397 let db = Connection::open_in_memory()?;
1398 let stmt = db.prepare("SELECT 1;")?;
1399 assert!(stmt.readonly());
1400 Ok(())
1401 }
1402
1403 #[test]
1404 fn test_error_offset() -> Result<()> {
1405 use crate::ffi::ErrorCode;
1406 let db = Connection::open_in_memory()?;
1407 let r = db.execute_batch("SELECT INVALID_FUNCTION;");
1408 match r.unwrap_err() {
1409 Error::SqlInputError { error, offset, .. } => {
1410 assert_eq!(error.code, ErrorCode::Unknown);
1411 assert_eq!(offset, 7);
1412 }
1413 err => panic!("Unexpected error {err}"),
1414 }
1415 Ok(())
1416 }
1417}