Ryan Leckey 7db850da71
feat(mysql): thread E: Execute through the executor
+ handle normal errors separate from unexpected errors, an unexpected
   error causes the connection to close (in which case, if this was
   behind a pool, the pool would not allow this connection to be
   acquired again)
2021-02-18 23:46:07 -08:00

79 lines
2.8 KiB
Rust

use sqlx_core::{Arguments, Execute, Result, Runtime};
use crate::connection::command::QueryCommand;
use crate::protocol::{self, Query, QueryResponse, QueryStep, Status};
use crate::{MySql, MySqlConnection, MySqlRawValueFormat, MySqlRow};
macro_rules! impl_fetch_all {
($(@$blocking:ident)? $self:ident, $query:ident) => {{
let format = raw_query!($(@$blocking)? $self, $query);
let Self { ref mut stream, ref mut commands, capabilities, .. } = *$self;
// STATE: remember that we are now expecting a query response
let mut cmd = QueryCommand::begin(commands);
// default an empty row set
let mut rows = Vec::with_capacity(10);
#[allow(clippy::while_let_loop, unused_labels)]
'results: loop {
let res = 'result: loop {
match read_packet!($(@$blocking)? stream).deserialize_with(capabilities)? {
QueryResponse::End(res) => break 'result res.into_result(),
QueryResponse::ResultSet { columns } => {
let columns = recv_columns!($(@$blocking)? /* store = */ true, columns, stream, cmd);
'rows: loop {
match read_packet!($(@$blocking)? stream).deserialize_with(capabilities)? {
// execute ignores any rows returned
// but we do increment affected rows
QueryStep::End(res) => break 'result res.into_result(),
QueryStep::Row(row) => rows.push(MySqlRow::new(row.deserialize_with((format, &columns[..]))?, &columns)),
}
}
}
}
};
// STATE: command is complete on error
let ok = cmd.end_if_error(res)?;
if !ok.status.contains(Status::MORE_RESULTS_EXISTS) {
// no more results, time to finally call it quits
break;
}
// STATE: expecting a response from another statement
*cmd = QueryCommand::QueryResponse;
}
// STATE: the current command is complete
cmd.end();
Ok(rows)
}};
}
impl<Rt: Runtime> MySqlConnection<Rt> {
#[cfg(feature = "async")]
pub(super) async fn fetch_all_async<'q, 'a, E>(&mut self, query: E) -> Result<Vec<MySqlRow>>
where
Rt: sqlx_core::Async,
E: Execute<'q, 'a, MySql>,
{
flush!(self);
impl_fetch_all!(self, query)
}
#[cfg(feature = "blocking")]
pub(super) fn fetch_all_blocking<'q, 'a, E>(&mut self, query: E) -> Result<Vec<MySqlRow>>
where
Rt: sqlx_core::blocking::Runtime,
E: Execute<'q, 'a, MySql>,
{
flush!(@blocking self);
impl_fetch_all!(@blocking self, query)
}
}