Skip to main content

diesel/sqlite/connection/
statement_iterator.rs

1use alloc::rc::Rc;
2use alloc::string::String;
3use core::cell::RefCell;
4
5use super::row::{PrivateSqliteRow, SqliteRow};
6use super::stmt::StatementUse;
7use crate::result::QueryResult;
8
9#[allow(missing_debug_implementations)]
10pub struct StatementIterator<'stmt, 'query> {
11    inner: PrivateStatementIterator<'stmt, 'query>,
12    column_names: Option<Rc<[Option<String>]>>,
13    field_count: usize,
14}
15
16impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
17    #[cold]
18    #[allow(unsafe_code)] // call to unsafe function
19    fn handle_duplicated_row_case(
20        outer_last_row: &mut Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>,
21        column_names: &mut Option<Rc<[Option<String>]>>,
22        field_count: usize,
23    ) -> Option<QueryResult<SqliteRow<'stmt, 'query>>> {
24        // We don't own the statement. There is another existing reference, likely because
25        // a user stored the row in some long time container before calling next another time
26        // In this case we copy out the current values into a temporary store and advance
27        // the statement iterator internally afterwards
28        let last_row = {
29            let mut last_row = match outer_last_row.try_borrow_mut() {
30                Ok(o) => o,
31                Err(_e) => {
32                    return Some(Err(crate::result::Error::DeserializationError(
33                                    "Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \
34                                     that exists at this point"
35                                        .into(),
36                                )));
37                }
38            };
39            let last_row = &mut *last_row;
40            let duplicated = match last_row.duplicate(column_names) {
41                Ok(duplicated) => duplicated,
42                // The statement is not advanced, so the row it holds stays current.
43                Err(e) => return Some(Err(e)),
44            };
45            core::mem::replace(last_row, duplicated)
46        };
47        if let PrivateSqliteRow::Direct(mut stmt) = last_row {
48            let res = unsafe {
49                // This is actually safe here as we've already
50                // performed one step. For the first step we would have
51                // used `PrivateStatementIterator::NotStarted` where we don't
52                // have access to `PrivateSqliteRow` at all
53                stmt.step(false)
54            };
55            *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
56            match res {
57                Err(e) => Some(Err(e)),
58                Ok(false) => None,
59                Ok(true) => Some(Ok(SqliteRow {
60                    inner: Rc::clone(outer_last_row),
61                    field_count,
62                })),
63            }
64        } else {
65            // any other state than `PrivateSqliteRow::Direct` is invalid here
66            // and should not happen. If this ever happens this is a logic error
67            // in the code above
68            {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("You\'ve reached an impossible internal state. If you ever see this error message please open an issue at https://github.com/diesel-rs/diesel providing example code how to trigger this error.")));
}unreachable!(
69                "You've reached an impossible internal state. \
70                             If you ever see this error message please open \
71                             an issue at https://github.com/diesel-rs/diesel \
72                             providing example code how to trigger this error."
73            )
74        }
75    }
76}
77
78enum PrivateStatementIterator<'stmt, 'query> {
79    NotStarted(Option<StatementUse<'stmt, 'query>>),
80    Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
81}
82
83impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
84    pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
85        Self {
86            inner: PrivateStatementIterator::NotStarted(Some(stmt)),
87            column_names: None,
88            field_count: 0,
89        }
90    }
91}
92
93impl<'stmt, 'query> Iterator for StatementIterator<'stmt, 'query> {
94    type Item = QueryResult<SqliteRow<'stmt, 'query>>;
95
96    #[allow(unsafe_code)] // call to unsafe function
97    fn next(&mut self) -> Option<Self::Item> {
98        use PrivateStatementIterator::{NotStarted, Started};
99        match &mut self.inner {
100            NotStarted(stmt @ Some(_)) => {
101                let mut stmt = stmt
102                    .take()
103                    .expect("It must be there because we checked that above");
104                let step = unsafe {
105                    // This is safe as we pass `first_step = true` to reset the cached column names
106                    stmt.step(true)
107                };
108                match step {
109                    Err(e) => Some(Err(e)),
110                    Ok(false) => None,
111                    Ok(true) => {
112                        let field_count = stmt
113                            .column_count()
114                            .try_into()
115                            .expect("Diesel expects to run at least on a 32 bit platform");
116                        self.field_count = field_count;
117                        let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
118                        self.inner = Started(inner.clone());
119                        Some(Ok(SqliteRow { inner, field_count }))
120                    }
121                }
122            }
123            Started(last_row) => {
124                // There was already at least one iteration step
125                // We check here if the caller already released the row value or not
126                // by checking if our Rc owns the data or not
127                if let Some(last_row_ref) = Rc::get_mut(last_row) {
128                    // We own the statement, there is no other reference here.
129                    // This means we don't need to copy out values from the sqlite provided
130                    // datastructures for now
131                    // We don't need to use the runtime borrowing system of the RefCell here
132                    // as we have a mutable reference, so all of this below is checked at compile time
133                    if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
134                        let step = unsafe {
135                            // This is actually safe here as we've already
136                            // performed one step. For the first step we would have
137                            // used `PrivateStatementIterator::NotStarted` where we don't
138                            // have access to `PrivateSqliteRow` at all
139
140                            stmt.step(false)
141                        };
142                        match step {
143                            Err(e) => Some(Err(e)),
144                            Ok(false) => None,
145                            Ok(true) => {
146                                let field_count = self.field_count;
147                                Some(Ok(SqliteRow {
148                                    inner: Rc::clone(last_row),
149                                    field_count,
150                                }))
151                            }
152                        }
153                    } else {
154                        // any other state than `PrivateSqliteRow::Direct` is invalid here
155                        // and should not happen. If this ever happens this is a logic error
156                        // in the code above
157                        {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("You\'ve reached an impossible internal state. If you ever see this error message please open an issue at https://github.com/diesel-rs/diesel providing example code how to trigger this error.")));
}unreachable!(
158                            "You've reached an impossible internal state. \
159                             If you ever see this error message please open \
160                             an issue at https://github.com/diesel-rs/diesel \
161                             providing example code how to trigger this error."
162                        )
163                    }
164                } else {
165                    Self::handle_duplicated_row_case(
166                        last_row,
167                        &mut self.column_names,
168                        self.field_count,
169                    )
170                }
171            }
172            NotStarted(_s) => {
173                // we likely got an error while executing the other
174                // `NotStarted` branch above. In this case we just want to stop
175                // iterating here
176                None
177            }
178        }
179    }
180}