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::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    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
467    use wasm_bindgen_test::wasm_bindgen_test as test;
468
469    use crate::{Connection, Result};
470
471    #[test]
472    fn test_try_from_row_for_tuple_1() -> Result<()> {
473        use crate::ToSql;
474        use std::convert::TryFrom;
475
476        let conn = Connection::open_in_memory()?;
477        conn.execute(
478            "CREATE TABLE test (a INTEGER)",
479            crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
480        )?;
481        conn.execute("INSERT INTO test VALUES (42)", [])?;
482        let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
483        assert_eq!(val, (42,));
484        let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
485        fail.unwrap_err();
486        Ok(())
487    }
488
489    #[test]
490    fn test_try_from_row_for_tuple_2() -> Result<()> {
491        use std::convert::TryFrom;
492
493        let conn = Connection::open_in_memory()?;
494        conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
495        conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
496        let val = conn.query_row("SELECT a, b FROM test", [], |row| {
497            <(u32, u32)>::try_from(row)
498        })?;
499        assert_eq!(val, (42, 47));
500        let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
501            <(u32, u32, u32)>::try_from(row)
502        });
503        fail.unwrap_err();
504        Ok(())
505    }
506
507    #[test]
508    fn test_try_from_row_for_tuple_16() -> Result<()> {
509        use std::convert::TryFrom;
510
511        let create_table = "CREATE TABLE test (
512            a INTEGER,
513            b INTEGER,
514            c INTEGER,
515            d INTEGER,
516            e INTEGER,
517            f INTEGER,
518            g INTEGER,
519            h INTEGER,
520            i INTEGER,
521            j INTEGER,
522            k INTEGER,
523            l INTEGER,
524            m INTEGER,
525            n INTEGER,
526            o INTEGER,
527            p INTEGER
528        )";
529
530        let insert_values = "INSERT INTO test VALUES (
531            0,
532            1,
533            2,
534            3,
535            4,
536            5,
537            6,
538            7,
539            8,
540            9,
541            10,
542            11,
543            12,
544            13,
545            14,
546            15
547        )";
548
549        type BigTuple = (
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            u32,
564            u32,
565            u32,
566        );
567
568        let conn = Connection::open_in_memory()?;
569        conn.execute(create_table, [])?;
570        conn.execute(insert_values, [])?;
571        let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
572        // Debug is not implemented for tuples of 16
573        assert_eq!(val.0, 0);
574        assert_eq!(val.1, 1);
575        assert_eq!(val.2, 2);
576        assert_eq!(val.3, 3);
577        assert_eq!(val.4, 4);
578        assert_eq!(val.5, 5);
579        assert_eq!(val.6, 6);
580        assert_eq!(val.7, 7);
581        assert_eq!(val.8, 8);
582        assert_eq!(val.9, 9);
583        assert_eq!(val.10, 10);
584        assert_eq!(val.11, 11);
585        assert_eq!(val.12, 12);
586        assert_eq!(val.13, 13);
587        assert_eq!(val.14, 14);
588        assert_eq!(val.15, 15);
589
590        // We don't test one bigger because it's unimplemented
591        Ok(())
592    }
593
594    #[test]
595    #[cfg(feature = "bundled")]
596    fn pathological_case() -> Result<()> {
597        let conn = Connection::open_in_memory()?;
598        conn.execute_batch(
599            "CREATE TABLE foo(x);
600        CREATE TRIGGER oops BEFORE INSERT ON foo BEGIN SELECT RAISE(FAIL, 'Boom'); END;",
601        )?;
602        let mut stmt = conn.prepare("INSERT INTO foo VALUES (0) RETURNING rowid;")?;
603        {
604            let iterator_count = stmt.query_map([], |_| Ok(()))?.count();
605            assert_eq!(1, iterator_count); // should be 0
606            use fallible_streaming_iterator::FallibleStreamingIterator;
607            let fallible_iterator_count = stmt.query([])?.count().unwrap_or(0);
608            assert_eq!(0, fallible_iterator_count);
609        }
610        {
611            let iterator_last = stmt.query_map([], |_| Ok(()))?.last();
612            assert!(iterator_last.is_some()); // should be none
613            use fallible_iterator::FallibleIterator;
614            let fallible_iterator_last = stmt.query([])?.map(|_| Ok(())).last();
615            assert!(fallible_iterator_last.is_err());
616        }
617        Ok(())
618    }
619
620    #[test]
621    fn as_ref() -> Result<()> {
622        let conn = Connection::open_in_memory()?;
623        let mut stmt = conn.prepare("SELECT 'Lisa' as name, 1 as id")?;
624        let rows = stmt.query([])?;
625        assert_eq!(rows.as_ref().unwrap().column_count(), 2);
626        Ok(())
627    }
628
629    #[test]
630    fn debug() -> Result<()> {
631        let conn = Connection::open_in_memory()?;
632        let mut stmt = conn.prepare(
633            "SELECT 'Lisa' as name, 1 as id, 3.14 as pi, X'53514C697465' as blob, NULL as void",
634        )?;
635        let mut rows = stmt.query([])?;
636        let row = rows.next()?.unwrap();
637        let s = format!("{row:?}");
638        assert_eq!(
639            s,
640            r#"{"name": (Text, "Lisa"), "id": (Integer, 1), "pi": (Real, 3.14), "blob": (Blob, 6), "void": (Null, ())}"#
641        );
642        Ok(())
643    }
644}