mirror of
https://github.com/launchbadge/sqlx
synced 2024-11-10 14:34:19 +00:00
Switched to a functional approach for front-end message construction
This commit is contained in:
parent
908f228fb5
commit
28168c414d
3 changed files with 58 additions and 72 deletions
|
@ -2,80 +2,55 @@ use crate::Encode;
|
|||
use byteorder::{BigEndian, ByteOrder};
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Bind<'a> {
|
||||
// The name of the destination portal (an empty string selects the unnamed portal).
|
||||
portal: &'a str,
|
||||
// FIXME: Having structs here is breaking down. I think front-end messages should be
|
||||
// simple functions that take the wbuf as a mut Vec
|
||||
|
||||
// The name of the source prepared statement (an empty string selects the unnamed prepared statement).
|
||||
statement: &'a str,
|
||||
pub fn header(buf: &mut Vec<u8>, portal: &str, statement: &str, formats: &[u16]) -> (usize, usize) {
|
||||
buf.push(b'B');
|
||||
|
||||
// The parameter format codes.
|
||||
formats: &'a [i16],
|
||||
// reserve room for the length
|
||||
let len_pos = buf.len();
|
||||
buf.extend_from_slice(&[0, 0, 0, 0]);
|
||||
|
||||
// The values of the parameters.
|
||||
// Arranged as: [len][size_0][value_0][size_1][value_1] etc...
|
||||
buffer: &'a [u8],
|
||||
buf.extend_from_slice(portal.as_bytes());
|
||||
buf.push(b'\0');
|
||||
|
||||
// The result-column format codes.
|
||||
result_formats: &'a [i16],
|
||||
}
|
||||
buf.extend_from_slice(statement.as_bytes());
|
||||
buf.push(b'\0');
|
||||
|
||||
impl<'a> Bind<'a> {
|
||||
pub fn new(
|
||||
portal: &'a str,
|
||||
statement: &'a str,
|
||||
formats: &'a [i16],
|
||||
buffer: &'a [u8],
|
||||
result_formats: &'a [i16],
|
||||
) -> Self {
|
||||
Self {
|
||||
portal,
|
||||
statement,
|
||||
formats,
|
||||
buffer,
|
||||
result_formats,
|
||||
}
|
||||
buf.extend_from_slice(&(formats.len() as i16).to_be_bytes());
|
||||
|
||||
for format in formats {
|
||||
buf.extend_from_slice(&format.to_be_bytes());
|
||||
}
|
||||
|
||||
// reserve room for the values count
|
||||
let value_len_pos = buf.len();
|
||||
buf.extend_from_slice(&[0, 0]);
|
||||
|
||||
(len_pos, value_len_pos)
|
||||
}
|
||||
|
||||
impl<'a> Encode for Bind<'a> {
|
||||
fn encode(&self, buf: &mut Vec<u8>) -> io::Result<()> {
|
||||
buf.push(b'B');
|
||||
pub fn value(buf: &mut Vec<u8>, value: &[u8]) {
|
||||
buf.extend_from_slice(&(value.len() as u32).to_be_bytes());
|
||||
buf.extend_from_slice(value);
|
||||
}
|
||||
|
||||
let pos = buf.len();
|
||||
buf.extend_from_slice(&[0, 0, 0, 0]);
|
||||
pub fn value_null(buf: &mut Vec<u8>) {
|
||||
buf.extend_from_slice(&(-1_i32).to_be_bytes());
|
||||
}
|
||||
|
||||
// portal
|
||||
buf.extend_from_slice(self.portal.as_bytes());
|
||||
buf.push(b'\0');
|
||||
pub fn trailer(buf: &mut Vec<u8>, state: (usize, usize), values: usize, result_formats: &[i16]) {
|
||||
buf.extend_from_slice(&(result_formats.len() as i16).to_be_bytes());
|
||||
|
||||
// statement
|
||||
buf.extend_from_slice(self.statement.as_bytes());
|
||||
buf.push(b'\0');
|
||||
|
||||
// formats.len
|
||||
buf.extend_from_slice(&(self.formats.len() as i16).to_be_bytes());
|
||||
|
||||
// formats
|
||||
for format in self.formats {
|
||||
buf.extend_from_slice(&format.to_be_bytes());
|
||||
}
|
||||
|
||||
// values
|
||||
buf.extend_from_slice(&self.buffer);
|
||||
|
||||
// result_formats.len
|
||||
buf.extend_from_slice(&(self.result_formats.len() as i16).to_be_bytes());
|
||||
|
||||
// result_formats
|
||||
for format in self.result_formats {
|
||||
buf.extend_from_slice(&format.to_be_bytes());
|
||||
}
|
||||
|
||||
let len = buf.len() - pos;
|
||||
BigEndian::write_u32(&mut buf[pos..], len as u32);
|
||||
|
||||
Ok(())
|
||||
for format in result_formats {
|
||||
buf.extend_from_slice(&format.to_be_bytes());
|
||||
}
|
||||
|
||||
// Calculate and emplace the total len of the message
|
||||
let len = buf.len() - state.0;
|
||||
BigEndian::write_u32(&mut buf[(state.0)..], len as u32);
|
||||
|
||||
// Emplace the total num of values
|
||||
BigEndian::write_u32(&mut buf[(state.1)..], values as u32);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
mod authentication;
|
||||
mod backend_key_data;
|
||||
mod bind;
|
||||
pub mod bind;
|
||||
mod command_complete;
|
||||
mod data_row;
|
||||
mod decode;
|
||||
|
@ -24,7 +24,6 @@ mod terminate;
|
|||
pub use self::{
|
||||
authentication::Authentication,
|
||||
backend_key_data::BackendKeyData,
|
||||
bind::Bind,
|
||||
command_complete::CommandComplete,
|
||||
data_row::DataRow,
|
||||
decode::Decode,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use super::Connection;
|
||||
use sqlx_postgres_protocol::{Bind, Execute, Message, Parse, Sync};
|
||||
use sqlx_postgres_protocol::{self as proto, Execute, Message, Parse, Sync};
|
||||
use std::io;
|
||||
|
||||
pub struct Prepare<'a> {
|
||||
connection: &'a mut Connection,
|
||||
bind_state: (usize, usize),
|
||||
bind_values: usize,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -12,20 +14,30 @@ pub fn prepare<'a, 'b>(connection: &'a mut Connection, query: &'b str) -> Prepar
|
|||
// TODO: Use named statements
|
||||
connection.send(Parse::new("", query, &[]));
|
||||
|
||||
Prepare { connection }
|
||||
let bind_state = proto::bind::header(&mut connection.wbuf, "", "", &[]);
|
||||
|
||||
Prepare { connection, bind_state, bind_values: 0 }
|
||||
}
|
||||
|
||||
impl<'a> Prepare<'a> {
|
||||
#[inline]
|
||||
pub fn bind<'b>(self, value: &'b [u8]) -> Self {
|
||||
// TODO: Encode the value here onto the wbuf
|
||||
pub fn bind<'b>(mut self, value: &'b [u8]) -> Self {
|
||||
proto::bind::value(&mut self.connection.wbuf, value);
|
||||
self.bind_values += 1;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bind_null<'b>(mut self) -> Self {
|
||||
proto::bind::value_null(&mut self.connection.wbuf);
|
||||
self.bind_values += 1;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn execute(self) -> io::Result<u64> {
|
||||
// FIXME: Break this up into BindHeader, BindValue, and BindTrailer
|
||||
self.connection.send(Bind::new("", "", &[], &[0, 0], &[]));
|
||||
proto::bind::trailer(&mut self.connection.wbuf, self.bind_state, self.bind_values, &[]);
|
||||
|
||||
self.connection.send(Execute::new("", 0));
|
||||
self.connection.send(Sync);
|
||||
self.connection.flush().await?;
|
||||
|
|
Loading…
Reference in a new issue