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 = last_row.duplicate(column_names);
41 core::mem::replace(last_row, duplicated)
42 };
43if let PrivateSqliteRow::Direct(mut stmt) = last_row {
44let 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
49stmt.step(false)
50 };
51*outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
52match res {
53Err(e) => Some(Err(e)),
54Ok(false) => None,
55Ok(true) => Some(Ok(SqliteRow {
56 inner: Rc::clone(outer_last_row),
57field_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}
7374enum PrivateStatementIterator<'stmt, 'query> {
75 NotStarted(Option<StatementUse<'stmt, 'query>>),
76 Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
77}
7879impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
80pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
81Self {
82 inner: PrivateStatementIterator::NotStarted(Some(stmt)),
83 column_names: None,
84 field_count: 0,
85 }
86 }
87}
8889impl<'stmt, 'query> Iteratorfor StatementIterator<'stmt, 'query> {
90type Item = QueryResult<SqliteRow<'stmt, 'query>>;
9192#[allow(unsafe_code)] // call to unsafe function
93fn next(&mut self) -> Option<Self::Item> {
94use PrivateStatementIterator::{NotStarted, Started};
95match &mut self.inner {
96NotStarted(stmt @ Some(_)) => {
97let mut stmt = stmt98 .take()
99 .expect("It must be there because we checked that above");
100let step = unsafe {
101// This is safe as we pass `first_step = true` to reset the cached column names
102stmt.step(true)
103 };
104match step {
105Err(e) => Some(Err(e)),
106Ok(false) => None,
107Ok(true) => {
108let field_count = stmt109 .column_count()
110 .try_into()
111 .expect("Diesel expects to run at least on a 32 bit platform");
112self.field_count = field_count;
113let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
114self.inner = Started(inner.clone());
115Some(Ok(SqliteRow { inner, field_count }))
116 }
117 }
118 }
119Started(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
123if 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
129if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
130let 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
135136stmt.step(false)
137 };
138match step {
139Err(e) => Some(Err(e)),
140Ok(false) => None,
141Ok(true) => {
142let field_count = self.field_count;
143Some(Ok(SqliteRow {
144 inner: Rc::clone(last_row),
145field_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 {
161Self::handle_duplicated_row_case(
162last_row,
163&mut self.column_names,
164self.field_count,
165 )
166 }
167 }
168NotStarted(_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
172None173 }
174 }
175 }
176}