1use alloc::rc::Rc;
2use alloc::string::String;
3use core::cell::RefCell;
45use super::row::{PrivateSqliteRow, SqliteRow};
6use super::stmt::StatementUse;
7use crate::result::QueryResult;
89#[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}
1516impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
17#[cold]
18 #[allow(unsafe_code)] // call to unsafe function
19fn 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
28let last_row = {
29let mut last_row = match outer_last_row.try_borrow_mut() {
30Ok(o) => o,
31Err(_e) => {
32return 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 };
39let last_row = &mut *last_row;
40let duplicated = match last_row.duplicate(column_names) {
41Ok(duplicated) => duplicated,
42// The statement is not advanced, so the row it holds stays current.
43Err(e) => return Some(Err(e)),
44 };
45 core::mem::replace(last_row, duplicated)
46 };
47if let PrivateSqliteRow::Direct(mut stmt) = last_row {
48let 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
53stmt.step(false)
54 };
55*outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
56match res {
57Err(e) => Some(Err(e)),
58Ok(false) => None,
59Ok(true) => Some(Ok(SqliteRow {
60 inner: Rc::clone(outer_last_row),
61field_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}
7778enum PrivateStatementIterator<'stmt, 'query> {
79 NotStarted(Option<StatementUse<'stmt, 'query>>),
80 Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
81}
8283impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
84pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
85Self {
86 inner: PrivateStatementIterator::NotStarted(Some(stmt)),
87 column_names: None,
88 field_count: 0,
89 }
90 }
91}
9293impl<'stmt, 'query> Iteratorfor StatementIterator<'stmt, 'query> {
94type Item = QueryResult<SqliteRow<'stmt, 'query>>;
9596#[allow(unsafe_code)] // call to unsafe function
97fn next(&mut self) -> Option<Self::Item> {
98use PrivateStatementIterator::{NotStarted, Started};
99match &mut self.inner {
100NotStarted(stmt @ Some(_)) => {
101let mut stmt = stmt102 .take()
103 .expect("It must be there because we checked that above");
104let step = unsafe {
105// This is safe as we pass `first_step = true` to reset the cached column names
106stmt.step(true)
107 };
108match step {
109Err(e) => Some(Err(e)),
110Ok(false) => None,
111Ok(true) => {
112let field_count = stmt113 .column_count()
114 .try_into()
115 .expect("Diesel expects to run at least on a 32 bit platform");
116self.field_count = field_count;
117let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
118self.inner = Started(inner.clone());
119Some(Ok(SqliteRow { inner, field_count }))
120 }
121 }
122 }
123Started(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
127if 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
133if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
134let 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
139140stmt.step(false)
141 };
142match step {
143Err(e) => Some(Err(e)),
144Ok(false) => None,
145Ok(true) => {
146let field_count = self.field_count;
147Some(Ok(SqliteRow {
148 inner: Rc::clone(last_row),
149field_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 {
165Self::handle_duplicated_row_case(
166last_row,
167&mut self.column_names,
168self.field_count,
169 )
170 }
171 }
172NotStarted(_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
176None177 }
178 }
179 }
180}