Skip to main content

rusqlite/
row.rs

1use fallible_iterator::FallibleIterator;
2use fallible_streaming_iterator::FallibleStreamingIterator;
3use std::convert;
4
5use super::{Error, Result, Statement};
6use crate::types::{FromSql, FromSqlError, ValueRef};
7
8/// A handle (lazy fallible streaming iterator) for the resulting rows of a query.
9#[must_use = "Rows is lazy and will do nothing unless consumed"]
10pub struct Rows<'stmt> {
11    pub(crate) stmt: Option<&'stmt Statement<'stmt>>,
12    row: Option<Row<'stmt>>,
13}
14
15impl<'stmt> Rows<'stmt> {
16    #[inline]
17    fn reset(&mut self) -> Result<()> {
18        if let Some(stmt) = self.stmt.take() {
19            stmt.reset()
20        } else {
21            Ok(())
22        }
23    }
24
25    /// Attempt to get the next row from the query. Returns `Ok(Some(Row))` if
26    /// there is another row, `Err(...)` if there was an error
27    /// getting the next row, and `Ok(None)` if all rows have been retrieved.
28    ///
29    /// ## Note
30    ///
31    /// This interface is not compatible with Rust's `Iterator` trait, because
32    /// the lifetime of the returned row is tied to the lifetime of `self`.
33    /// This is a fallible "streaming iterator". For a more natural interface,
34    /// consider using [`query_map`](Statement::query_map) or
35    /// [`query_and_then`](Statement::query_and_then) instead, which
36    /// return types that implement `Iterator`.
37    #[expect(clippy::should_implement_trait)] // cannot implement Iterator
38    #[inline]
39    pub fn next(&mut self) -> Result<Option<&Row<'stmt>>> {
40        self.advance()?;
41        Ok((*self).get())
42    }
43
44    /// Map over this `Rows`, converting it to a [`Map`], which
45    /// implements `FallibleIterator`.
46    /// ```rust,no_run
47    /// use fallible_iterator::FallibleIterator;
48    /// # use rusqlite::{Result, Statement};
49    /// fn query(stmt: &mut Statement) -> Result<Vec<i64>> {
50    ///     let rows = stmt.query([])?;
51    ///     rows.map(|r| r.get(0)).collect()
52    /// }
53    /// ```
54    // FIXME Hide FallibleStreamingIterator::map
55    #[inline]
56    pub fn map<F, B>(self, f: F) -> Map<'stmt, F>
57    where
58        F: FnMut(&Row<'_>) -> Result<B>,
59    {
60        Map { rows: self, f }
61    }
62
63    /// Map over this `Rows`, converting it to a [`MappedRows`], which
64    /// implements `Iterator`.
65    #[inline]
66    pub fn mapped<F, B>(self, f: F) -> MappedRows<'stmt, F>
67    where
68        F: FnMut(&Row<'_>) -> Result<B>,
69    {
70        MappedRows { rows: self, map: f }
71    }
72
73    /// Map over this `Rows` with a fallible function, converting it to a
74    /// [`AndThenRows`], which implements `Iterator` (instead of
75    /// `FallibleStreamingIterator`).
76    #[inline]
77    pub fn and_then<F, T, E>(self, f: F) -> AndThenRows<'stmt, F>
78    where
79        F: FnMut(&Row<'_>) -> Result<T, E>,
80    {
81        AndThenRows { rows: self, map: f }
82    }
83
84    /// Give access to the underlying statement
85    #[must_use]
86    pub fn as_ref(&self) -> Option<&Statement<'stmt>> {
87        self.stmt
88    }
89}
90
91impl<'stmt> Rows<'stmt> {
92    #[inline]
93    pub(crate) fn new(stmt: &'stmt Statement<'stmt>) -> Self {
94        Rows {
95            stmt: Some(stmt),
96            row: None,
97        }
98    }
99
100    #[inline]
101    pub(crate) fn get_expected_row(&mut self) -> Result<&Row<'stmt>> {
102        match self.next()? {
103            Some(row) => Ok(row),
104            None => Err(Error::QueryReturnedNoRows),
105        }
106    }
107}
108
109impl Drop for Rows<'_> {
110    #[expect(unused_must_use)]
111    #[inline]
112    fn drop(&mut self) {
113        self.reset();
114    }
115}
116
117/// `F` is used to transform the _streaming_ iterator into a _fallible_
118/// iterator.
119#[must_use = "iterators are lazy and do nothing unless consumed"]
120pub struct Map<'stmt, F> {
121    rows: Rows<'stmt>,
122    f: F,
123}
124
125impl<F, B> FallibleIterator for Map<'_, F>
126where
127    F: FnMut(&Row<'_>) -> Result<B>,
128{
129    type Error = Error;
130    type Item = B;
131
132    #[inline]
133    fn next(&mut self) -> Result<Option<B>> {
134        match self.rows.next()? {
135            Some(v) => Ok(Some((self.f)(v)?)),
136            None => Ok(None),
137        }
138    }
139}
140
141/// An iterator over the mapped resulting rows of a query.
142///
143/// `F` is used to transform the _streaming_ iterator into a _standard_
144/// iterator.
145#[must_use = "iterators are lazy and do nothing unless consumed"]
146pub struct MappedRows<'stmt, F> {
147    rows: Rows<'stmt>,
148    map: F,
149}
150
151impl<T, F> Iterator for MappedRows<'_, F>
152where
153    F: FnMut(&Row<'_>) -> Result<T>,
154{
155    type Item = Result<T>;
156
157    #[inline]
158    fn next(&mut self) -> Option<Result<T>> {
159        let map = &mut self.map;
160        self.rows
161            .next()
162            .transpose()
163            .map(|row_result| row_result.and_then(map))
164    }
165}
166
167/// An iterator over the mapped resulting rows of a query, with an Error type
168/// unifying with Error.
169#[must_use = "iterators are lazy and do nothing unless consumed"]
170pub struct AndThenRows<'stmt, F> {
171    rows: Rows<'stmt>,
172    map: F,
173}
174
175impl<T, E, F> Iterator for AndThenRows<'_, F>
176where
177    E: From<Error>,
178    F: FnMut(&Row<'_>) -> Result<T, E>,
179{
180    type Item = Result<T, E>;
181
182    #[inline]
183    fn next(&mut self) -> Option<Self::Item> {
184        let map = &mut self.map;
185        self.rows
186            .next()
187            .transpose()
188            .map(|row_result| row_result.map_err(E::from).and_then(map))
189    }
190}
191
192/// `FallibleStreamingIterator` differs from the standard library's `Iterator`
193/// in two ways:
194/// * each call to `next` (`sqlite3_step`) can fail.
195/// * returned `Row` is valid until `next` is called again or `Statement` is
196///   reset or finalized.
197///
198/// While these iterators cannot be used with Rust `for` loops, `while let`
199/// loops offer a similar level of ergonomics:
200/// ```rust,no_run
201/// # use rusqlite::{Result, Statement};
202/// fn query(stmt: &mut Statement) -> Result<()> {
203///     let mut rows = stmt.query([])?;
204///     while let Some(row) = rows.next()? {
205///         // scan columns value
206///     }
207///     Ok(())
208/// }
209/// ```
210impl<'stmt> FallibleStreamingIterator for Rows<'stmt> {
211    type Error = Error;
212    type Item = Row<'stmt>;
213
214    #[inline]
215    fn advance(&mut self) -> Result<()> {
216        if let Some(stmt) = self.stmt {
217            match stmt.step() {
218                Ok(true) => {
219                    self.row = Some(Row { stmt });
220                    Ok(())
221                }
222                Ok(false) => {
223                    let r = self.reset();
224                    self.row = None;
225                    r
226                }
227                Err(e) => {
228                    let _ = self.reset(); // prevents infinite loop on error
229                    self.row = None;
230                    Err(e)
231                }
232            }
233        } else {
234            self.row = None;
235            Ok(())
236        }
237    }
238
239    #[inline]
240    fn get(&self) -> Option<&Row<'stmt>> {
241        self.row.as_ref()
242    }
243}
244
245/// A single result row of a query.
246pub struct Row<'stmt> {
247    pub(crate) stmt: &'stmt Statement<'stmt>,
248}
249
250impl Row<'_> {
251    /// Get the value of a particular column of the result row.
252    ///
253    /// # Panics
254    ///
255    /// Panics if calling [`row.get(idx)`](Row::get) would return an error,
256    /// including:
257    ///
258    /// * If the underlying SQLite column type is not a valid type as a source
259    ///   for `T`
260    /// * If the underlying SQLite integral value is outside the range
261    ///   representable by `T`
262    /// * If `idx` is outside the range of columns in the returned query
263    #[track_caller]
264    pub fn get_unwrap<I: RowIndex, T: FromSql>(&self, idx: I) -> T {
265        self.get(idx).unwrap()
266    }
267
268    /// Get the value of a particular column of the result row.
269    ///
270    /// ## Failure
271    ///
272    /// Returns an `Error::InvalidColumnType` if the underlying SQLite column
273    /// type is not a valid type as a source for `T`.
274    ///
275    /// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
276    /// column range for this row.
277    ///
278    /// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
279    /// name for this row.
280    ///
281    /// If the result type is i128 (which requires the `i128_blob` feature to be
282    /// enabled), and the underlying SQLite column is a blob whose size is not
283    /// 16 bytes, `Error::InvalidColumnType` will also be returned.
284    #[track_caller]
285    pub fn get<I: RowIndex, T: FromSql>(&self, idx: I) -> Result<T> {
286        let idx = idx.idx(self.stmt)?;
287        let value = self.stmt.value_ref(idx);
288        FromSql::column_result(value).map_err(|err| match err {
289            FromSqlError::InvalidType => Error::InvalidColumnType(
290                idx,
291                self.stmt.column_name_unwrap(idx).into(),
292                value.data_type(),
293            ),
294            FromSqlError::OutOfRange(i) => Error::IntegralValueOutOfRange(idx, i),
295            FromSqlError::Utf8Error(err) => Error::Utf8Error(idx, err),
296            FromSqlError::Other(err) => {
297                Error::FromSqlConversionFailure(idx, value.data_type(), err)
298            }
299            FromSqlError::InvalidBlobSize { .. } => {
300                Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
301            }
302        })
303    }
304
305    /// Get the value of a particular column of the result row as a `ValueRef`,
306    /// allowing data to be read out of a row without copying.
307    ///
308    /// This `ValueRef` is valid only as long as this Row, which is enforced by
309    /// its lifetime. This means that while this method is completely safe,
310    /// it can be somewhat difficult to use, and most callers will be better
311    /// served by [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
312    ///
313    /// ## Failure
314    ///
315    /// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
316    /// column range for this row.
317    ///
318    /// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
319    /// name for this row.
320    pub fn get_ref<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'_>> {
321        let idx = idx.idx(self.stmt)?;
322        // Narrowing from `ValueRef<'stmt>` (which `self.stmt.value_ref(idx)`
323        // returns) to `ValueRef<'a>` is needed because it's only valid until
324        // the next call to sqlite3_step.
325        let val_ref = self.stmt.value_ref(idx);
326        Ok(val_ref)
327    }
328
329    /// Get the value of a particular column of the result row as a `ValueRef`,
330    /// allowing data to be read out of a row without copying.
331    ///
332    /// This `ValueRef` is valid only as long as this Row, which is enforced by
333    /// its lifetime. This means that while this method is completely safe,
334    /// it can be difficult to use, and most callers will be better served by
335    /// [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
336    ///
337    /// # Panics
338    ///
339    /// Panics if calling [`row.get_ref(idx)`](Row::get_ref) would return an
340    /// error, including:
341    ///
342    /// * If `idx` is outside the range of columns in the returned query.
343    /// * If `idx` is not a valid column name for this row.
344    #[track_caller]
345    pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
346        self.get_ref(idx).unwrap()
347    }
348
349    /// Return raw pointer at `idx`
350    /// # Safety
351    /// This function is unsafe because it uses raw pointer and cast
352    #[cfg(feature = "pointer")]
353    pub unsafe fn get_pointer<I: RowIndex, T: 'static>(
354        &self,
355        idx: I,
356        ptr_type: &'static std::ffi::CStr,
357    ) -> Result<Option<&T>> {
358        let idx = idx.idx(self.stmt)?;
359        debug_assert_eq!(self.stmt.stmt.column_type(idx), super::ffi::SQLITE_NULL);
360        unsafe {
361            let sv = super::ffi::sqlite3_column_value(self.stmt.stmt.ptr(), idx as std::ffi::c_int);
362            Ok(if sv.is_null() {
363                None
364            } else {
365                super::ffi::sqlite3_value_pointer(sv, ptr_type.as_ptr())
366                    .cast::<T>()
367                    .as_ref()
368            })
369        }
370    }
371}
372
373impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
374    fn as_ref(&self) -> &Statement<'stmt> {
375        self.stmt
376    }
377}
378
379/// Debug `Row` like an ordered `Map<Result<&str>, Result<(Type, ValueRef)>>`
380/// with column name as key except that for `Type::Blob` only its size is
381/// printed (not its content).
382impl std::fmt::Debug for Row<'_> {
383    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
384        let mut dm = f.debug_map();
385        for c in 0..self.stmt.column_count() {
386            let name = self.stmt.column_name(c).expect("valid column index");
387            dm.key(&name);
388            let value = self.get_ref(c);
389            match value {
390                Ok(value) => {
391                    let dt = value.data_type();
392                    match value {
393                        ValueRef::Null => {
394                            dm.value(&(dt, ()));
395                        }
396                        ValueRef::Integer(i) => {
397                            dm.value(&(dt, i));
398                        }
399                        ValueRef::Real(f) => {
400                            dm.value(&(dt, f));
401                        }
402                        ValueRef::Text(s) => {
403                            dm.value(&(dt, String::from_utf8_lossy(s)));
404                        }
405                        ValueRef::Blob(b) => {
406                            dm.value(&(dt, b.len()));
407                        }
408                    }
409                }
410                Err(ref _err) => {
411                    dm.value(&value);
412                }
413            }
414        }
415        dm.finish()
416    }
417}
418
419mod sealed {
420    /// This trait exists just to ensure that the only impls of `trait RowIndex`
421    /// that are allowed are ones in this crate.
422    pub trait Sealed {}
423    impl Sealed for usize {}
424    impl Sealed for &str {}
425}
426
427/// A trait implemented by types that can index into columns of a row.
428///
429/// It is only implemented for `usize` and `&str`.
430pub trait RowIndex: sealed::Sealed + Copy {
431    /// Returns the index of the appropriate column, or `Error` if no such
432    /// column exists.
433    fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
434}
435
436impl RowIndex for usize {
437    #[inline]
438    fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
439        if *self >= stmt.column_count() {
440            Err(Error::InvalidColumnIndex(*self))
441        } else {
442            Ok(*self)
443        }
444    }
445}
446
447impl RowIndex for &'_ str {
448    #[inline]
449    fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
450        stmt.column_index(self)
451    }
452}
453
454macro_rules! tuple_try_from_row {
455    ($($field:ident),*) => {
456        impl<'a, $($field,)*> convert::TryFrom<&'a Row<'a>> for ($($field,)*) where $($field: FromSql,)* {
457            type Error = crate::Error;
458
459            // we end with index += 1, which rustc warns about
460            // unused_variables and unused_mut are allowed for ()
461            #[allow(unused_assignments, unused_variables, unused_mut)]
462            fn try_from(row: &'a Row<'a>) -> Result<Self> {
463                let mut index = 0;
464                $(
465                    #[expect(non_snake_case)]
466                    let $field = row.get::<_, $field>(index)?;
467                    index += 1;
468                )*
469                Ok(($($field,)*))
470            }
471        }
472    }
473}
474
475macro_rules! tuples_try_from_row {
476    () => {
477        // not very useful, but maybe some other macro users will find this helpful
478        tuple_try_from_row!();
479    };
480    ($first:ident $(, $remaining:ident)*) => {
481        tuple_try_from_row!($first $(, $remaining)*);
482        tuples_try_from_row!($($remaining),*);
483    };
484}
485
486tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
487
488#[cfg(all(test, not(miri)))]
489mod tests {
490    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
491    use wasm_bindgen_test::wasm_bindgen_test as test;
492
493    use crate::{Connection, Result};
494
495    #[test]
496    fn test_try_from_row_for_tuple_1() -> Result<()> {
497        use crate::ToSql;
498        use std::convert::TryFrom as _;
499
500        let conn = Connection::open_in_memory()?;
501        conn.execute(
502            "CREATE TABLE test (a INTEGER)",
503            crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
504        )?;
505        conn.execute("INSERT INTO test VALUES (42)", [])?;
506        let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
507        assert_eq!(val, (42,));
508        let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
509        fail.unwrap_err();
510        Ok(())
511    }
512
513    #[test]
514    fn test_try_from_row_for_tuple_2() -> Result<()> {
515        use std::convert::TryFrom as _;
516
517        let conn = Connection::open_in_memory()?;
518        conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
519        conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
520        let val = conn.query_row("SELECT a, b FROM test", [], |row| {
521            <(u32, u32)>::try_from(row)
522        })?;
523        assert_eq!(val, (42, 47));
524        let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
525            <(u32, u32, u32)>::try_from(row)
526        });
527        fail.unwrap_err();
528        Ok(())
529    }
530
531    #[test]
532    fn test_try_from_row_for_tuple_16() -> Result<()> {
533        use std::convert::TryFrom as _;
534
535        let create_table = "CREATE TABLE test (
536            a INTEGER,
537            b INTEGER,
538            c INTEGER,
539            d INTEGER,
540            e INTEGER,
541            f INTEGER,
542            g INTEGER,
543            h INTEGER,
544            i INTEGER,
545            j INTEGER,
546            k INTEGER,
547            l INTEGER,
548            m INTEGER,
549            n INTEGER,
550            o INTEGER,
551            p INTEGER
552        )";
553
554        let insert_values = "INSERT INTO test VALUES (
555            0,
556            1,
557            2,
558            3,
559            4,
560            5,
561            6,
562            7,
563            8,
564            9,
565            10,
566            11,
567            12,
568            13,
569            14,
570            15
571        )";
572
573        type BigTuple = (
574            u32,
575            u32,
576            u32,
577            u32,
578            u32,
579            u32,
580            u32,
581            u32,
582            u32,
583            u32,
584            u32,
585            u32,
586            u32,
587            u32,
588            u32,
589            u32,
590        );
591
592        let conn = Connection::open_in_memory()?;
593        conn.execute(create_table, [])?;
594        conn.execute(insert_values, [])?;
595        let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
596        // Debug is not implemented for tuples of 16
597        assert_eq!(val.0, 0);
598        assert_eq!(val.1, 1);
599        assert_eq!(val.2, 2);
600        assert_eq!(val.3, 3);
601        assert_eq!(val.4, 4);
602        assert_eq!(val.5, 5);
603        assert_eq!(val.6, 6);
604        assert_eq!(val.7, 7);
605        assert_eq!(val.8, 8);
606        assert_eq!(val.9, 9);
607        assert_eq!(val.10, 10);
608        assert_eq!(val.11, 11);
609        assert_eq!(val.12, 12);
610        assert_eq!(val.13, 13);
611        assert_eq!(val.14, 14);
612        assert_eq!(val.15, 15);
613
614        // We don't test one bigger because it's unimplemented
615        Ok(())
616    }
617
618    #[test]
619    #[cfg(feature = "bundled")]
620    fn pathological_case() -> Result<()> {
621        let conn = Connection::open_in_memory()?;
622        conn.execute_batch(
623            "CREATE TABLE foo(x);
624        CREATE TRIGGER oops BEFORE INSERT ON foo BEGIN SELECT RAISE(FAIL, 'Boom'); END;",
625        )?;
626        let mut stmt = conn.prepare("INSERT INTO foo VALUES (0) RETURNING rowid;")?;
627        {
628            let iterator_count = stmt.query_map([], |_| Ok(()))?.count();
629            assert_eq!(1, iterator_count); // should be 0
630            use fallible_streaming_iterator::FallibleStreamingIterator as _;
631            let fallible_iterator_count = stmt.query([])?.count().unwrap_or(0);
632            assert_eq!(0, fallible_iterator_count);
633        }
634        {
635            let iterator_last = stmt.query_map([], |_| Ok(()))?.last();
636            assert!(iterator_last.is_some()); // should be none
637            use fallible_iterator::FallibleIterator as _;
638            let fallible_iterator_last = stmt.query([])?.map(|_| Ok(())).last();
639            assert!(fallible_iterator_last.is_err());
640        }
641        Ok(())
642    }
643
644    #[test]
645    fn as_ref() -> Result<()> {
646        let conn = Connection::open_in_memory()?;
647        let mut stmt = conn.prepare("SELECT 'Lisa' as name, 1 as id")?;
648        let rows = stmt.query([])?;
649        assert_eq!(rows.as_ref().unwrap().column_count(), 2);
650        Ok(())
651    }
652
653    #[test]
654    fn debug() -> Result<()> {
655        let conn = Connection::open_in_memory()?;
656        let mut stmt = conn.prepare(
657            "SELECT 'Lisa' as name, 1 as id, 3.14 as pi, X'53514C697465' as blob, NULL as void",
658        )?;
659        let mut rows = stmt.query([])?;
660        let row = rows.next()?.unwrap();
661        let s = format!("{row:?}");
662        assert_eq!(
663            s,
664            r#"{"name": (Text, "Lisa"), "id": (Integer, 1), "pi": (Real, 3.14), "blob": (Blob, 6), "void": (Null, ())}"#
665        );
666        Ok(())
667    }
668
669    #[test]
670    #[cfg(feature = "pointer")]
671    fn test_pointer() -> Result<()> {
672        use crate::ffi::fts5_api;
673        use crate::types::ToSqlOutput;
674        const PTR_TYPE: &std::ffi::CStr = c"fts5_api_ptr";
675        let p_ret: *mut fts5_api = std::ptr::null_mut();
676        let ptr = ToSqlOutput::Pointer((&p_ret as *const *mut fts5_api as _, PTR_TYPE, None));
677        let db = Connection::open_in_memory()?;
678        db.query_row("SELECT fts5(?)", [ptr], |_| Ok(()))?;
679        assert!(!p_ret.is_null());
680        Ok(())
681    }
682}