sqlx_core_guts/sqlite/connection/
execute.rs

1use crate::error::Error;
2use crate::logger::QueryLogger;
3use crate::sqlite::connection::{ConnectionHandle, ConnectionState};
4use crate::sqlite::statement::{StatementHandle, VirtualStatement};
5use crate::sqlite::{SqliteArguments, SqliteQueryResult, SqliteRow};
6use either::Either;
7
8pub struct ExecuteIter<'a> {
9    handle: &'a mut ConnectionHandle,
10    statement: &'a mut VirtualStatement,
11    logger: QueryLogger<'a>,
12    args: Option<SqliteArguments<'a>>,
13
14    /// since a `VirtualStatement` can encompass multiple actual statements,
15    /// this keeps track of the number of arguments so far
16    args_used: usize,
17
18    goto_next: bool,
19}
20
21pub(crate) fn iter<'a>(
22    conn: &'a mut ConnectionState,
23    query: &'a str,
24    args: Option<SqliteArguments<'a>>,
25    persistent: bool,
26) -> Result<ExecuteIter<'a>, Error> {
27    // fetch the cached statement or allocate a new one
28    let statement = conn.statements.get(query, persistent)?;
29
30    let logger = QueryLogger::new(query, conn.log_settings.clone());
31
32    Ok(ExecuteIter {
33        handle: &mut conn.handle,
34        statement,
35        logger,
36        args,
37        args_used: 0,
38        goto_next: true,
39    })
40}
41
42fn bind(
43    statement: &mut StatementHandle,
44    arguments: &Option<SqliteArguments<'_>>,
45    offset: usize,
46) -> Result<usize, Error> {
47    let mut n = 0;
48
49    if let Some(arguments) = arguments {
50        n = arguments.bind(statement, offset)?;
51    }
52
53    Ok(n)
54}
55
56impl Iterator for ExecuteIter<'_> {
57    type Item = Result<Either<SqliteQueryResult, SqliteRow>, Error>;
58
59    fn next(&mut self) -> Option<Self::Item> {
60        let statement = if self.goto_next {
61            let mut statement = match self.statement.prepare_next(self.handle) {
62                Ok(Some(statement)) => statement,
63                Ok(None) => return None,
64                Err(e) => return Some(Err(e.into())),
65            };
66
67            self.goto_next = false;
68
69            // sanity check: ensure the VM is reset and the bindings are cleared
70            if let Err(e) = statement.handle.reset() {
71                return Some(Err(e.into()));
72            }
73
74            statement.handle.clear_bindings();
75
76            match bind(&mut statement.handle, &self.args, self.args_used) {
77                Ok(args_used) => self.args_used += args_used,
78                Err(e) => return Some(Err(e)),
79            }
80
81            statement
82        } else {
83            self.statement.current()?
84        };
85
86        match statement.handle.step() {
87            Ok(true) => {
88                self.logger.increment_rows_returned();
89
90                Some(Ok(Either::Right(SqliteRow::current(
91                    &statement.handle,
92                    &statement.columns,
93                    &statement.column_names,
94                ))))
95            }
96            Ok(false) => {
97                let last_insert_rowid = self.handle.last_insert_rowid();
98
99                let changes = statement.handle.changes();
100                self.logger.increase_rows_affected(changes);
101
102                let done = SqliteQueryResult {
103                    changes,
104                    last_insert_rowid,
105                };
106
107                self.goto_next = true;
108
109                Some(Ok(Either::Left(done)))
110            }
111            Err(e) => Some(Err(e.into())),
112        }
113    }
114}
115
116impl Drop for ExecuteIter<'_> {
117    fn drop(&mut self) {
118        self.statement.reset().ok();
119    }
120}