rusqlite/statement.rs
1use std::ffi::{c_int, c_void};
2use std::slice::from_raw_parts;
3use std::{fmt, mem, ptr, str};
4
5use super::ffi;
6use super::str_for_sqlite;
7use super::{
8 AndThenRows, Connection, Error, MappedRows, Params, RawStatement, Result, Row, Rows, ValueRef,
9};
10use crate::bind::BindIndex;
11use crate::types::{ToSql, ToSqlOutput};
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 Err(Error::InvalidParameterCount(index, expected))
490 } else {
491 Ok(())
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 Err(Error::InvalidParameterCount(n, count))
500 } else {
501 Ok(())
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 let value = match value {
619 ToSqlOutput::Borrowed(v) => v,
620 ToSqlOutput::Owned(ref v) => ValueRef::from(v),
621
622 #[cfg(feature = "blob")]
623 ToSqlOutput::ZeroBlob(len) => {
624 // TODO sqlite3_bind_zeroblob64 // 3.8.11
625 return self
626 .conn
627 .decode_result(unsafe { ffi::sqlite3_bind_zeroblob(ptr, ndx as c_int, len) });
628 }
629 #[cfg(feature = "functions")]
630 ToSqlOutput::Arg(_) => {
631 return Err(err!(ffi::SQLITE_MISUSE, "Unsupported value \"{value:?}\""));
632 }
633 #[cfg(feature = "pointer")]
634 ToSqlOutput::Pointer(p) => {
635 return self.conn.decode_result(unsafe {
636 ffi::sqlite3_bind_pointer(ptr, ndx as c_int, p.0 as _, p.1.as_ptr(), p.2)
637 });
638 }
639 };
640 self.conn.decode_result(match value {
641 ValueRef::Null => unsafe { ffi::sqlite3_bind_null(ptr, ndx as c_int) },
642 ValueRef::Integer(i) => unsafe { ffi::sqlite3_bind_int64(ptr, ndx as c_int, i) },
643 ValueRef::Real(r) => unsafe { ffi::sqlite3_bind_double(ptr, ndx as c_int, r) },
644 ValueRef::Text(s) => unsafe {
645 let (c_str, len, destructor) = str_for_sqlite(s);
646 ffi::sqlite3_bind_text64(
647 ptr,
648 ndx as c_int,
649 c_str,
650 len,
651 destructor,
652 ffi::SQLITE_UTF8 as _,
653 )
654 },
655 ValueRef::Blob(b) => unsafe {
656 let length = b.len();
657 if length == 0 {
658 ffi::sqlite3_bind_zeroblob(ptr, ndx as c_int, 0)
659 } else {
660 ffi::sqlite3_bind_blob64(
661 ptr,
662 ndx as c_int,
663 b.as_ptr().cast::<c_void>(),
664 length as ffi::sqlite3_uint64,
665 ffi::SQLITE_TRANSIENT(),
666 )
667 }
668 },
669 })
670 }
671
672 #[inline]
673 fn execute_with_bound_parameters(&mut self) -> Result<usize> {
674 self.check_update()?;
675 let r = self.stmt.step();
676 let rr = self.stmt.reset();
677 match r {
678 ffi::SQLITE_DONE => match rr {
679 ffi::SQLITE_OK => Ok(self.conn.changes() as usize),
680 _ => Err(self.conn.decode_result(rr).unwrap_err()),
681 },
682 ffi::SQLITE_ROW => Err(Error::ExecuteReturnedResults),
683 _ => Err(self.conn.decode_result(r).unwrap_err()),
684 }
685 }
686
687 #[inline]
688 fn finalize_(&mut self) -> Result<()> {
689 let mut stmt = unsafe { RawStatement::new(ptr::null_mut()) };
690 mem::swap(&mut stmt, &mut self.stmt);
691 self.conn.decode_result(stmt.finalize())
692 }
693
694 #[cfg(feature = "extra_check")]
695 #[inline]
696 fn check_update(&self) -> Result<()> {
697 if self.column_count() > 0 && self.stmt.readonly() {
698 return Err(Error::ExecuteReturnedResults);
699 }
700 Ok(())
701 }
702
703 #[cfg(not(feature = "extra_check"))]
704 #[inline]
705 #[expect(clippy::unnecessary_wraps)]
706 fn check_update(&self) -> Result<()> {
707 Ok(())
708 }
709
710 /// Returns a string containing the SQL text of prepared statement with
711 /// bound parameters expanded.
712 pub fn expanded_sql(&self) -> Option<String> {
713 self.stmt
714 .expanded_sql()
715 .map(|s| s.to_string_lossy().to_string())
716 }
717
718 /// Get the value for one of the status counters for this statement.
719 #[inline]
720 pub fn get_status(&self, status: StatementStatus) -> i32 {
721 self.stmt.get_status(status, false)
722 }
723
724 /// Reset the value of one of the status counters for this statement,
725 #[inline]
726 /// returning the value it had before resetting.
727 pub fn reset_status(&self, status: StatementStatus) -> i32 {
728 self.stmt.get_status(status, true)
729 }
730
731 /// Returns 1 if the prepared statement is an EXPLAIN statement,
732 /// or 2 if the statement is an EXPLAIN QUERY PLAN,
733 /// or 0 if it is an ordinary statement or a NULL pointer.
734 #[inline]
735 pub fn is_explain(&self) -> i32 {
736 self.stmt.is_explain()
737 }
738
739 /// Returns true if the statement is read only.
740 #[inline]
741 pub fn readonly(&self) -> bool {
742 self.stmt.readonly()
743 }
744
745 /// Safety: This is unsafe, because using `sqlite3_stmt` after the
746 /// connection has closed is illegal, but `RawStatement` does not enforce
747 /// this, as it loses our protective `'conn` lifetime bound.
748 #[inline]
749 #[cfg(feature = "cache")]
750 pub(crate) unsafe fn into_raw(mut self) -> RawStatement {
751 let mut stmt = RawStatement::new(ptr::null_mut());
752 mem::swap(&mut stmt, &mut self.stmt);
753 stmt
754 }
755
756 /// Reset all bindings
757 pub fn clear_bindings(&mut self) {
758 self.stmt.clear_bindings();
759 }
760
761 pub(crate) unsafe fn ptr(&self) -> *mut ffi::sqlite3_stmt {
762 self.stmt.ptr()
763 }
764}
765
766impl fmt::Debug for Statement<'_> {
767 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
768 let sql = if self.stmt.is_null() {
769 Ok("")
770 } else {
771 self.stmt.sql().unwrap().to_str()
772 };
773 f.debug_struct("Statement")
774 .field("conn", self.conn)
775 .field("stmt", &self.stmt)
776 .field("sql", &sql)
777 .finish()
778 }
779}
780
781impl Drop for Statement<'_> {
782 #[expect(unused_must_use)]
783 #[inline]
784 fn drop(&mut self) {
785 self.finalize_();
786 }
787}
788
789impl Statement<'_> {
790 #[inline]
791 pub(super) fn new(conn: &Connection, stmt: RawStatement) -> Statement<'_> {
792 Statement { conn, stmt }
793 }
794
795 pub(super) fn value_ref(&self, col: usize) -> ValueRef<'_> {
796 let raw = unsafe { self.stmt.ptr() };
797
798 match self.stmt.column_type(col) {
799 ffi::SQLITE_NULL => ValueRef::Null,
800 ffi::SQLITE_INTEGER => {
801 ValueRef::Integer(unsafe { ffi::sqlite3_column_int64(raw, col as c_int) })
802 }
803 ffi::SQLITE_FLOAT => {
804 ValueRef::Real(unsafe { ffi::sqlite3_column_double(raw, col as c_int) })
805 }
806 ffi::SQLITE_TEXT => {
807 let s = unsafe {
808 // Quoting from "Using SQLite" book:
809 // To avoid problems, an application should first extract the desired type using
810 // a sqlite3_column_xxx() function, and then call the
811 // appropriate sqlite3_column_bytes() function.
812 let text = ffi::sqlite3_column_text(raw, col as c_int);
813 let len = ffi::sqlite3_column_bytes(raw, col as c_int);
814 assert!(
815 !text.is_null(),
816 "unexpected SQLITE_TEXT column type with NULL data"
817 );
818 from_raw_parts(text.cast::<u8>(), len as usize)
819 };
820
821 ValueRef::Text(s)
822 }
823 ffi::SQLITE_BLOB => {
824 let (blob, len) = unsafe {
825 (
826 ffi::sqlite3_column_blob(raw, col as c_int),
827 ffi::sqlite3_column_bytes(raw, col as c_int),
828 )
829 };
830
831 assert!(
832 len >= 0,
833 "unexpected negative return from sqlite3_column_bytes"
834 );
835 if len > 0 {
836 assert!(
837 !blob.is_null(),
838 "unexpected SQLITE_BLOB column type with NULL data"
839 );
840 ValueRef::Blob(unsafe { from_raw_parts(blob.cast::<u8>(), len as usize) })
841 } else {
842 // The return value from sqlite3_column_blob() for a zero-length BLOB
843 // is a NULL pointer.
844 ValueRef::Blob(&[])
845 }
846 }
847 _ => unreachable!("sqlite3_column_type returned invalid value"),
848 }
849 }
850
851 #[inline]
852 pub(super) fn step(&self) -> Result<bool> {
853 match self.stmt.step() {
854 ffi::SQLITE_ROW => Ok(true),
855 ffi::SQLITE_DONE => Ok(false),
856 code => Err(self.conn.decode_result(code).unwrap_err()),
857 }
858 }
859
860 #[inline]
861 pub(super) fn reset(&self) -> Result<()> {
862 match self.stmt.reset() {
863 ffi::SQLITE_OK => Ok(()),
864 code => Err(self.conn.decode_result(code).unwrap_err()),
865 }
866 }
867}
868
869/// Prepared statement status counters.
870///
871/// See `https://www.sqlite.org/c3ref/c_stmtstatus_counter.html`
872/// for explanations of each.
873///
874/// Note that depending on your version of SQLite, all of these
875/// may not be available.
876#[repr(i32)]
877#[derive(Clone, Copy, PartialEq, Eq)]
878#[non_exhaustive]
879pub enum StatementStatus {
880 /// Equivalent to `SQLITE_STMTSTATUS_FULLSCAN_STEP`
881 FullscanStep = 1,
882 /// Equivalent to `SQLITE_STMTSTATUS_SORT`
883 Sort = 2,
884 /// Equivalent to `SQLITE_STMTSTATUS_AUTOINDEX`
885 AutoIndex = 3,
886 /// Equivalent to `SQLITE_STMTSTATUS_VM_STEP`
887 VmStep = 4,
888 /// Equivalent to `SQLITE_STMTSTATUS_REPREPARE` (3.20.0)
889 RePrepare = 5,
890 /// Equivalent to `SQLITE_STMTSTATUS_RUN` (3.20.0)
891 Run = 6,
892 /// Equivalent to `SQLITE_STMTSTATUS_FILTER_MISS`
893 FilterMiss = 7,
894 /// Equivalent to `SQLITE_STMTSTATUS_FILTER_HIT`
895 FilterHit = 8,
896 /// Equivalent to `SQLITE_STMTSTATUS_MEMUSED` (3.20.0)
897 MemUsed = 99,
898}
899
900#[cfg(test)]
901mod test {
902 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
903 use wasm_bindgen_test::wasm_bindgen_test as test;
904
905 use crate::types::ToSql;
906 use crate::{params_from_iter, Connection, Error, Result};
907
908 #[test]
909 fn test_execute_named() -> Result<()> {
910 let db = Connection::open_in_memory()?;
911 db.execute_batch("CREATE TABLE foo(x INTEGER)")?;
912
913 assert_eq!(
914 db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)])?,
915 1
916 );
917 assert_eq!(
918 db.execute("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)])?,
919 1
920 );
921 assert_eq!(
922 db.execute(
923 "INSERT INTO foo(x) VALUES (:x)",
924 crate::named_params! {":x": 3i32}
925 )?,
926 1
927 );
928
929 assert_eq!(
930 6i32,
931 db.query_row::<i32, _, _>(
932 "SELECT SUM(x) FROM foo WHERE x > :x",
933 &[(":x", &0i32)],
934 |r| r.get(0)
935 )?
936 );
937 assert_eq!(
938 5i32,
939 db.query_row::<i32, _, _>(
940 "SELECT SUM(x) FROM foo WHERE x > :x",
941 &[(":x", &1i32)],
942 |r| r.get(0)
943 )?
944 );
945 Ok(())
946 }
947
948 #[test]
949 fn test_stmt_execute_named() -> Result<()> {
950 let db = Connection::open_in_memory()?;
951 let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag \
952 INTEGER)";
953 db.execute_batch(sql)?;
954
955 let mut stmt = db.prepare("INSERT INTO test (name) VALUES (:name)")?;
956 stmt.execute(&[(":name", "one")])?;
957 stmt.execute(vec![(":name", "one")].as_slice())?;
958
959 let mut stmt = db.prepare("SELECT COUNT(*) FROM test WHERE name = :name")?;
960 assert_eq!(
961 2i32,
962 stmt.query_row::<i32, _, _>(&[(":name", "one")], |r| r.get(0))?
963 );
964 Ok(())
965 }
966
967 #[test]
968 fn test_query_named() -> Result<()> {
969 let db = Connection::open_in_memory()?;
970 let sql = r#"
971 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
972 INSERT INTO test(id, name) VALUES (1, "one");
973 "#;
974 db.execute_batch(sql)?;
975
976 let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
977 let mut rows = stmt.query(&[(":name", "one")])?;
978 let id: Result<i32> = rows.next()?.unwrap().get(0);
979 assert_eq!(Ok(1), id);
980 Ok(())
981 }
982
983 #[test]
984 fn test_query_map_named() -> Result<()> {
985 let db = Connection::open_in_memory()?;
986 let sql = r#"
987 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
988 INSERT INTO test(id, name) VALUES (1, "one");
989 "#;
990 db.execute_batch(sql)?;
991
992 let mut stmt = db.prepare("SELECT id FROM test where name = :name")?;
993 let mut rows = stmt.query_map(&[(":name", "one")], |row| {
994 let id: Result<i32> = row.get(0);
995 id.map(|i| 2 * i)
996 })?;
997
998 let doubled_id: i32 = rows.next().unwrap()?;
999 assert_eq!(2, doubled_id);
1000 Ok(())
1001 }
1002
1003 #[test]
1004 fn test_query_and_then_by_name() -> Result<()> {
1005 let db = Connection::open_in_memory()?;
1006 let sql = r#"
1007 CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER);
1008 INSERT INTO test(id, name) VALUES (1, "one");
1009 INSERT INTO test(id, name) VALUES (2, "one");
1010 "#;
1011 db.execute_batch(sql)?;
1012
1013 let mut stmt = db.prepare("SELECT id FROM test where name = :name ORDER BY id ASC")?;
1014 let mut rows = stmt.query_and_then(&[(":name", "one")], |row| {
1015 let id: i32 = row.get(0)?;
1016 if id == 1 {
1017 Ok(id)
1018 } else {
1019 Err(Error::SqliteSingleThreadedMode)
1020 }
1021 })?;
1022
1023 // first row should be Ok
1024 let doubled_id: i32 = rows.next().unwrap()?;
1025 assert_eq!(1, doubled_id);
1026
1027 // second row should be an `Err`
1028 #[expect(clippy::match_wild_err_arm)]
1029 match rows.next().unwrap() {
1030 Ok(_) => panic!("invalid Ok"),
1031 Err(Error::SqliteSingleThreadedMode) => (),
1032 Err(_) => panic!("invalid Err"),
1033 }
1034 Ok(())
1035 }
1036
1037 #[test]
1038 fn test_unbound_parameters_are_null() -> Result<()> {
1039 let db = Connection::open_in_memory()?;
1040 let sql = "CREATE TABLE test (x TEXT, y TEXT)";
1041 db.execute_batch(sql)?;
1042
1043 let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
1044 stmt.execute(&[(":x", "one")])?;
1045
1046 let result: Option<String> = db.one_column("SELECT y FROM test WHERE x = 'one'", [])?;
1047 assert!(result.is_none());
1048 Ok(())
1049 }
1050
1051 #[test]
1052 fn test_raw_binding() -> Result<()> {
1053 let db = Connection::open_in_memory()?;
1054 db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?;
1055 {
1056 let mut stmt = db.prepare("INSERT INTO test (name, value) VALUES (:name, ?3)")?;
1057
1058 stmt.raw_bind_parameter(c":name", "example")?;
1059 stmt.raw_bind_parameter(":name", "example")?;
1060 stmt.raw_bind_parameter(3, 50i32)?;
1061 let n = stmt.raw_execute()?;
1062 assert_eq!(n, 1);
1063 }
1064
1065 {
1066 let mut stmt = db.prepare("SELECT name, value FROM test WHERE value = ?2")?;
1067 stmt.raw_bind_parameter(2, 50)?;
1068 let mut rows = stmt.raw_query();
1069 {
1070 let row = rows.next()?.unwrap();
1071 let name: String = row.get(0)?;
1072 assert_eq!(name, "example");
1073 let value: i32 = row.get(1)?;
1074 assert_eq!(value, 50);
1075 }
1076 assert!(rows.next()?.is_none());
1077 }
1078
1079 Ok(())
1080 }
1081
1082 #[test]
1083 fn test_unbound_parameters_are_reused() -> Result<()> {
1084 let db = Connection::open_in_memory()?;
1085 let sql = "CREATE TABLE test (x TEXT, y TEXT)";
1086 db.execute_batch(sql)?;
1087
1088 let mut stmt = db.prepare("INSERT INTO test (x, y) VALUES (:x, :y)")?;
1089 stmt.execute(&[(":x", "one")])?;
1090 stmt.execute(&[(c":y", "two")])?;
1091
1092 let result: String = db.one_column("SELECT x FROM test WHERE y = 'two'", [])?;
1093 assert_eq!(result, "one");
1094 Ok(())
1095 }
1096
1097 #[test]
1098 fn test_insert() -> Result<()> {
1099 let db = Connection::open_in_memory()?;
1100 db.execute_batch("CREATE TABLE foo(x INTEGER UNIQUE)")?;
1101 let mut stmt = db.prepare("INSERT OR IGNORE INTO foo (x) VALUES (?1)")?;
1102 assert_eq!(stmt.insert([1i32])?, 1);
1103 assert_eq!(stmt.insert([2i32])?, 2);
1104 match stmt.insert([1i32]).unwrap_err() {
1105 Error::StatementChangedRows(0) => (),
1106 err => panic!("Unexpected error {err}"),
1107 }
1108 let mut multi = db.prepare("INSERT INTO foo (x) SELECT 3 UNION ALL SELECT 4")?;
1109 match multi.insert([]).unwrap_err() {
1110 Error::StatementChangedRows(2) => (),
1111 err => panic!("Unexpected error {err}"),
1112 }
1113 Ok(())
1114 }
1115
1116 #[test]
1117 fn test_insert_different_tables() -> Result<()> {
1118 // Test for https://github.com/rusqlite/rusqlite/issues/171
1119 let db = Connection::open_in_memory()?;
1120 db.execute_batch(
1121 r"
1122 CREATE TABLE foo(x INTEGER);
1123 CREATE TABLE bar(x INTEGER);
1124 ",
1125 )?;
1126
1127 assert_eq!(db.prepare("INSERT INTO foo VALUES (10)")?.insert([])?, 1);
1128 assert_eq!(db.prepare("INSERT INTO bar VALUES (10)")?.insert([])?, 1);
1129 Ok(())
1130 }
1131
1132 #[test]
1133 fn test_exists() -> Result<()> {
1134 let db = Connection::open_in_memory()?;
1135 let sql = "BEGIN;
1136 CREATE TABLE foo(x INTEGER);
1137 INSERT INTO foo VALUES(1);
1138 INSERT INTO foo VALUES(2);
1139 END;";
1140 db.execute_batch(sql)?;
1141 let mut stmt = db.prepare("SELECT 1 FROM foo WHERE x = ?1")?;
1142 assert!(stmt.exists([1i32])?);
1143 assert!(stmt.exists([2i32])?);
1144 assert!(!stmt.exists([0i32])?);
1145 Ok(())
1146 }
1147 #[test]
1148 fn test_tuple_params() -> Result<()> {
1149 let db = Connection::open_in_memory()?;
1150 let s = db.query_row("SELECT printf('[%s]', ?1)", ("abc",), |r| {
1151 r.get::<_, String>(0)
1152 })?;
1153 assert_eq!(s, "[abc]");
1154 let s = db.query_row(
1155 "SELECT printf('%d %s %d', ?1, ?2, ?3)",
1156 (1i32, "abc", 2i32),
1157 |r| r.get::<_, String>(0),
1158 )?;
1159 assert_eq!(s, "1 abc 2");
1160 let s = db.query_row(
1161 "SELECT printf('%d %s %d %d', ?1, ?2, ?3, ?4)",
1162 (1, "abc", 2i32, 4i64),
1163 |r| r.get::<_, String>(0),
1164 )?;
1165 assert_eq!(s, "1 abc 2 4");
1166 #[rustfmt::skip]
1167 let bigtup = (
1168 0, "a", 1, "b", 2, "c", 3, "d",
1169 4, "e", 5, "f", 6, "g", 7, "h",
1170 );
1171 let query = "SELECT printf(
1172 '%d %s | %d %s | %d %s | %d %s || %d %s | %d %s | %d %s | %d %s',
1173 ?1, ?2, ?3, ?4,
1174 ?5, ?6, ?7, ?8,
1175 ?9, ?10, ?11, ?12,
1176 ?13, ?14, ?15, ?16
1177 )";
1178 let s = db.query_row(query, bigtup, |r| r.get::<_, String>(0))?;
1179 assert_eq!(s, "0 a | 1 b | 2 c | 3 d || 4 e | 5 f | 6 g | 7 h");
1180 Ok(())
1181 }
1182
1183 #[test]
1184 fn test_query_row() -> Result<()> {
1185 let db = Connection::open_in_memory()?;
1186 let sql = "BEGIN;
1187 CREATE TABLE foo(x INTEGER, y INTEGER);
1188 INSERT INTO foo VALUES(1, 3);
1189 INSERT INTO foo VALUES(2, 4);
1190 END;";
1191 db.execute_batch(sql)?;
1192 let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?1")?;
1193 let y: Result<i64> = stmt.query_row([1i32], |r| r.get(0));
1194 assert_eq!(3i64, y?);
1195 Ok(())
1196 }
1197
1198 #[test]
1199 fn query_one() -> Result<()> {
1200 let db = Connection::open_in_memory()?;
1201 db.execute_batch("CREATE TABLE foo(x INTEGER, y INTEGER);")?;
1202 let mut stmt = db.prepare("SELECT y FROM foo WHERE x = ?1")?;
1203 let y: Result<i64> = stmt.query_one([1i32], |r| r.get(0));
1204 assert_eq!(Error::QueryReturnedNoRows, y.unwrap_err());
1205 db.execute_batch("INSERT INTO foo VALUES(1, 3);")?;
1206 let y: Result<i64> = stmt.query_one([1i32], |r| r.get(0));
1207 assert_eq!(3i64, y?);
1208 db.execute_batch("INSERT INTO foo VALUES(1, 3);")?;
1209 let y: Result<i64> = stmt.query_one([1i32], |r| r.get(0));
1210 assert_eq!(Error::QueryReturnedMoreThanOneRow, y.unwrap_err());
1211 Ok(())
1212 }
1213
1214 #[test]
1215 fn test_query_by_column_name() -> Result<()> {
1216 let db = Connection::open_in_memory()?;
1217 let sql = "BEGIN;
1218 CREATE TABLE foo(x INTEGER, y INTEGER);
1219 INSERT INTO foo VALUES(1, 3);
1220 END;";
1221 db.execute_batch(sql)?;
1222 let mut stmt = db.prepare("SELECT y FROM foo")?;
1223 let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
1224 assert_eq!(3i64, y?);
1225 Ok(())
1226 }
1227
1228 #[test]
1229 fn test_query_by_column_name_ignore_case() -> Result<()> {
1230 let db = Connection::open_in_memory()?;
1231 let sql = "BEGIN;
1232 CREATE TABLE foo(x INTEGER, y INTEGER);
1233 INSERT INTO foo VALUES(1, 3);
1234 END;";
1235 db.execute_batch(sql)?;
1236 let mut stmt = db.prepare("SELECT y as Y FROM foo")?;
1237 let y: Result<i64> = stmt.query_row([], |r| r.get("y"));
1238 assert_eq!(3i64, y?);
1239 Ok(())
1240 }
1241
1242 #[test]
1243 fn test_expanded_sql() -> Result<()> {
1244 let db = Connection::open_in_memory()?;
1245 let stmt = db.prepare("SELECT ?1")?;
1246 stmt.bind_parameter(&1, 1)?;
1247 assert_eq!(Some("SELECT 1".to_owned()), stmt.expanded_sql());
1248 Ok(())
1249 }
1250
1251 #[test]
1252 fn test_bind_parameters() -> Result<()> {
1253 let db = Connection::open_in_memory()?;
1254 // dynamic slice:
1255 db.query_row(
1256 "SELECT ?1, ?2, ?3",
1257 [&1u8 as &dyn ToSql, &"one", &Some("one")],
1258 |row| row.get::<_, u8>(0),
1259 )?;
1260 // existing collection:
1261 let data = vec![1, 2, 3];
1262 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1263 row.get::<_, u8>(0)
1264 })?;
1265 db.query_row(
1266 "SELECT ?1, ?2, ?3",
1267 params_from_iter(data.as_slice()),
1268 |row| row.get::<_, u8>(0),
1269 )?;
1270 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data), |row| {
1271 row.get::<_, u8>(0)
1272 })?;
1273
1274 use std::collections::BTreeSet;
1275 let data: BTreeSet<String> = ["one", "two", "three"]
1276 .iter()
1277 .map(|s| (*s).to_string())
1278 .collect();
1279 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1280 row.get::<_, String>(0)
1281 })?;
1282
1283 let data = [0; 3];
1284 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(&data), |row| {
1285 row.get::<_, u8>(0)
1286 })?;
1287 db.query_row("SELECT ?1, ?2, ?3", params_from_iter(data.iter()), |row| {
1288 row.get::<_, u8>(0)
1289 })?;
1290 Ok(())
1291 }
1292
1293 #[test]
1294 fn test_parameter_name() -> Result<()> {
1295 let db = Connection::open_in_memory()?;
1296 db.execute_batch("CREATE TABLE test (name TEXT, value INTEGER)")?;
1297 let stmt = db.prepare("INSERT INTO test (name, value) VALUES (:name, ?3)")?;
1298 assert_eq!(stmt.parameter_name(0), None);
1299 assert_eq!(stmt.parameter_name(1), Some(":name"));
1300 assert_eq!(stmt.parameter_name(2), None);
1301 Ok(())
1302 }
1303
1304 #[test]
1305 fn test_empty_stmt() -> Result<()> {
1306 let conn = Connection::open_in_memory()?;
1307 let mut stmt = conn.prepare("")?;
1308 assert_eq!(0, stmt.column_count());
1309 stmt.parameter_index("test")?;
1310 let err = stmt.step().unwrap_err();
1311 assert_eq!(err.sqlite_error_code(), Some(crate::ErrorCode::ApiMisuse));
1312 // error msg is different with sqlcipher, so we use assert_ne:
1313 assert_ne!(err.to_string(), "not an error".to_owned());
1314 stmt.reset()?; // SQLITE_OMIT_AUTORESET = false
1315 stmt.execute([]).unwrap_err();
1316 Ok(())
1317 }
1318
1319 #[test]
1320 fn test_comment_stmt() -> Result<()> {
1321 let conn = Connection::open_in_memory()?;
1322 conn.prepare("/*SELECT 1;*/")?;
1323 Ok(())
1324 }
1325
1326 #[test]
1327 fn test_comment_and_sql_stmt() -> Result<()> {
1328 let conn = Connection::open_in_memory()?;
1329 let stmt = conn.prepare("/*...*/ SELECT 1;")?;
1330 assert_eq!(1, stmt.column_count());
1331 Ok(())
1332 }
1333
1334 #[test]
1335 fn test_semi_colon_stmt() -> Result<()> {
1336 let conn = Connection::open_in_memory()?;
1337 let stmt = conn.prepare(";")?;
1338 assert_eq!(0, stmt.column_count());
1339 Ok(())
1340 }
1341
1342 #[test]
1343 fn test_utf16_conversion() -> Result<()> {
1344 let db = Connection::open_in_memory()?;
1345 db.pragma_update(None, "encoding", "UTF-16le")?;
1346 let encoding: String = db.pragma_query_value(None, "encoding", |row| row.get(0))?;
1347 assert_eq!("UTF-16le", encoding);
1348 db.execute_batch("CREATE TABLE foo(x TEXT)")?;
1349 let expected = "ใในใ";
1350 db.execute("INSERT INTO foo(x) VALUES (?1)", [&expected])?;
1351 let actual: String = db.one_column("SELECT x FROM foo", [])?;
1352 assert_eq!(expected, actual);
1353 Ok(())
1354 }
1355
1356 #[test]
1357 fn test_nul_byte() -> Result<()> {
1358 let db = Connection::open_in_memory()?;
1359 let expected = "a\x00b";
1360 let actual: String = db.one_column("SELECT ?1", [expected])?;
1361 assert_eq!(expected, actual);
1362 Ok(())
1363 }
1364
1365 #[test]
1366 fn is_explain() -> Result<()> {
1367 let db = Connection::open_in_memory()?;
1368 let stmt = db.prepare("SELECT 1;")?;
1369 assert_eq!(0, stmt.is_explain());
1370 Ok(())
1371 }
1372
1373 #[test]
1374 fn readonly() -> Result<()> {
1375 let db = Connection::open_in_memory()?;
1376 let stmt = db.prepare("SELECT 1;")?;
1377 assert!(stmt.readonly());
1378 Ok(())
1379 }
1380
1381 #[test]
1382 #[cfg(feature = "modern_sqlite")] // SQLite >= 3.38.0
1383 fn test_error_offset() -> Result<()> {
1384 use crate::ffi::ErrorCode;
1385 let db = Connection::open_in_memory()?;
1386 let r = db.execute_batch("SELECT INVALID_FUNCTION;");
1387 match r.unwrap_err() {
1388 Error::SqlInputError { error, offset, .. } => {
1389 assert_eq!(error.code, ErrorCode::Unknown);
1390 assert_eq!(offset, 7);
1391 }
1392 err => panic!("Unexpected error {err}"),
1393 }
1394 Ok(())
1395 }
1396}