1use std::cell::RefCell;
2use std::rc::Rc;
34use super::row::{PrivateSqliteRow, SqliteRow};
5use super::stmt::StatementUse;
6use crate::result::QueryResult;
78#[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}
1415impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
16#[cold]
17 #[allow(unsafe_code)] // call to unsafe function
18fn 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
27let last_row = {
28let mut last_row = match outer_last_row.try_borrow_mut() {
29Ok(o) => o,
30Err(_e) => {
31return 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 };
38let last_row = &mut *last_row;
39let duplicated = match last_row.duplicate(column_names) {
40Ok(duplicated) => duplicated,
41// The statement is not advanced, so the row it holds stays current.
42Err(e) => return Some(Err(e)),
43 };
44 std::mem::replace(last_row, duplicated)
45 };
46if let PrivateSqliteRow::Direct(mut stmt) = last_row {
47let 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
52stmt.step(false)
53 };
54*outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
55match res {
56Err(e) => Some(Err(e)),
57Ok(false) => None,
58Ok(true) => Some(Ok(SqliteRow {
59 inner: Rc::clone(outer_last_row),
60field_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}
7677enum PrivateStatementIterator<'stmt, 'query> {
78 NotStarted(Option<StatementUse<'stmt, 'query>>),
79 Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
80}
8182impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
83pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
84Self {
85 inner: PrivateStatementIterator::NotStarted(Some(stmt)),
86 column_names: None,
87 field_count: 0,
88 }
89 }
90}
9192impl<'stmt, 'query> Iteratorfor StatementIterator<'stmt, 'query> {
93type Item = QueryResult<SqliteRow<'stmt, 'query>>;
9495#[allow(unsafe_code)] // call to unsafe function
96fn next(&mut self) -> Option<Self::Item> {
97use PrivateStatementIterator::{NotStarted, Started};
98match &mut self.inner {
99NotStarted(stmt @ Some(_)) => {
100let mut stmt = stmt101 .take()
102 .expect("It must be there because we checked that above");
103let step = unsafe {
104// This is safe as we pass `first_step = true` to reset the cached column names
105stmt.step(true)
106 };
107match step {
108Err(e) => Some(Err(e)),
109Ok(false) => None,
110Ok(true) => {
111let field_count = stmt112 .column_count()
113 .try_into()
114 .expect("Diesel expects to run at least on a 32 bit platform");
115self.field_count = field_count;
116let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
117self.inner = Started(inner.clone());
118Some(Ok(SqliteRow { inner, field_count }))
119 }
120 }
121 }
122Started(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
126if 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
132if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
133let 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
138139stmt.step(false)
140 };
141match step {
142Err(e) => Some(Err(e)),
143Ok(false) => None,
144Ok(true) => {
145let field_count = self.field_count;
146Some(Ok(SqliteRow {
147 inner: Rc::clone(last_row),
148field_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 {
164Self::handle_duplicated_row_case(
165last_row,
166&mut self.column_names,
167self.field_count,
168 )
169 }
170 }
171NotStarted(_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
175None176 }
177 }
178 }
179}