mirror of
https://github.com/launchbadge/sqlx
synced 2024-09-21 06:41:56 +00:00
fix Executor::describe()
for MariaDB
prevent exhaustive match of `describe` structs
This commit is contained in:
parent
4d28424af5
commit
b0a36ddd5c
4 changed files with 85 additions and 46 deletions
|
@ -10,6 +10,7 @@ pub struct Describe<DB: Backend> {
|
|||
pub param_types: Vec<<DB as HasTypeMetadata>::TypeId>,
|
||||
///
|
||||
pub result_fields: Vec<ResultField<DB>>,
|
||||
pub(crate) _backcompat: (),
|
||||
}
|
||||
|
||||
impl<DB: Backend> fmt::Debug for Describe<DB>
|
||||
|
@ -30,6 +31,7 @@ pub struct ResultField<DB: Backend> {
|
|||
pub table_id: Option<<DB as Backend>::TableIdent>,
|
||||
/// The type ID of this result column.
|
||||
pub type_id: <DB as HasTypeMetadata>::TypeId,
|
||||
pub(crate) _backcompat: (),
|
||||
}
|
||||
|
||||
impl<DB: Backend> fmt::Debug for ResultField<DB>
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
use super::establish;
|
||||
use crate::{
|
||||
io::{Buf, BufMut, BufStream},
|
||||
mariadb::{
|
||||
protocol::{
|
||||
Capabilities, ColumnCountPacket, ColumnDefinitionPacket, ComPing, ComQuit,
|
||||
ComStmtExecute, ComStmtPrepare, ComStmtPrepareOk, Encode, EofPacket, ErrPacket,
|
||||
OkPacket, ResultRow, StmtExecFlag,
|
||||
},
|
||||
query::MariaDbQueryParameters,
|
||||
use crate::{io::{Buf, BufMut, BufStream}, mariadb::{
|
||||
protocol::{
|
||||
Capabilities, ColumnCountPacket, ColumnDefinitionPacket, ComPing, ComQuit,
|
||||
ComStmtExecute, ComStmtPrepare, ComStmtPrepareOk, Encode, EofPacket, ErrPacket,
|
||||
OkPacket, ResultRow, StmtExecFlag,
|
||||
},
|
||||
url::Url,
|
||||
Error, Result,
|
||||
};
|
||||
query::MariaDbQueryParameters,
|
||||
}, url::Url, Error, Result, Describe, ResultField};
|
||||
use async_std::net::TcpStream;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use std::{
|
||||
|
@ -19,6 +14,8 @@ use std::{
|
|||
net::{IpAddr, SocketAddr},
|
||||
};
|
||||
|
||||
pub type StatementId = u32;
|
||||
|
||||
pub struct MariaDb {
|
||||
pub(crate) stream: BufStream<TcpStream>,
|
||||
pub(crate) rbuf: Vec<u8>,
|
||||
|
@ -157,7 +154,20 @@ impl MariaDb {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) async fn send_prepare<'c>(
|
||||
async fn check_eof(&mut self) -> Result<()> {
|
||||
// When (legacy) EOFs are enabled, the fixed number column definitions are further
|
||||
// terminated by an EOF packet
|
||||
if !self
|
||||
.capabilities
|
||||
.contains(Capabilities::CLIENT_DEPRECATE_EOF)
|
||||
{
|
||||
let _eof = EofPacket::decode(self.receive().await?)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_prepare<'c>(
|
||||
&'c mut self,
|
||||
statement: &'c str,
|
||||
) -> Result<ComStmtPrepareOk> {
|
||||
|
@ -177,19 +187,21 @@ impl MariaDb {
|
|||
|
||||
let ok = ComStmtPrepareOk::decode(packet)?;
|
||||
|
||||
Ok(ok)
|
||||
}
|
||||
|
||||
// MySQL/MariaDB responds with statement metadata for every PREPARE command
|
||||
// sometimes we care, sometimes we don't
|
||||
pub(super) async fn prepare_ignore_describe(&mut self, statement: &str) -> Result<StatementId> {
|
||||
let ok = self.send_prepare(statement).await?;
|
||||
|
||||
// Input parameters
|
||||
for _ in 0..ok.params {
|
||||
// TODO: Maybe do something with this data ?
|
||||
let _column = ColumnDefinitionPacket::decode(self.receive().await?)?;
|
||||
}
|
||||
|
||||
// TODO: De-duplicate this
|
||||
if !self
|
||||
.capabilities
|
||||
.contains(Capabilities::CLIENT_DEPRECATE_EOF)
|
||||
{
|
||||
let _eof = EofPacket::decode(self.receive().await?)?;
|
||||
}
|
||||
self.check_eof().await?;
|
||||
|
||||
// Output parameters
|
||||
for _ in 0..ok.columns {
|
||||
|
@ -197,18 +209,46 @@ impl MariaDb {
|
|||
let _column = ColumnDefinitionPacket::decode(self.receive().await?)?;
|
||||
}
|
||||
|
||||
// TODO: De-duplicate this
|
||||
if !self
|
||||
.capabilities
|
||||
.contains(Capabilities::CLIENT_DEPRECATE_EOF)
|
||||
{
|
||||
let _eof = EofPacket::decode(self.receive().await?)?;
|
||||
}
|
||||
self.check_eof().await?;
|
||||
|
||||
Ok(ok)
|
||||
Ok(ok.statement_id)
|
||||
}
|
||||
|
||||
pub(super) async fn column_definitions(&mut self) -> Result<Vec<ColumnDefinitionPacket>> {
|
||||
pub(super) async fn prepare_describe(&mut self, statement: &str) -> Result<Describe<Self>> {
|
||||
let ok = self.send_prepare(statement).await?;
|
||||
|
||||
let mut param_types = Vec::with_capacity(ok.params as usize);
|
||||
let mut result_fields= Vec::with_capacity(ok.columns as usize);
|
||||
|
||||
// Input parameters
|
||||
for _ in 0..ok.params {
|
||||
let param = ColumnDefinitionPacket::decode(self.receive().await?)?;
|
||||
param_types.push(param.field_type.0);
|
||||
}
|
||||
|
||||
self.check_eof().await?;
|
||||
|
||||
// Output parameters
|
||||
for _ in 0..ok.columns {
|
||||
let column = ColumnDefinitionPacket::decode(self.receive().await?)?;
|
||||
result_fields.push(ResultField {
|
||||
name: column.column_alias.or(column.column),
|
||||
table_id: column.table_alias.or(column.table),
|
||||
type_id: column.field_type.0,
|
||||
_backcompat: ()
|
||||
});
|
||||
}
|
||||
|
||||
self.check_eof().await?;
|
||||
|
||||
Ok(Describe {
|
||||
param_types,
|
||||
result_fields,
|
||||
_backcompat: (),
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) async fn result_column_defs(&mut self) -> Result<Vec<ColumnDefinitionPacket>> {
|
||||
let packet = self.receive().await?;
|
||||
|
||||
// A Resultset starts with a [ColumnCountPacket] which is a single field that encodes
|
||||
|
@ -224,14 +264,7 @@ impl MariaDb {
|
|||
columns.push(column);
|
||||
}
|
||||
|
||||
// When (legacy) EOFs are enabled, the fixed number column definitions are further terminated by
|
||||
// an EOF packet
|
||||
if !self
|
||||
.capabilities
|
||||
.contains(Capabilities::CLIENT_DEPRECATE_EOF)
|
||||
{
|
||||
let _eof = EofPacket::decode(self.receive().await?)?;
|
||||
}
|
||||
self.check_eof().await?;
|
||||
|
||||
Ok(columns)
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ impl Executor for MariaDb {
|
|||
params: MariaDbQueryParameters,
|
||||
) -> BoxFuture<'e, crate::Result<u64>> {
|
||||
Box::pin(async move {
|
||||
let prepare = self.send_prepare(query).await?;
|
||||
self.send_execute(prepare.statement_id, params).await?;
|
||||
let statement_id = self.prepare_ignore_describe(query).await?;
|
||||
self.send_execute(statement_id, params).await?;
|
||||
|
||||
let columns = self.column_definitions().await?;
|
||||
let columns = self.result_column_defs().await?;
|
||||
let capabilities = self.capabilities;
|
||||
|
||||
// For each row in the result set we will receive a ResultRow packet.
|
||||
|
@ -109,10 +109,10 @@ impl Executor for MariaDb {
|
|||
T: FromRow<Self::Backend> + Send,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let prepare = self.send_prepare(query).await?;
|
||||
self.send_execute(prepare.statement_id, params).await?;
|
||||
let statement_id = self.prepare_ignore_describe(query).await?;
|
||||
self.send_execute(statement_id, params).await?;
|
||||
|
||||
let columns = self.column_definitions().await?;
|
||||
let columns = self.result_column_defs().await?;
|
||||
let capabilities = self.capabilities;
|
||||
|
||||
let mut row: Option<_> = None;
|
||||
|
@ -142,6 +142,8 @@ impl Executor for MariaDb {
|
|||
|
||||
fn describe<'e, 'q: 'e>(
|
||||
&'e mut self,
|
||||
_query: &'q str,
|
||||
) -> BoxFuture<'e, crate::Result<Describe<Self::Backend>>> { unimplemented!(); }
|
||||
query: &'q str,
|
||||
) -> BoxFuture<'e, crate::Result<Describe<Self::Backend>>> {
|
||||
Box::pin(self.prepare_describe(query))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,10 +128,12 @@ impl Executor for Postgres {
|
|||
.into_iter()
|
||||
.map(|field| ResultField {
|
||||
name: if field.name == "?column?" { None } else { Some(field.name) },
|
||||
table_id: Some(field.table_id),
|
||||
table_id: if field.table_id > 0 { Some(field.table_id) } else { None },
|
||||
type_id: field.type_id,
|
||||
_backcompat: (),
|
||||
})
|
||||
.collect(),
|
||||
_backcompat: (),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue