Skip to main content

diesel/sqlite/connection/
statement_iterator.rs

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