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::Other(err) => {
296                Error::FromSqlConversionFailure(idx, value.data_type(), err)
297            }
298            FromSqlError::InvalidBlobSize { .. } => {
299                Error::FromSqlConversionFailure(idx, value.data_type(), Box::new(err))
300            }
301        })
302    }
303
304    /// Get the value of a particular column of the result row as a `ValueRef`,
305    /// allowing data to be read out of a row without copying.
306    ///
307    /// This `ValueRef` is valid only as long as this Row, which is enforced by
308    /// its lifetime. This means that while this method is completely safe,
309    /// it can be somewhat difficult to use, and most callers will be better
310    /// served by [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
311    ///
312    /// ## Failure
313    ///
314    /// Returns an `Error::InvalidColumnIndex` if `idx` is outside the valid
315    /// column range for this row.
316    ///
317    /// Returns an `Error::InvalidColumnName` if `idx` is not a valid column
318    /// name for this row.
319    pub fn get_ref<I: RowIndex>(&self, idx: I) -> Result<ValueRef<'_>> {
320        let idx = idx.idx(self.stmt)?;
321        // Narrowing from `ValueRef<'stmt>` (which `self.stmt.value_ref(idx)`
322        // returns) to `ValueRef<'a>` is needed because it's only valid until
323        // the next call to sqlite3_step.
324        let val_ref = self.stmt.value_ref(idx);
325        Ok(val_ref)
326    }
327
328    /// Get the value of a particular column of the result row as a `ValueRef`,
329    /// allowing data to be read out of a row without copying.
330    ///
331    /// This `ValueRef` is valid only as long as this Row, which is enforced by
332    /// its lifetime. This means that while this method is completely safe,
333    /// it can be difficult to use, and most callers will be better served by
334    /// [`get`](Row::get) or [`get_unwrap`](Row::get_unwrap).
335    ///
336    /// # Panics
337    ///
338    /// Panics if calling [`row.get_ref(idx)`](Row::get_ref) would return an
339    /// error, including:
340    ///
341    /// * If `idx` is outside the range of columns in the returned query.
342    /// * If `idx` is not a valid column name for this row.
343    #[track_caller]
344    pub fn get_ref_unwrap<I: RowIndex>(&self, idx: I) -> ValueRef<'_> {
345        self.get_ref(idx).unwrap()
346    }
347}
348
349impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
350    fn as_ref(&self) -> &Statement<'stmt> {
351        self.stmt
352    }
353}
354
355/// Debug `Row` like an ordered `Map<Result<&str>, Result<(Type, ValueRef)>>`
356/// with column name as key except that for `Type::Blob` only its size is
357/// printed (not its content).
358impl std::fmt::Debug for Row<'_> {
359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360        let mut dm = f.debug_map();
361        for c in 0..self.stmt.column_count() {
362            let name = self.stmt.column_name(c).expect("valid column index");
363            dm.key(&name);
364            let value = self.get_ref(c);
365            match value {
366                Ok(value) => {
367                    let dt = value.data_type();
368                    match value {
369                        ValueRef::Null => {
370                            dm.value(&(dt, ()));
371                        }
372                        ValueRef::Integer(i) => {
373                            dm.value(&(dt, i));
374                        }
375                        ValueRef::Real(f) => {
376                            dm.value(&(dt, f));
377                        }
378                        ValueRef::Text(s) => {
379                            dm.value(&(dt, String::from_utf8_lossy(s)));
380                        }
381                        ValueRef::Blob(b) => {
382                            dm.value(&(dt, b.len()));
383                        }
384                    }
385                }
386                Err(ref _err) => {
387                    dm.value(&value);
388                }
389            }
390        }
391        dm.finish()
392    }
393}
394
395mod sealed {
396    /// This trait exists just to ensure that the only impls of `trait RowIndex`
397    /// that are allowed are ones in this crate.
398    pub trait Sealed {}
399    impl Sealed for usize {}
400    impl Sealed for &str {}
401}
402
403/// A trait implemented by types that can index into columns of a row.
404///
405/// It is only implemented for `usize` and `&str`.
406pub trait RowIndex: sealed::Sealed {
407    /// Returns the index of the appropriate column, or `Error` if no such
408    /// column exists.
409    fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
410}
411
412impl RowIndex for usize {
413    #[inline]
414    fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
415        if *self >= stmt.column_count() {
416            Err(Error::InvalidColumnIndex(*self))
417        } else {
418            Ok(*self)
419        }
420    }
421}
422
423impl RowIndex for &'_ str {
424    #[inline]
425    fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
426        stmt.column_index(self)
427    }
428}
429
430macro_rules! tuple_try_from_row {
431    ($($field:ident),*) => {
432        impl<'a, $($field,)*> convert::TryFrom<&'a Row<'a>> for ($($field,)*) where $($field: FromSql,)* {
433            type Error = crate::Error;
434
435            // we end with index += 1, which rustc warns about
436            // unused_variables and unused_mut are allowed for ()
437            #[allow(unused_assignments, unused_variables, unused_mut)]
438            fn try_from(row: &'a Row<'a>) -> Result<Self> {
439                let mut index = 0;
440                $(
441                    #[expect(non_snake_case)]
442                    let $field = row.get::<_, $field>(index)?;
443                    index += 1;
444                )*
445                Ok(($($field,)*))
446            }
447        }
448    }
449}
450
451macro_rules! tuples_try_from_row {
452    () => {
453        // not very useful, but maybe some other macro users will find this helpful
454        tuple_try_from_row!();
455    };
456    ($first:ident $(, $remaining:ident)*) => {
457        tuple_try_from_row!($first $(, $remaining)*);
458        tuples_try_from_row!($($remaining),*);
459    };
460}
461
462tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
463
464#[cfg(test)]
465mod tests {
466    use crate::{Connection, Result};
467
468    #[test]
469    fn test_try_from_row_for_tuple_1() -> Result<()> {
470        use crate::ToSql;
471        use std::convert::TryFrom;
472
473        let conn = Connection::open_in_memory()?;
474        conn.execute(
475            "CREATE TABLE test (a INTEGER)",
476            crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
477        )?;
478        conn.execute("INSERT INTO test VALUES (42)", [])?;
479        let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
480        assert_eq!(val, (42,));
481        let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
482        fail.unwrap_err();
483        Ok(())
484    }
485
486    #[test]
487    fn test_try_from_row_for_tuple_2() -> Result<()> {
488        use std::convert::TryFrom;
489
490        let conn = Connection::open_in_memory()?;
491        conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
492        conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
493        let val = conn.query_row("SELECT a, b FROM test", [], |row| {
494            <(u32, u32)>::try_from(row)
495        })?;
496        assert_eq!(val, (42, 47));
497        let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
498            <(u32, u32, u32)>::try_from(row)
499        });
500        fail.unwrap_err();
501        Ok(())
502    }
503
504    #[test]
505    fn test_try_from_row_for_tuple_16() -> Result<()> {
506        use std::convert::TryFrom;
507
508        let create_table = "CREATE TABLE test (
509            a INTEGER,
510            b INTEGER,
511            c INTEGER,
512            d INTEGER,
513            e INTEGER,
514            f INTEGER,
515            g INTEGER,
516            h INTEGER,
517            i INTEGER,
518            j INTEGER,
519            k INTEGER,
520            l INTEGER,
521            m INTEGER,
522            n INTEGER,
523            o INTEGER,
524            p INTEGER
525        )";
526
527        let insert_values = "INSERT INTO test VALUES (
528            0,
529            1,
530            2,
531            3,
532            4,
533            5,
534            6,
535            7,
536            8,
537            9,
538            10,
539            11,
540            12,
541            13,
542            14,
543            15
544        )";
545
546        type BigTuple = (
547            u32,
548            u32,
549            u32,
550            u32,
551            u32,
552            u32,
553            u32,
554            u32,
555            u32,
556            u32,
557            u32,
558            u32,
559            u32,
560            u32,
561            u32,
562            u32,
563        );
564
565        let conn = Connection::open_in_memory()?;
566        conn.execute(create_table, [])?;
567        conn.execute(insert_values, [])?;
568        let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
569        // Debug is not implemented for tuples of 16
570        assert_eq!(val.0, 0);
571        assert_eq!(val.1, 1);
572        assert_eq!(val.2, 2);
573        assert_eq!(val.3, 3);
574        assert_eq!(val.4, 4);
575        assert_eq!(val.5, 5);
576        assert_eq!(val.6, 6);
577        assert_eq!(val.7, 7);
578        assert_eq!(val.8, 8);
579        assert_eq!(val.9, 9);
580        assert_eq!(val.10, 10);
581        assert_eq!(val.11, 11);
582        assert_eq!(val.12, 12);
583        assert_eq!(val.13, 13);
584        assert_eq!(val.14, 14);
585        assert_eq!(val.15, 15);
586
587        // We don't test one bigger because it's unimplemented
588        Ok(())
589    }
590
591    #[test]
592    #[cfg(feature = "bundled")]
593    fn pathological_case() -> Result<()> {
594        let conn = Connection::open_in_memory()?;
595        conn.execute_batch(
596            "CREATE TABLE foo(x);
597        CREATE TRIGGER oops BEFORE INSERT ON foo BEGIN SELECT RAISE(FAIL, 'Boom'); END;",
598        )?;
599        let mut stmt = conn.prepare("INSERT INTO foo VALUES (0) RETURNING rowid;")?;
600        {
601            let iterator_count = stmt.query_map([], |_| Ok(()))?.count();
602            assert_eq!(1, iterator_count); // should be 0
603            use fallible_streaming_iterator::FallibleStreamingIterator;
604            let fallible_iterator_count = stmt.query([])?.count().unwrap_or(0);
605            assert_eq!(0, fallible_iterator_count);
606        }
607        {
608            let iterator_last = stmt.query_map([], |_| Ok(()))?.last();
609            assert!(iterator_last.is_some()); // should be none
610            use fallible_iterator::FallibleIterator;
611            let fallible_iterator_last = stmt.query([])?.map(|_| Ok(())).last();
612            assert!(fallible_iterator_last.is_err());
613        }
614        Ok(())
615    }
616
617    #[test]
618    fn as_ref() -> Result<()> {
619        let conn = Connection::open_in_memory()?;
620        let mut stmt = conn.prepare("SELECT 'Lisa' as name, 1 as id")?;
621        let rows = stmt.query([])?;
622        assert_eq!(rows.as_ref().unwrap().column_count(), 2);
623        Ok(())
624    }
625
626    #[test]
627    fn debug() -> Result<()> {
628        let conn = Connection::open_in_memory()?;
629        let mut stmt = conn.prepare(
630            "SELECT 'Lisa' as name, 1 as id, 3.14 as pi, X'53514C697465' as blob, NULL as void",
631        )?;
632        let mut rows = stmt.query([])?;
633        let row = rows.next()?.unwrap();
634        let s = format!("{row:?}");
635        assert_eq!(
636            s,
637            r#"{"name": (Text, "Lisa"), "id": (Integer, 1), "pi": (Real, 3.14), "blob": (Blob, 6), "void": (Null, ())}"#
638        );
639        Ok(())
640    }
641}