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 = last_row.duplicate(column_names);
40 std::mem::replace(last_row, duplicated)
41 };
42if let PrivateSqliteRow::Direct(mut stmt) = last_row {
43let res = unsafe {
44// This is actually safe here as we've already
45 // performed one step. For the first step we would have
46 // used `PrivateStatementIterator::NotStarted` where we don't
47 // have access to `PrivateSqliteRow` at all
48stmt.step(false)
49 };
50*outer_last_row = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
51match res {
52Err(e) => Some(Err(e)),
53Ok(false) => None,
54Ok(true) => Some(Ok(SqliteRow {
55 inner: Rc::clone(outer_last_row),
56field_count,
57 })),
58 }
59 } else {
60// any other state than `PrivateSqliteRow::Direct` is invalid here
61 // and should not happen. If this ever happens this is a logic error
62 // in the code above
63{
::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!(
64"You've reached an impossible internal state. \
65 If you ever see this error message please open \
66 an issue at https://github.com/diesel-rs/diesel \
67 providing example code how to trigger this error."
68)69 }
70 }
71}
7273enum PrivateStatementIterator<'stmt, 'query> {
74 NotStarted(Option<StatementUse<'stmt, 'query>>),
75 Started(Rc<RefCell<PrivateSqliteRow<'stmt, 'query>>>),
76}
7778impl<'stmt, 'query> StatementIterator<'stmt, 'query> {
79pub fn new(stmt: StatementUse<'stmt, 'query>) -> StatementIterator<'stmt, 'query> {
80Self {
81 inner: PrivateStatementIterator::NotStarted(Some(stmt)),
82 column_names: None,
83 field_count: 0,
84 }
85 }
86}
8788impl<'stmt, 'query> Iteratorfor StatementIterator<'stmt, 'query> {
89type Item = QueryResult<SqliteRow<'stmt, 'query>>;
9091#[allow(unsafe_code)] // call to unsafe function
92fn next(&mut self) -> Option<Self::Item> {
93use PrivateStatementIterator::{NotStarted, Started};
94match &mut self.inner {
95NotStarted(stmt @ Some(_)) => {
96let mut stmt = stmt97 .take()
98 .expect("It must be there because we checked that above");
99let step = unsafe {
100// This is safe as we pass `first_step = true` to reset the cached column names
101stmt.step(true)
102 };
103match step {
104Err(e) => Some(Err(e)),
105Ok(false) => None,
106Ok(true) => {
107let field_count = stmt108 .column_count()
109 .try_into()
110 .expect("Diesel expects to run at least on a 32 bit platform");
111self.field_count = field_count;
112let inner = Rc::new(RefCell::new(PrivateSqliteRow::Direct(stmt)));
113self.inner = Started(inner.clone());
114Some(Ok(SqliteRow { inner, field_count }))
115 }
116 }
117 }
118Started(last_row) => {
119// There was already at least one iteration step
120 // We check here if the caller already released the row value or not
121 // by checking if our Rc owns the data or not
122if let Some(last_row_ref) = Rc::get_mut(last_row) {
123// We own the statement, there is no other reference here.
124 // This means we don't need to copy out values from the sqlite provided
125 // datastructures for now
126 // We don't need to use the runtime borrowing system of the RefCell here
127 // as we have a mutable reference, so all of this below is checked at compile time
128if let PrivateSqliteRow::Direct(stmt) = last_row_ref.get_mut() {
129let step = unsafe {
130// This is actually safe here as we've already
131 // performed one step. For the first step we would have
132 // used `PrivateStatementIterator::NotStarted` where we don't
133 // have access to `PrivateSqliteRow` at all
134135stmt.step(false)
136 };
137match step {
138Err(e) => Some(Err(e)),
139Ok(false) => None,
140Ok(true) => {
141let field_count = self.field_count;
142Some(Ok(SqliteRow {
143 inner: Rc::clone(last_row),
144field_count,
145 }))
146 }
147 }
148 } else {
149// any other state than `PrivateSqliteRow::Direct` is invalid here
150 // and should not happen. If this ever happens this is a logic error
151 // in the code above
152{
::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!(
153"You've reached an impossible internal state. \
154 If you ever see this error message please open \
155 an issue at https://github.com/diesel-rs/diesel \
156 providing example code how to trigger this error."
157)158 }
159 } else {
160Self::handle_duplicated_row_case(
161last_row,
162&mut self.column_names,
163self.field_count,
164 )
165 }
166 }
167NotStarted(_s) => {
168// we likely got an error while executing the other
169 // `NotStarted` branch above. In this case we just want to stop
170 // iterating here
171None172 }
173 }
174 }
175}