Update to protocol 0.2

This commit is contained in:
Steven Fackler 2016-12-18 16:11:38 -08:00
parent 8e5f28eb70
commit 9d53e677ff
9 changed files with 231 additions and 158 deletions

5
.gitignore vendored
View File

@ -1,5 +1,6 @@
target/
target
Cargo.lock
.cargo/
.cargo
.idea
*.iml
.vscode

View File

@ -41,7 +41,7 @@ fallible-iterator = "0.1.3"
hex = "0.2"
log = "0.3"
phf = "=0.7.20"
postgres-protocol = "0.1"
postgres-protocol = "0.2"
bit-vec = { version = "0.4", optional = true }
chrono = { version = "0.2.14", optional = true }
eui48 = { version = "0.1", optional = true }

View File

@ -120,10 +120,10 @@ fn make_impl(codes: &[Code], file: &mut BufWriter<File>) {
write!(file, r#"
impl SqlState {{
/// Creates a `SqlState` from its error code.
pub fn from_code(s: String) -> SqlState {{
match SQLSTATE_MAP.get(&*s) {{
pub fn from_code(s: &str) -> SqlState {{
match SQLSTATE_MAP.get(s) {{
Some(state) => state.clone(),
None => SqlState::Other(s),
None => SqlState::Other(s.to_owned()),
}}
}}

View File

@ -1,11 +1,12 @@
//! Error types.
use fallible_iterator::FallibleIterator;
use postgres_protocol::message::backend::ErrorFields;
use std::error;
use std::convert::From;
use std::fmt;
use std::io;
use std::result;
use std::collections::HashMap;
pub use self::sqlstate::SqlState;
use {Result, DbErrorNew};
@ -85,52 +86,92 @@ pub struct DbError {
}
impl DbErrorNew for DbError {
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()> {
let mut map: HashMap<_, _> = fields.into_iter().collect();
fn new_raw(fields: &mut ErrorFields) -> io::Result<DbError> {
let mut severity = None;
let mut code = None;
let mut message = None;
let mut detail = None;
let mut hint = None;
let mut normal_position = None;
let mut internal_position = None;
let mut internal_query = None;
let mut where_ = None;
let mut schema = None;
let mut table = None;
let mut column = None;
let mut datatype = None;
let mut constraint = None;
let mut file = None;
let mut line = None;
let mut routine = None;
while let Some(field) = try!(fields.next()) {
match field.type_() {
b'S' => severity = Some(field.value().to_owned()),
b'C' => code = Some(SqlState::from_code(field.value())),
b'M' => message = Some(field.value().to_owned()),
b'D' => detail = Some(field.value().to_owned()),
b'H' => hint = Some(field.value().to_owned()),
b'P' => normal_position = Some(try!(field.value().parse::<u32>().map_err(|_| ::bad_response()))),
b'p' => internal_position = Some(try!(field.value().parse::<u32>().map_err(|_| ::bad_response()))),
b'q' => internal_query = Some(field.value().to_owned()),
b'W' => where_ = Some(field.value().to_owned()),
b's' => schema = Some(field.value().to_owned()),
b't' => table = Some(field.value().to_owned()),
b'c' => column = Some(field.value().to_owned()),
b'd' => datatype = Some(field.value().to_owned()),
b'n' => constraint = Some(field.value().to_owned()),
b'F' => file = Some(field.value().to_owned()),
b'L' => line = Some(try!(field.value().parse::<u32>().map_err(|_| ::bad_response()))),
b'R' => routine = Some(field.value().to_owned()),
_ => {},
}
}
Ok(DbError {
severity: try!(map.remove(&b'S').ok_or(())),
code: SqlState::from_code(try!(map.remove(&b'C').ok_or(()))),
message: try!(map.remove(&b'M').ok_or(())),
detail: map.remove(&b'D'),
hint: map.remove(&b'H'),
position: match map.remove(&b'P') {
Some(pos) => Some(ErrorPosition::Normal(try!(pos.parse().map_err(|_| ())))),
severity: try!(severity.ok_or_else(|| ::bad_response())),
code: try!(code.ok_or_else(|| ::bad_response())),
message: try!(message.ok_or_else(|| ::bad_response())),
detail: detail,
hint: hint,
position: match normal_position {
Some(position) => Some(ErrorPosition::Normal(position)),
None => {
match map.remove(&b'p') {
Some(pos) => {
match internal_position {
Some(position) => {
Some(ErrorPosition::Internal {
position: try!(pos.parse().map_err(|_| ())),
query: try!(map.remove(&b'q').ok_or(())),
position: position,
query: try!(internal_query.ok_or_else(|| ::bad_response())),
})
}
None => None,
}
}
},
where_: map.remove(&b'W'),
schema: map.remove(&b's'),
table: map.remove(&b't'),
column: map.remove(&b'c'),
datatype: map.remove(&b'd'),
constraint: map.remove(&b'n'),
file: map.remove(&b'F'),
line: map.remove(&b'L').and_then(|l| l.parse().ok()),
routine: map.remove(&b'R'),
where_: where_,
schema: schema,
table: table,
column: column,
datatype: datatype,
constraint: constraint,
file: file,
line: line,
routine: routine,
_p: (),
})
}
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError> {
fn new_connect<T>(fields: &mut ErrorFields) -> result::Result<T, ConnectError> {
match DbError::new_raw(fields) {
Ok(err) => Err(ConnectError::Db(Box::new(err))),
Err(()) => Err(ConnectError::Io(::bad_response())),
Err(e) => Err(ConnectError::Io(e)),
}
}
fn new<T>(fields: Vec<(u8, String)>) -> Result<T> {
fn new<T>(fields: &mut ErrorFields) -> Result<T> {
match DbError::new_raw(fields) {
Ok(err) => Err(Error::Db(Box::new(err))),
Err(()) => Err(Error::Io(::bad_response())),
Err(e) => Err(Error::Io(e)),
}
}
}

View File

@ -782,10 +782,10 @@ static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map {
impl SqlState {
/// Creates a `SqlState` from its error code.
pub fn from_code(s: String) -> SqlState {
match SQLSTATE_MAP.get(&*s) {
pub fn from_code(s: &str) -> SqlState {
match SQLSTATE_MAP.get(s) {
Some(state) => state.clone(),
None => SqlState::Other(s),
None => SqlState::Other(s.to_owned()),
}
}

View File

@ -79,6 +79,7 @@ extern crate log;
extern crate phf;
extern crate postgres_protocol;
use fallible_iterator::FallibleIterator;
use std::cell::{Cell, RefCell};
use std::collections::{VecDeque, HashMap};
use std::fmt;
@ -88,7 +89,7 @@ use std::result;
use std::sync::Arc;
use std::time::Duration;
use postgres_protocol::authentication;
use postgres_protocol::message::backend::{self, RowDescriptionEntry};
use postgres_protocol::message::backend::{self, ErrorFields};
use postgres_protocol::message::frontend;
use error::{Error, ConnectError, SqlState, DbError};
@ -307,12 +308,14 @@ impl InnerConnection {
loop {
match try!(conn.read_message()) {
backend::Message::BackendKeyData { process_id, secret_key } => {
conn.cancel_data.process_id = process_id;
conn.cancel_data.secret_key = secret_key;
backend::Message::BackendKeyData(body) => {
conn.cancel_data.process_id = body.process_id();
conn.cancel_data.secret_key = body.secret_key();
}
backend::Message::ReadyForQuery(_) => break,
backend::Message::ErrorResponse(body) => {
return DbError::new_connect(&mut body.fields())
}
backend::Message::ReadyForQuery { .. } => break,
backend::Message::ErrorResponse { fields } => return DbError::new_connect(fields),
_ => return Err(ConnectError::Io(bad_response())),
}
}
@ -320,17 +323,18 @@ impl InnerConnection {
Ok(conn)
}
fn read_message_with_notification(&mut self) -> io::Result<backend::Message> {
fn read_message_with_notification(&mut self) -> io::Result<backend::Message<Vec<u8>>> {
debug_assert!(!self.desynchronized);
loop {
match try_desync!(self, self.stream.read_message()) {
backend::Message::NoticeResponse { fields } => {
if let Ok(err) = DbError::new_raw(fields) {
backend::Message::NoticeResponse(body) => {
if let Ok(err) = DbError::new_raw(&mut body.fields()) {
self.notice_handler.handle_notice(err);
}
}
backend::Message::ParameterStatus { parameter, value } => {
self.parameters.insert(parameter, value);
backend::Message::ParameterStatus(body) => {
self.parameters.insert(try!(body.name()).to_owned(),
try!(body.value()).to_owned());
}
val => return Ok(val),
}
@ -339,17 +343,18 @@ impl InnerConnection {
fn read_message_with_notification_timeout(&mut self,
timeout: Duration)
-> io::Result<Option<backend::Message>> {
-> io::Result<Option<backend::Message<Vec<u8>>>> {
debug_assert!(!self.desynchronized);
loop {
match try_desync!(self, self.stream.read_message_timeout(timeout)) {
Some(backend::Message::NoticeResponse { fields }) => {
if let Ok(err) = DbError::new_raw(fields) {
Some(backend::Message::NoticeResponse(body)) => {
if let Ok(err) = DbError::new_raw(&mut body.fields()) {
self.notice_handler.handle_notice(err);
}
}
Some(backend::Message::ParameterStatus { parameter, value }) => {
self.parameters.insert(parameter, value);
Some(backend::Message::ParameterStatus(body)) => {
self.parameters.insert(try!(body.name()).to_owned(),
try!(body.value()).to_owned());
}
val => return Ok(val),
}
@ -357,31 +362,32 @@ impl InnerConnection {
}
fn read_message_with_notification_nonblocking(&mut self)
-> io::Result<Option<backend::Message>> {
-> io::Result<Option<backend::Message<Vec<u8>>>> {
debug_assert!(!self.desynchronized);
loop {
match try_desync!(self, self.stream.read_message_nonblocking()) {
Some(backend::Message::NoticeResponse { fields }) => {
if let Ok(err) = DbError::new_raw(fields) {
Some(backend::Message::NoticeResponse(body)) => {
if let Ok(err) = DbError::new_raw(&mut body.fields()) {
self.notice_handler.handle_notice(err);
}
}
Some(backend::Message::ParameterStatus { parameter, value }) => {
self.parameters.insert(parameter, value);
Some(backend::Message::ParameterStatus(body)) => {
self.parameters.insert(try!(body.name()).to_owned(),
try!(body.value()).to_owned());
}
val => return Ok(val),
}
}
}
fn read_message(&mut self) -> io::Result<backend::Message> {
fn read_message(&mut self) -> io::Result<backend::Message<Vec<u8>>> {
loop {
match try!(self.read_message_with_notification()) {
backend::Message::NotificationResponse { process_id, channel, payload } => {
backend::Message::NotificationResponse(body) => {
self.notifications.push_back(Notification {
process_id: process_id,
channel: channel,
payload: payload,
process_id: body.process_id(),
channel: try!(body.channel()).to_owned(),
payload: try!(body.message()).to_owned(),
})
}
val => return Ok(val),
@ -399,28 +405,30 @@ impl InnerConnection {
try!(self.stream.write_message(|buf| frontend::password_message(&pass, buf)));
try!(self.stream.flush());
}
backend::Message::AuthenticationMD5Password { salt } => {
backend::Message::AuthenticationMd5Password(body) => {
let pass = try!(user.password.ok_or_else(|| {
ConnectError::ConnectParams("a password was requested but not provided".into())
}));
let output = authentication::md5_hash(user.user.as_bytes(), pass.as_bytes(), salt);
let output = authentication::md5_hash(user.user.as_bytes(),
pass.as_bytes(),
body.salt());
try!(self.stream.write_message(|buf| frontend::password_message(&output, buf)));
try!(self.stream.flush());
}
backend::Message::AuthenticationKerberosV5 |
backend::Message::AuthenticationSCMCredential |
backend::Message::AuthenticationGSS |
backend::Message::AuthenticationSSPI => {
backend::Message::AuthenticationScmCredential |
backend::Message::AuthenticationGss |
backend::Message::AuthenticationSspi => {
return Err(ConnectError::Io(io::Error::new(io::ErrorKind::Other,
"unsupported authentication")))
}
backend::Message::ErrorResponse { fields } => return DbError::new_connect(fields),
backend::Message::ErrorResponse(body) => return DbError::new_connect(&mut body.fields()),
_ => return Err(ConnectError::Io(bad_response())),
}
match try!(self.read_message()) {
backend::Message::AuthenticationOk => Ok(()),
backend::Message::ErrorResponse { fields } => DbError::new_connect(fields),
backend::Message::ErrorResponse(body) => DbError::new_connect(&mut body.fields()),
_ => Err(ConnectError::Io(bad_response())),
}
}
@ -439,35 +447,43 @@ impl InnerConnection {
match try!(self.read_message()) {
backend::Message::ParseComplete => {}
backend::Message::ErrorResponse { fields } => {
backend::Message::ErrorResponse(body) => {
try!(self.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
_ => bad_response!(self),
}
let raw_param_types = match try!(self.read_message()) {
backend::Message::ParameterDescription { types } => types,
backend::Message::ParameterDescription(body) => body,
_ => bad_response!(self),
};
let raw_columns = match try!(self.read_message()) {
backend::Message::RowDescription { descriptions } => descriptions,
backend::Message::NoData => vec![],
backend::Message::RowDescription(body) => Some(body),
backend::Message::NoData => None,
_ => bad_response!(self),
};
try!(self.wait_for_ready());
let mut param_types = vec![];
for oid in raw_param_types {
param_types.push(try!(self.get_type(oid)));
}
let mut columns = vec![];
for RowDescriptionEntry { name, type_oid, .. } in raw_columns {
columns.push(Column::new(name, try!(self.get_type(type_oid))));
}
let param_types = try!(raw_param_types
.parameters()
.map_err(Into::into)
.and_then(|oid| self.get_type(oid))
.collect());
let columns = match raw_columns {
Some(body) => {
try!(body.fields()
.and_then(|field| {
Ok(Column::new(field.name().to_owned(),
try!(self.get_type(field.type_oid()))))
})
.collect())
}
None => vec![],
};
Ok((param_types, columns))
}
@ -477,7 +493,7 @@ impl InnerConnection {
loop {
match try!(self.read_message()) {
backend::Message::EmptyQueryResponse |
backend::Message::CommandComplete { .. } => {
backend::Message::CommandComplete(_) => {
more_rows = false;
break;
}
@ -485,12 +501,15 @@ impl InnerConnection {
more_rows = true;
break;
}
backend::Message::DataRow { row } => buf.push_back(row),
backend::Message::ErrorResponse { fields } => {
try!(self.wait_for_ready());
return DbError::new(fields);
backend::Message::DataRow(body) => {
let row = try!(body.values().map(|v| v.map(ToOwned::to_owned)).collect());
buf.push_back(row);
}
backend::Message::CopyInResponse { .. } => {
backend::Message::ErrorResponse(body) => {
try!(self.wait_for_ready());
return DbError::new(&mut body.fields());
}
backend::Message::CopyInResponse(_) => {
try!(self.stream.write_message(|buf| {
frontend::copy_fail("COPY queries cannot be directly executed", buf)
}));
@ -498,9 +517,9 @@ impl InnerConnection {
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf))));
try!(self.stream.flush());
}
backend::Message::CopyOutResponse { .. } => {
backend::Message::CopyOutResponse(_) => {
loop {
if let backend::Message::ReadyForQuery { .. } = try!(self.read_message()) {
if let backend::Message::ReadyForQuery(_) = try!(self.read_message()) {
break;
}
}
@ -563,9 +582,9 @@ impl InnerConnection {
match try!(self.read_message()) {
backend::Message::BindComplete => Ok(()),
backend::Message::ErrorResponse { fields } => {
backend::Message::ErrorResponse(body) => {
try!(self.wait_for_ready());
DbError::new(fields)
DbError::new(&mut body.fields())
}
_ => {
self.desynchronized = true;
@ -618,7 +637,7 @@ impl InnerConnection {
try!(self.stream.flush());
let resp = match try!(self.read_message()) {
backend::Message::CloseComplete => Ok(()),
backend::Message::ErrorResponse { fields } => DbError::new(fields),
backend::Message::ErrorResponse(body) => DbError::new(&mut body.fields()),
_ => bad_response!(self),
};
try!(self.wait_for_ready());
@ -813,7 +832,7 @@ impl InnerConnection {
#[allow(needless_return)]
fn wait_for_ready(&mut self) -> Result<()> {
match try!(self.read_message()) {
backend::Message::ReadyForQuery { .. } => Ok(()),
backend::Message::ReadyForQuery(_) => Ok(()),
_ => bad_response!(self),
}
}
@ -827,13 +846,14 @@ impl InnerConnection {
let mut result = vec![];
loop {
match try!(self.read_message()) {
backend::Message::ReadyForQuery { .. } => break,
backend::Message::DataRow { row } => {
result.push(row.into_iter()
.map(|opt| opt.map(|b| String::from_utf8_lossy(&b).into_owned()))
backend::Message::ReadyForQuery(_) => break,
backend::Message::DataRow(body) => {
let row = try!(body.values()
.map(|v| v.map(|v| String::from_utf8_lossy(v).into_owned()))
.collect());
result.push(row);
}
backend::Message::CopyInResponse { .. } => {
backend::Message::CopyInResponse(_) => {
try!(self.stream.write_message(|buf| {
frontend::copy_fail("COPY queries cannot be directly executed", buf)
}));
@ -841,9 +861,9 @@ impl InnerConnection {
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf))));
try!(self.stream.flush());
}
backend::Message::ErrorResponse { fields } => {
backend::Message::ErrorResponse(body) => {
try!(self.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
_ => {}
}
@ -1314,9 +1334,9 @@ trait OtherNew {
}
trait DbErrorNew {
fn new_raw(fields: Vec<(u8, String)>) -> result::Result<DbError, ()>;
fn new_connect<T>(fields: Vec<(u8, String)>) -> result::Result<T, ConnectError>;
fn new<T>(fields: Vec<(u8, String)>) -> Result<T>;
fn new_raw(fields: &mut ErrorFields) -> io::Result<DbError>;
fn new_connect<T>(fields: &mut ErrorFields) -> result::Result<T, ConnectError>;
fn new<T>(fields: &mut ErrorFields) -> Result<T>;
}
trait RowsNew<'a> {

View File

@ -113,11 +113,11 @@ impl<'a> FallibleIterator for Iter<'a> {
}
match conn.read_message_with_notification_nonblocking() {
Ok(Some(backend::Message::NotificationResponse { process_id, channel, payload })) => {
Ok(Some(backend::Message::NotificationResponse(body))) => {
Ok(Some(Notification {
process_id: process_id,
channel: channel,
payload: payload,
process_id: body.process_id(),
channel: try!(body.channel()).to_owned(),
payload: try!(body.message()).to_owned(),
}))
}
Ok(None) => Ok(None),
@ -152,11 +152,11 @@ impl<'a> FallibleIterator for BlockingIter<'a> {
}
match conn.read_message_with_notification() {
Ok(backend::Message::NotificationResponse { process_id, channel, payload }) => {
Ok(backend::Message::NotificationResponse(body)) => {
Ok(Some(Notification {
process_id: process_id,
channel: channel,
payload: payload,
process_id: body.process_id(),
channel: try!(body.channel()).to_owned(),
payload: try!(body.message()).to_owned(),
}))
}
Err(err) => Err(Error::Io(err)),
@ -188,11 +188,11 @@ impl<'a> FallibleIterator for TimeoutIter<'a> {
}
match conn.read_message_with_notification_timeout(self.timeout) {
Ok(Some(backend::Message::NotificationResponse { process_id, channel, payload })) => {
Ok(Some(backend::Message::NotificationResponse(body))) => {
Ok(Some(Notification {
process_id: process_id,
channel: channel,
payload: payload,
process_id: body.process_id(),
channel: try!(body.channel()).to_owned(),
payload: try!(body.message()).to_owned(),
}))
}
Ok(None) => Ok(None),

View File

@ -47,12 +47,12 @@ impl MessageStream {
self.stream.write_all(&self.buf).map_err(From::from)
}
fn inner_read_message(&mut self, b: u8) -> io::Result<backend::Message> {
fn inner_read_message(&mut self, b: u8) -> io::Result<backend::Message<Vec<u8>>> {
self.buf.resize(MESSAGE_HEADER_SIZE, 0);
self.buf[0] = b;
try!(self.stream.read_exact(&mut self.buf[1..]));
let len = match try!(backend::Message::parse(&self.buf)) {
let len = match try!(backend::Message::parse_owned(&self.buf)) {
ParseResult::Complete { message, .. } => return Ok(message),
ParseResult::Incomplete { required_size } => Some(required_size.unwrap()),
};
@ -62,13 +62,13 @@ impl MessageStream {
try!(self.stream.read_exact(&mut self.buf[MESSAGE_HEADER_SIZE..]));
};
match try!(backend::Message::parse(&self.buf)) {
match try!(backend::Message::parse_owned(&self.buf)) {
ParseResult::Complete { message, .. } => Ok(message),
ParseResult::Incomplete { .. } => unreachable!(),
}
}
pub fn read_message(&mut self) -> io::Result<backend::Message> {
pub fn read_message(&mut self) -> io::Result<backend::Message<Vec<u8>>> {
let mut b = [0; 1];
try!(self.stream.read_exact(&mut b));
self.inner_read_message(b[0])
@ -76,7 +76,7 @@ impl MessageStream {
pub fn read_message_timeout(&mut self,
timeout: Duration)
-> io::Result<Option<backend::Message>> {
-> io::Result<Option<backend::Message<Vec<u8>>>> {
try!(self.set_read_timeout(Some(timeout)));
let mut b = [0; 1];
let r = self.stream.read_exact(&mut b);
@ -90,7 +90,7 @@ impl MessageStream {
}
}
pub fn read_message_nonblocking(&mut self) -> io::Result<Option<backend::Message>> {
pub fn read_message_nonblocking(&mut self) -> io::Result<Option<backend::Message<Vec<u8>>>> {
try!(self.set_nonblocking(true));
let mut b = [0; 1];
let r = self.stream.read_exact(&mut b);

View File

@ -1,5 +1,6 @@
//! Prepared statements
use fallible_iterator::FallibleIterator;
use std::cell::{Cell, RefMut};
use std::collections::VecDeque;
use std::fmt;
@ -132,20 +133,20 @@ impl<'conn> Statement<'conn> {
let num;
loop {
match try!(conn.read_message()) {
backend::Message::DataRow { .. } => {}
backend::Message::ErrorResponse { fields } => {
backend::Message::DataRow(_) => {}
backend::Message::ErrorResponse(body) => {
try!(conn.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
backend::Message::CommandComplete { tag } => {
num = parse_update_count(tag);
backend::Message::CommandComplete(body) => {
num = parse_update_count(try!(body.tag()));
break;
}
backend::Message::EmptyQueryResponse => {
num = 0;
break;
}
backend::Message::CopyInResponse { .. } => {
backend::Message::CopyInResponse(_) => {
try!(conn.stream.write_message(|buf| {
frontend::copy_fail("COPY queries cannot be directly executed", buf)
}));
@ -153,13 +154,13 @@ impl<'conn> Statement<'conn> {
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf))));
try!(conn.stream.flush());
}
backend::Message::CopyOutResponse { .. } => {
backend::Message::CopyOutResponse(_) => {
loop {
match try!(conn.read_message()) {
backend::Message::CopyDone => break,
backend::Message::ErrorResponse { fields } => {
backend::Message::ErrorResponse(body) => {
try!(conn.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
_ => {}
}
@ -269,14 +270,20 @@ impl<'conn> Statement<'conn> {
try!(conn.raw_execute(&self.info.name, "", 0, self.param_types(), params));
let (format, column_formats) = match try!(conn.read_message()) {
backend::Message::CopyInResponse { format, column_formats } => (format, column_formats),
backend::Message::ErrorResponse { fields } => {
backend::Message::CopyInResponse(body) => {
let format = body.format();
let column_formats = try!(body.column_formats()
.map(|f| Format::from_u16(f))
.collect());
(format, column_formats)
}
backend::Message::ErrorResponse(body) => {
try!(conn.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
_ => {
loop {
if let backend::Message::ReadyForQuery { .. } = try!(conn.read_message()) {
if let backend::Message::ReadyForQuery(_) = try!(conn.read_message()) {
return Err(Error::Io(io::Error::new(io::ErrorKind::InvalidInput,
"called `copy_in` on a \
non-`COPY FROM STDIN` \
@ -289,7 +296,7 @@ impl<'conn> Statement<'conn> {
let mut info = CopyInfo {
conn: conn,
format: Format::from_u16(format as u16),
column_formats: column_formats.iter().map(|&f| Format::from_u16(f)).collect(),
column_formats: column_formats,
};
let mut buf = [0; 16 * 1024];
@ -311,7 +318,7 @@ impl<'conn> Statement<'conn> {
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf))));
try!(info.conn.stream.flush());
match try!(info.conn.read_message()) {
backend::Message::ErrorResponse { .. } => {
backend::Message::ErrorResponse(_) => {
// expected from the CopyFail
}
_ => {
@ -330,10 +337,10 @@ impl<'conn> Statement<'conn> {
try!(info.conn.stream.flush());
let num = match try!(info.conn.read_message()) {
backend::Message::CommandComplete { tag } => parse_update_count(tag),
backend::Message::ErrorResponse { fields } => {
backend::Message::CommandComplete(body) => parse_update_count(try!(body.tag())),
backend::Message::ErrorResponse(body) => {
try!(info.conn.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
_ => {
info.conn.desynchronized = true;
@ -372,17 +379,21 @@ impl<'conn> Statement<'conn> {
try!(conn.raw_execute(&self.info.name, "", 0, self.param_types(), params));
let (format, column_formats) = match try!(conn.read_message()) {
backend::Message::CopyOutResponse { format, column_formats } => {
backend::Message::CopyOutResponse(body) => {
let format = body.format();
let column_formats = try!(body.column_formats()
.map(|f| Format::from_u16(f))
.collect());
(format, column_formats)
}
backend::Message::CopyInResponse { .. } => {
backend::Message::CopyInResponse(_) => {
try!(conn.stream.write_message(|buf| frontend::copy_fail("", buf)));
try!(conn.stream
.write_message(|buf| Ok::<(), io::Error>(frontend::copy_done(buf))));
try!(conn.stream.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf))));
try!(conn.stream.flush());
match try!(conn.read_message()) {
backend::Message::ErrorResponse { .. } => {
backend::Message::ErrorResponse(_) => {
// expected from the CopyFail
}
_ => {
@ -395,13 +406,13 @@ impl<'conn> Statement<'conn> {
"called `copy_out` on a non-`COPY TO \
STDOUT` statement")));
}
backend::Message::ErrorResponse { fields } => {
backend::Message::ErrorResponse(body) => {
try!(conn.wait_for_ready());
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
_ => {
loop {
if let backend::Message::ReadyForQuery { .. } = try!(conn.read_message()) {
if let backend::Message::ReadyForQuery(_) = try!(conn.read_message()) {
return Err(Error::Io(io::Error::new(io::ErrorKind::InvalidInput,
"called `copy_out` on a \
non-`COPY TO STDOUT` statement")));
@ -413,20 +424,20 @@ impl<'conn> Statement<'conn> {
let mut info = CopyInfo {
conn: conn,
format: Format::from_u16(format as u16),
column_formats: column_formats.iter().map(|&f| Format::from_u16(f)).collect(),
column_formats: column_formats,
};
let count;
loop {
match try!(info.conn.read_message()) {
backend::Message::CopyData { data } => {
let mut data = &data[..];
backend::Message::CopyData(body) => {
let mut data = body.data();
while !data.is_empty() {
match w.write_with_info(data, &info) {
Ok(n) => data = &data[n..],
Err(e) => {
loop {
if let backend::Message::ReadyForQuery { .. } =
if let backend::Message::ReadyForQuery(_) =
try!(info.conn.read_message()) {
return Err(Error::Io(e));
}
@ -436,21 +447,21 @@ impl<'conn> Statement<'conn> {
}
}
backend::Message::CopyDone => {}
backend::Message::CommandComplete { tag } => {
count = parse_update_count(tag);
backend::Message::CommandComplete(body) => {
count = parse_update_count(try!(body.tag()));
break;
}
backend::Message::ErrorResponse { fields } => {
backend::Message::ErrorResponse(body) => {
loop {
if let backend::Message::ReadyForQuery { .. } =
if let backend::Message::ReadyForQuery(_) =
try!(info.conn.read_message()) {
return DbError::new(fields);
return DbError::new(&mut body.fields());
}
}
}
_ => {
loop {
if let backend::Message::ReadyForQuery { .. } =
if let backend::Message::ReadyForQuery(_) =
try!(info.conn.read_message()) {
return Err(Error::Io(bad_response()));
}
@ -586,6 +597,6 @@ impl Format {
}
}
fn parse_update_count(tag: String) -> u64 {
fn parse_update_count(tag: &str) -> u64 {
tag.split(' ').last().unwrap().parse().unwrap_or(0)
}