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 Item = B;
130    type Error = Error;
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 Item = Row<'stmt>;
212    type Error = Error;
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        let sv = super::ffi::sqlite3_column_value(self.stmt.stmt.ptr(), idx as std::ffi::c_int);
361        Ok(if sv.is_null() {
362            None
363        } else {
364            super::ffi::sqlite3_value_pointer(sv, ptr_type.as_ptr())
365                .cast::<T>()
366                .as_ref()
367        })
368    }
369}
370
371impl<'stmt> AsRef<Statement<'stmt>> for Row<'stmt> {
372    fn as_ref(&self) -> &Statement<'stmt> {
373        self.stmt
374    }
375}
376
377/// Debug `Row` like an ordered `Map<Result<&str>, Result<(Type, ValueRef)>>`
378/// with column name as key except that for `Type::Blob` only its size is
379/// printed (not its content).
380impl std::fmt::Debug for Row<'_> {
381    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
382        let mut dm = f.debug_map();
383        for c in 0..self.stmt.column_count() {
384            let name = self.stmt.column_name(c).expect("valid column index");
385            dm.key(&name);
386            let value = self.get_ref(c);
387            match value {
388                Ok(value) => {
389                    let dt = value.data_type();
390                    match value {
391                        ValueRef::Null => {
392                            dm.value(&(dt, ()));
393                        }
394                        ValueRef::Integer(i) => {
395                            dm.value(&(dt, i));
396                        }
397                        ValueRef::Real(f) => {
398                            dm.value(&(dt, f));
399                        }
400                        ValueRef::Text(s) => {
401                            dm.value(&(dt, String::from_utf8_lossy(s)));
402                        }
403                        ValueRef::Blob(b) => {
404                            dm.value(&(dt, b.len()));
405                        }
406                    }
407                }
408                Err(ref _err) => {
409                    dm.value(&value);
410                }
411            }
412        }
413        dm.finish()
414    }
415}
416
417mod sealed {
418    /// This trait exists just to ensure that the only impls of `trait RowIndex`
419    /// that are allowed are ones in this crate.
420    pub trait Sealed {}
421    impl Sealed for usize {}
422    impl Sealed for &str {}
423}
424
425/// A trait implemented by types that can index into columns of a row.
426///
427/// It is only implemented for `usize` and `&str`.
428pub trait RowIndex: sealed::Sealed {
429    /// Returns the index of the appropriate column, or `Error` if no such
430    /// column exists.
431    fn idx(&self, stmt: &Statement<'_>) -> Result<usize>;
432}
433
434impl RowIndex for usize {
435    #[inline]
436    fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
437        if *self >= stmt.column_count() {
438            Err(Error::InvalidColumnIndex(*self))
439        } else {
440            Ok(*self)
441        }
442    }
443}
444
445impl RowIndex for &'_ str {
446    #[inline]
447    fn idx(&self, stmt: &Statement<'_>) -> Result<usize> {
448        stmt.column_index(self)
449    }
450}
451
452macro_rules! tuple_try_from_row {
453    ($($field:ident),*) => {
454        impl<'a, $($field,)*> convert::TryFrom<&'a Row<'a>> for ($($field,)*) where $($field: FromSql,)* {
455            type Error = crate::Error;
456
457            // we end with index += 1, which rustc warns about
458            // unused_variables and unused_mut are allowed for ()
459            #[allow(unused_assignments, unused_variables, unused_mut)]
460            fn try_from(row: &'a Row<'a>) -> Result<Self> {
461                let mut index = 0;
462                $(
463                    #[expect(non_snake_case)]
464                    let $field = row.get::<_, $field>(index)?;
465                    index += 1;
466                )*
467                Ok(($($field,)*))
468            }
469        }
470    }
471}
472
473macro_rules! tuples_try_from_row {
474    () => {
475        // not very useful, but maybe some other macro users will find this helpful
476        tuple_try_from_row!();
477    };
478    ($first:ident $(, $remaining:ident)*) => {
479        tuple_try_from_row!($first $(, $remaining)*);
480        tuples_try_from_row!($($remaining),*);
481    };
482}
483
484tuples_try_from_row!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
485
486#[cfg(test)]
487mod tests {
488    #[cfg(all(target_family = "wasm", target_os = "unknown"))]
489    use wasm_bindgen_test::wasm_bindgen_test as test;
490
491    use crate::{Connection, Result};
492
493    #[test]
494    fn test_try_from_row_for_tuple_1() -> Result<()> {
495        use crate::ToSql;
496        use std::convert::TryFrom;
497
498        let conn = Connection::open_in_memory()?;
499        conn.execute(
500            "CREATE TABLE test (a INTEGER)",
501            crate::params_from_iter(std::iter::empty::<&dyn ToSql>()),
502        )?;
503        conn.execute("INSERT INTO test VALUES (42)", [])?;
504        let val = conn.query_row("SELECT a FROM test", [], |row| <(u32,)>::try_from(row))?;
505        assert_eq!(val, (42,));
506        let fail = conn.query_row("SELECT a FROM test", [], |row| <(u32, u32)>::try_from(row));
507        fail.unwrap_err();
508        Ok(())
509    }
510
511    #[test]
512    fn test_try_from_row_for_tuple_2() -> Result<()> {
513        use std::convert::TryFrom;
514
515        let conn = Connection::open_in_memory()?;
516        conn.execute("CREATE TABLE test (a INTEGER, b INTEGER)", [])?;
517        conn.execute("INSERT INTO test VALUES (42, 47)", [])?;
518        let val = conn.query_row("SELECT a, b FROM test", [], |row| {
519            <(u32, u32)>::try_from(row)
520        })?;
521        assert_eq!(val, (42, 47));
522        let fail = conn.query_row("SELECT a, b FROM test", [], |row| {
523            <(u32, u32, u32)>::try_from(row)
524        });
525        fail.unwrap_err();
526        Ok(())
527    }
528
529    #[test]
530    fn test_try_from_row_for_tuple_16() -> Result<()> {
531        use std::convert::TryFrom;
532
533        let create_table = "CREATE TABLE test (
534            a INTEGER,
535            b INTEGER,
536            c INTEGER,
537            d INTEGER,
538            e INTEGER,
539            f INTEGER,
540            g INTEGER,
541            h INTEGER,
542            i INTEGER,
543            j INTEGER,
544            k INTEGER,
545            l INTEGER,
546            m INTEGER,
547            n INTEGER,
548            o INTEGER,
549            p INTEGER
550        )";
551
552        let insert_values = "INSERT INTO test VALUES (
553            0,
554            1,
555            2,
556            3,
557            4,
558            5,
559            6,
560            7,
561            8,
562            9,
563            10,
564            11,
565            12,
566            13,
567            14,
568            15
569        )";
570
571        type BigTuple = (
572            u32,
573            u32,
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        );
589
590        let conn = Connection::open_in_memory()?;
591        conn.execute(create_table, [])?;
592        conn.execute(insert_values, [])?;
593        let val = conn.query_row("SELECT * FROM test", [], |row| BigTuple::try_from(row))?;
594        // Debug is not implemented for tuples of 16
595        assert_eq!(val.0, 0);
596        assert_eq!(val.1, 1);
597        assert_eq!(val.2, 2);
598        assert_eq!(val.3, 3);
599        assert_eq!(val.4, 4);
600        assert_eq!(val.5, 5);
601        assert_eq!(val.6, 6);
602        assert_eq!(val.7, 7);
603        assert_eq!(val.8, 8);
604        assert_eq!(val.9, 9);
605        assert_eq!(val.10, 10);
606        assert_eq!(val.11, 11);
607        assert_eq!(val.12, 12);
608        assert_eq!(val.13, 13);
609        assert_eq!(val.14, 14);
610        assert_eq!(val.15, 15);
611
612        // We don't test one bigger because it's unimplemented
613        Ok(())
614    }
615
616    #[test]
617    #[cfg(feature = "bundled")]
618    fn pathological_case() -> Result<()> {
619        let conn = Connection::open_in_memory()?;
620        conn.execute_batch(
621            "CREATE TABLE foo(x);
622        CREATE TRIGGER oops BEFORE INSERT ON foo BEGIN SELECT RAISE(FAIL, 'Boom'); END;",
623        )?;
624        let mut stmt = conn.prepare("INSERT INTO foo VALUES (0) RETURNING rowid;")?;
625        {
626            let iterator_count = stmt.query_map([], |_| Ok(()))?.count();
627            assert_eq!(1, iterator_count); // should be 0
628            use fallible_streaming_iterator::FallibleStreamingIterator;
629            let fallible_iterator_count = stmt.query([])?.count().unwrap_or(0);
630            assert_eq!(0, fallible_iterator_count);
631        }
632        {
633            let iterator_last = stmt.query_map([], |_| Ok(()))?.last();
634            assert!(iterator_last.is_some()); // should be none
635            use fallible_iterator::FallibleIterator;
636            let fallible_iterator_last = stmt.query([])?.map(|_| Ok(())).last();
637            assert!(fallible_iterator_last.is_err());
638        }
639        Ok(())
640    }
641
642    #[test]
643    fn as_ref() -> Result<()> {
644        let conn = Connection::open_in_memory()?;
645        let mut stmt = conn.prepare("SELECT 'Lisa' as name, 1 as id")?;
646        let rows = stmt.query([])?;
647        assert_eq!(rows.as_ref().unwrap().column_count(), 2);
648        Ok(())
649    }
650
651    #[test]
652    fn debug() -> Result<()> {
653        let conn = Connection::open_in_memory()?;
654        let mut stmt = conn.prepare(
655            "SELECT 'Lisa' as name, 1 as id, 3.14 as pi, X'53514C697465' as blob, NULL as void",
656        )?;
657        let mut rows = stmt.query([])?;
658        let row = rows.next()?.unwrap();
659        let s = format!("{row:?}");
660        assert_eq!(
661            s,
662            r#"{"name": (Text, "Lisa"), "id": (Integer, 1), "pi": (Real, 3.14), "blob": (Blob, 6), "void": (Null, ())}"#
663        );
664        Ok(())
665    }
666
667    #[test]
668    #[cfg(feature = "pointer")]
669    fn test_pointer() -> Result<()> {
670        use crate::ffi::fts5_api;
671        use crate::types::ToSqlOutput;
672        const PTR_TYPE: &std::ffi::CStr = c"fts5_api_ptr";
673        let p_ret: *mut fts5_api = std::ptr::null_mut();
674        let ptr = ToSqlOutput::Pointer((&p_ret as *const *mut fts5_api as _, PTR_TYPE, None));
675        let db = Connection::open_in_memory()?;
676        db.query_row("SELECT fts5(?)", [ptr], |_| Ok(()))?;
677        assert!(!p_ret.is_null());
678        Ok(())
679    }
680}