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 = last_row.duplicate(column_names);
41            core::mem::replace(last_row, duplicated)
42        };
43        if let PrivateSqliteRow::Direct(mut stmt) = last_row {
44            let res = unsafe {
45                // This is actually safe here as we've already
46                // performed one step. For the first step we would have
47                // used `PrivateStatementIterator::NotStarted` where we don't
48                // have access to `PrivateSqliteRow` at all
49                stmt.step(false)
50            };
51            *outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
52            match res {
53                Err(e) => Some(Err(e)),
54                Ok(false) => None,
55                Ok(true) => Some(Ok(SqliteRow {
56                    inner: Rc::clone(outer_last_row),
57                    field_count,
58                })),
59            }
60        } else {
61            // any other state than `PrivateSqliteRow::Direct` is invalid here
62            // and should not happen. If this ever happens this is a logic error
63            // in the code above
64            {
    ::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!(
65                "You've reached an impossible internal state. \
66                             If you ever see this error message please open \
67                             an issue at https://github.com/diesel-rs/diesel \
68                             providing example code how to trigger this error."
69            )
70        }
71    }
72}
73
74enum PrivateStatementIterator<'stmt, 'query> {
75    NotStarted(Option<StatementUse<'stmt, 'query>>),
76    Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
77}
78
79impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
80    pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
81        Self {
82            inner: PrivateStatementIterator::NotStarted(Some(stmt)),
83            column_names: None,
84            field_count: 0,
85        }
86    }
87}
88
89impl<'stmt, 'query> Iterator for StatementIterator<'stmt, 'query> {
90    type Item = QueryResult<SqliteRow<'stmt, 'query>>;
91
92    #[allow(unsafe_code)] // call to unsafe function
93    fn next(&mut self) -> Option<Self::Item> {
94        use PrivateStatementIterator::{NotStarted, Started};
95        match &mut self.inner {
96            NotStarted(stmt @ Some(_)) => {
97                let mut stmt = stmt
98                    .take()
99                    .expect("It must be there because we checked that above");
100                let step = unsafe {
101                    // This is safe as we pass `first_step = true` to reset the cached column names
102                    stmt.step(true)
103                };
104                match step {
105                    Err(e) => Some(Err(e)),
106                    Ok(false) => None,
107                    Ok(true) => {
108                        let field_count = stmt
109                            .column_count()
110                            .try_into()
111                            .expect("Diesel expects to run at least on a 32 bit platform");
112                        self.field_count = field_count;
113                        let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
114                        self.inner = Started(inner.clone());
115                        Some(Ok(SqliteRow { inner, field_count }))
116                    }
117                }
118            }
119            Started(last_row) => {
120                // There was already at least one iteration step
121                // We check here if the caller already released the row value or not
122                // by checking if our Rc owns the data or not
123                if let Some(last_row_ref) = Rc::get_mut(last_row) {
124                    // We own the statement, there is no other reference here.
125                    // This means we don't need to copy out values from the sqlite provided
126                    // datastructures for now
127                    // We don't need to use the runtime borrowing system of the RefCell here
128                    // as we have a mutable reference, so all of this below is checked at compile time
129                    if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
130                        let step = unsafe {
131                            // This is actually safe here as we've already
132                            // performed one step. For the first step we would have
133                            // used `PrivateStatementIterator::NotStarted` where we don't
134                            // have access to `PrivateSqliteRow` at all
135
136                            stmt.step(false)
137                        };
138                        match step {
139                            Err(e) => Some(Err(e)),
140                            Ok(false) => None,
141                            Ok(true) => {
142                                let field_count = self.field_count;
143                                Some(Ok(SqliteRow {
144                                    inner: Rc::clone(last_row),
145                                    field_count,
146                                }))
147                            }
148                        }
149                    } else {
150                        // any other state than `PrivateSqliteRow::Direct` is invalid here
151                        // and should not happen. If this ever happens this is a logic error
152                        // in the code above
153                        {
    ::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!(
154                            "You've reached an impossible internal state. \
155                             If you ever see this error message please open \
156                             an issue at https://github.com/diesel-rs/diesel \
157                             providing example code how to trigger this error."
158                        )
159                    }
160                } else {
161                    Self::handle_duplicated_row_case(
162                        last_row,
163                        &mut self.column_names,
164                        self.field_count,
165                    )
166                }
167            }
168            NotStarted(_s) => {
169                // we likely got an error while executing the other
170                // `NotStarted` branch above. In this case we just want to stop
171                // iterating here
172                None
173            }
174        }
175    }
176}