1use alloc::rc::Rc;
2use alloc::string::String;
3use core::cell::RefCell;
4use core::iter::FusedIterator;
56use super::row::{PrivateSqliteRow, SqliteRow};
7use super::stmt::StatementUse;
8use crate::result::QueryResult;
910#[allow(missing_debug_implementations)]
11pub struct StatementIterator<'stmt, 'query> {
12 inner: PrivateStatementIterator<'stmt, 'query>,
13 column_names: Option<Rc<[Option<String>]>>,
14 field_count: usize,
15}
1617impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
18#[cold]
19 #[allow(unsafe_code)] // call to unsafe function
20fn handle_duplicated_row_case(
21 outer_last_row: &mut Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>,
22 column_names: &mut Option<Rc<[Option<String>]>>,
23 field_count: usize,
24 ) -> Option<(QueryResult<SqliteRow<'stmt, 'query>>, bool)> {
25// We don't own the statement. There is another existing reference, likely because
26 // a user stored the row in some long time container before calling next another time
27 // In this case we copy out the current values into a temporary store and advance
28 // the statement iterator internally afterwards
29let last_row = {
30let mut last_row = match outer_last_row.try_borrow_mut() {
31Ok(o) => o,
32Err(_e) => {
33return Some((Err(crate::result::Error::DeserializationError(
34"Failed to reborrow row. Try to release any `SqliteField` or `SqliteValue` \
35 that exists at this point"
36.into(),
37 )), false));
38 }
39 };
40let last_row = &mut *last_row;
41let duplicated = match last_row.duplicate(column_names) {
42Ok(duplicated) => duplicated,
43// The statement is not advanced, so the row it holds stays current.
44Err(e) => return Some((Err(e), false)),
45 };
46 core::mem::replace(last_row, duplicated)
47 };
48if let PrivateSqliteRow::Direct(mut stmt) = last_row {
49let res = unsafe {
50// This is actually safe here as we've already
51 // performed one step. For the first step we would have
52 // used `PrivateStatementIterator::NotStarted` where we don't
53 // have access to `PrivateSqliteRow` at all
54stmt.step(false)
55 };
56*outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
57match res {
58Err(e) => Some((Err(e), true)),
59Ok(false) => None,
60Ok(true) => Some((
61Ok(SqliteRow {
62 inner: Rc::clone(outer_last_row),
63field_count,
64 }),
65false,
66 )),
67 }
68 } else {
69// any other state than `PrivateSqliteRow::Direct` is invalid here
70 // and should not happen. If this ever happens this is a logic error
71 // in the code above
72{
::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!(
73"You've reached an impossible internal state. \
74 If you ever see this error message please open \
75 an issue at https://github.com/diesel-rs/diesel \
76 providing example code how to trigger this error."
77)78 }
79 }
80}
8182enum PrivateStatementIterator<'stmt, 'query> {
83 NotStarted(Option<StatementUse<'stmt, 'query>>),
84 Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
85 Finished,
86}
8788impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
89pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
90Self {
91 inner: PrivateStatementIterator::NotStarted(Some(stmt)),
92 column_names: None,
93 field_count: 0,
94 }
95 }
96}
9798impl<'stmt, 'query> Iteratorfor StatementIterator<'stmt, 'query> {
99type Item = QueryResult<SqliteRow<'stmt, 'query>>;
100101#[allow(unsafe_code)] // call to unsafe function
102fn next(&mut self) -> Option<Self::Item> {
103use PrivateStatementIterator::{Finished, NotStarted, Started};
104match &mut self.inner {
105NotStarted(stmt @ Some(_)) => {
106let mut stmt = stmt107 .take()
108 .expect("It must be there because we checked that above");
109let step = unsafe {
110// This is safe as we pass `first_step = true` to reset the cached column names
111stmt.step(true)
112 };
113match step {
114Err(e) => {
115self.inner = Finished;
116Some(Err(e))
117 }
118Ok(false) => {
119// we reached the end of the iterator
120 // so we mark it done on rust side
121self.inner = Finished;
122None123 }
124Ok(true) => {
125let field_count = stmt126 .column_count()
127 .try_into()
128 .expect("Diesel expects to run at least on a 32 bit platform");
129self.field_count = field_count;
130let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
131self.inner = Started(inner.clone());
132Some(Ok(SqliteRow { inner, field_count }))
133 }
134 }
135 }
136Started(last_row) => {
137// There was already at least one iteration step
138 // We check here if the caller already released the row value or not
139 // by checking if our Rc owns the data or not
140if let Some(last_row_ref) = Rc::get_mut(last_row) {
141// We own the statement, there is no other reference here.
142 // This means we don't need to copy out values from the sqlite provided
143 // datastructures for now
144 // We don't need to use the runtime borrowing system of the RefCell here
145 // as we have a mutable reference, so all of this below is checked at compile time
146if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
147let step = unsafe {
148// This is actually safe here as we've already
149 // performed one step. For the first step we would have
150 // used `PrivateStatementIterator::NotStarted` where we don't
151 // have access to `PrivateSqliteRow` at all
152153stmt.step(false)
154 };
155match step {
156Err(e) => {
157self.inner = Finished;
158Some(Err(e))
159 }
160Ok(false) => {
161// we reached the end of the iterator
162 // so we mark it done on rust side
163self.inner = Finished;
164None165 }
166Ok(true) => {
167let field_count = self.field_count;
168Some(Ok(SqliteRow {
169 inner: Rc::clone(last_row),
170field_count,
171 }))
172 }
173 }
174 } else {
175// any other state than `PrivateSqliteRow::Direct` is invalid here
176 // and should not happen. If this ever happens this is a logic error
177 // in the code above
178{
::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!(
179"You've reached an impossible internal state. \
180 If you ever see this error message please open \
181 an issue at https://github.com/diesel-rs/diesel \
182 providing example code how to trigger this error."
183)184 }
185 } else {
186let result = Self::handle_duplicated_row_case(
187last_row,
188&mut self.column_names,
189self.field_count,
190 );
191if result.as_ref().is_none_or(|(r, f)| *f && r.is_err()) {
192self.inner = Finished;
193 }
194result.map(|(r, _)| r)
195 }
196 }
197NotStarted(_s) => {
198// we likely got an error while executing the other
199 // `NotStarted` branch above. In this case we just want to stop
200 // iterating here
201None202 }
203Finished => None,
204 }
205 }
206}
207208impl<'stmt, 'query> FusedIteratorfor StatementIterator<'stmt, 'query> {}
209210#[cfg(test)]
211mod tests {
212use crate::connection::{DefaultLoadingMode, SimpleConnection};
213use crate::dsl::sql;
214use crate::prelude::*;
215use crate::sql_types::Integer;
216217#[diesel_test_helper::test]
218fn statement_iterator_is_fused() {
219let mut conn = SqliteConnection::establish(":memory:").unwrap();
220 conn.batch_execute("CREATE TABLE t(x INTEGER); INSERT INTO t VALUES (1), (2);")
221 .unwrap();
222 {
223let mut it = sql::<Integer>("SELECT x FROM t")
224 .load_iter::<i32, DefaultLoadingMode>(&mut conn)
225 .unwrap();
226assert_eq!(it.next().unwrap().unwrap(), 1);
227assert_eq!(it.next().unwrap().unwrap(), 2);
228assert!(it.next().is_none());
229// Polling past the end must not restart (re-execute) the statement.
230assert!(it.next().is_none(), "iterator re-executed the statement");
231 }
232 conn.batch_execute("DELETE FROM t").unwrap();
233let mut it = sql::<Integer>("SELECT x FROM t")
234 .load_iter::<i32, DefaultLoadingMode>(&mut conn)
235 .unwrap();
236assert!(it.next().is_none());
237// Polling past the end must not restart (re-execute) the statement.
238assert!(it.next().is_none(), "iterator re-executed the statement");
239 }
240241#[diesel_test_helper::test]
242 #[cfg(not(miri))] // returns an error which allocates and uses an ffi string
243fn sqlite_iterator_terminates_after_step_error() {
244let mut conn = SqliteConnection::establish(":memory:").unwrap();
245let q = diesel::dsl::sql::<Integer>(
246"WITH RECURSIVE c(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM c WHERE x < 5) \
247 SELECT CASE WHEN x = 3 THEN json('{') ELSE x END FROM c",
248 );
249let items: Vec<Result<i32, String>> = q
250 .load_iter::<i32, DefaultLoadingMode>(&mut conn)
251 .unwrap()
252 .take(100)
253 .map(|r| r.map_err(|e| e.to_string()))
254 .collect();
255assert_eq!(
256 items.len(),
2573,
258"iterator yielded {} items - restarts after error",
259 items.len()
260 );
261assert_eq!(items[0], Ok(1));
262assert_eq!(items[1], Ok(2));
263assert!(items[2].is_err());
264assert_eq!(items[2].as_ref().unwrap_err().to_string(), "malformed JSON");
265 }
266267#[diesel_test_helper::test]
268 #[cfg(not(miri))] // returns an error which allocates and uses an ffi string
269fn held_rows_iterator_terminates_after_step_error() {
270use crate::connection::LoadConnection;
271use crate::row::Row;
272273let mut conn = SqliteConnection::establish(":memory:").unwrap();
274let q = sql::<Integer>(
275"WITH RECURSIVE c(x) AS (SELECT 1 UNION ALL SELECT x + 1 FROM c WHERE x < 5) \
276 SELECT CASE WHEN x = 3 THEN json('{') ELSE x END FROM c",
277 );
278let mut iter = LoadConnection::<DefaultLoadingMode>::load(&mut conn, q).unwrap();
279280let first = iter.next().unwrap().unwrap();
281let second = iter.next().unwrap().unwrap();
282let err = iter.next().unwrap().err().expect("step error");
283assert_eq!(err.to_string(), "malformed JSON");
284assert!(iter.next().is_none(), "iterator restarted the statement");
285assert!(iter.next().is_none());
286287assert_eq!(first.get_value::<Integer, i32, _>(0).unwrap(), 1);
288assert_eq!(second.get_value::<Integer, i32, _>(0).unwrap(), 2);
289 }
290291#[diesel_test_helper::test]
292 #[cfg(not(miri))] // returns an error which allocates and uses an ffi string
293fn held_rows_iterator_continues_after_reborrow_error() {
294use crate::connection::LoadConnection;
295use crate::row::Row;
296297let mut conn = SqliteConnection::establish(":memory:").unwrap();
298 conn.batch_execute("CREATE TABLE t(x INTEGER); INSERT INTO t VALUES (1), (2), (3);")
299 .unwrap();
300let q = sql::<Integer>("SELECT x FROM t");
301let mut iter = LoadConnection::<DefaultLoadingMode>::load(&mut conn, q).unwrap();
302303let first = iter.next().unwrap().unwrap();
304let field = first.get(0).unwrap();
305assert!(iter.next().unwrap().is_err());
306 drop(field);
307308let rest = iter
309 .map(|row| row.unwrap().get_value::<Integer, i32, _>(0).unwrap())
310 .collect::<Vec<_>>();
311assert_eq!(rest, [2, 3]);
312 }
313}