Rustfmt
This commit is contained in:
parent
3809972907
commit
6a86f8dd85
@ -71,43 +71,51 @@ fn variant_name(code: &str) -> Option<String> {
|
||||
}
|
||||
|
||||
fn make_header(file: &mut BufWriter<File>) {
|
||||
write!(file,
|
||||
"// Autogenerated file - DO NOT EDIT
|
||||
write!(
|
||||
file,
|
||||
"// Autogenerated file - DO NOT EDIT
|
||||
use phf;
|
||||
|
||||
"
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
fn make_enum(codes: &[Code], file: &mut BufWriter<File>) {
|
||||
write!(file,
|
||||
r#"/// SQLSTATE error codes
|
||||
write!(
|
||||
file,
|
||||
r#"/// SQLSTATE error codes
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
#[allow(enum_variant_names)]
|
||||
pub enum SqlState {{
|
||||
"#
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
|
||||
for code in codes {
|
||||
write!(file,
|
||||
" /// `{}`
|
||||
write!(
|
||||
file,
|
||||
" /// `{}`
|
||||
{},\n",
|
||||
code.code, code.variant).unwrap();
|
||||
code.code,
|
||||
code.variant
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(file,
|
||||
" /// An unknown code
|
||||
write!(
|
||||
file,
|
||||
" /// An unknown code
|
||||
Other(String),
|
||||
}}
|
||||
|
||||
"
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
fn make_map(codes: &[Code], file: &mut BufWriter<File>) {
|
||||
write!(file,
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ").unwrap();
|
||||
write!(
|
||||
file,
|
||||
"#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = "
|
||||
).unwrap();
|
||||
let mut builder = phf_codegen::Map::new();
|
||||
for code in codes {
|
||||
builder.entry(&*code.code, &format!("SqlState::{}", code.variant));
|
||||
@ -117,7 +125,9 @@ static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ").unwrap();
|
||||
}
|
||||
|
||||
fn make_impl(codes: &[Code], file: &mut BufWriter<File>) {
|
||||
write!(file, r#"
|
||||
write!(
|
||||
file,
|
||||
r#"
|
||||
impl SqlState {{
|
||||
/// Creates a `SqlState` from its error code.
|
||||
pub fn from_code(s: &str) -> SqlState {{
|
||||
@ -130,20 +140,25 @@ impl SqlState {{
|
||||
/// Returns the error code corresponding to the `SqlState`.
|
||||
pub fn code(&self) -> &str {{
|
||||
match *self {{"#
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
|
||||
for code in codes {
|
||||
write!(file, r#"
|
||||
write!(
|
||||
file,
|
||||
r#"
|
||||
SqlState::{} => "{}","#,
|
||||
code.variant, code.code).unwrap();
|
||||
code.variant,
|
||||
code.code
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(file, r#"
|
||||
write!(
|
||||
file,
|
||||
r#"
|
||||
SqlState::Other(ref s) => s,
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"#
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
|
@ -94,9 +94,10 @@ fn parse_types(ranges: &BTreeMap<u32, u32>) -> BTreeMap<u32, Type> {
|
||||
let doc = array_re.replace(name, "$1[]");
|
||||
let mut doc = doc.to_ascii_uppercase();
|
||||
|
||||
let descr = lines.peek()
|
||||
.and_then(|line| doc_re.captures(line))
|
||||
.and_then(|captures| captures.at(1));
|
||||
let descr = lines
|
||||
.peek()
|
||||
.and_then(|line| doc_re.captures(line))
|
||||
.and_then(|captures| captures.at(1));
|
||||
if let Some(descr) = descr {
|
||||
doc.push_str(" - ");
|
||||
doc.push_str(descr);
|
||||
@ -119,38 +120,45 @@ fn parse_types(ranges: &BTreeMap<u32, u32>) -> BTreeMap<u32, Type> {
|
||||
}
|
||||
|
||||
fn make_header(w: &mut BufWriter<File>) {
|
||||
write!(w,
|
||||
"// Autogenerated file - DO NOT EDIT
|
||||
write!(
|
||||
w,
|
||||
"// Autogenerated file - DO NOT EDIT
|
||||
use std::fmt;
|
||||
|
||||
use types::{{Oid, Kind, Other}};
|
||||
|
||||
"
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
fn make_enum(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
write!(w,
|
||||
"/// A Postgres type.
|
||||
write!(
|
||||
w,
|
||||
"/// A Postgres type.
|
||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||
pub enum Type {{
|
||||
"
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
|
||||
for type_ in types.values() {
|
||||
write!(w,
|
||||
" /// {}
|
||||
write!(
|
||||
w,
|
||||
" /// {}
|
||||
{},
|
||||
"
|
||||
, type_.doc, type_.variant).unwrap();
|
||||
",
|
||||
type_.doc,
|
||||
type_.variant
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(w,
|
||||
r" /// An unknown type.
|
||||
write!(
|
||||
w,
|
||||
r" /// An unknown type.
|
||||
Other(Other),
|
||||
}}
|
||||
|
||||
" ).unwrap();
|
||||
"
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
fn make_display_impl(w: &mut BufWriter<File>) {
|
||||
@ -180,10 +188,13 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
).unwrap();
|
||||
|
||||
for (oid, type_) in types {
|
||||
write!(w,
|
||||
" {} => Some(Type::{}),
|
||||
write!(
|
||||
w,
|
||||
" {} => Some(Type::{}),
|
||||
",
|
||||
oid, type_.variant).unwrap();
|
||||
oid,
|
||||
type_.variant
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(w,
|
||||
@ -199,10 +210,13 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
|
||||
|
||||
for (oid, type_) in types {
|
||||
write!(w,
|
||||
" Type::{} => {},
|
||||
write!(
|
||||
w,
|
||||
" Type::{} => {},
|
||||
",
|
||||
type_.variant, oid).unwrap();
|
||||
type_.variant,
|
||||
oid
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(w,
|
||||
@ -224,13 +238,16 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
_ => "Simple".to_owned(),
|
||||
};
|
||||
|
||||
write!(w,
|
||||
" Type::{} => {{
|
||||
write!(
|
||||
w,
|
||||
" Type::{} => {{
|
||||
const V: &'static Kind = &Kind::{};
|
||||
V
|
||||
}}
|
||||
",
|
||||
type_.variant, kind).unwrap();
|
||||
type_.variant,
|
||||
kind
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(w,
|
||||
@ -253,17 +270,21 @@ r#" Type::Other(ref u) => u.kind(),
|
||||
).unwrap();
|
||||
|
||||
for type_ in types.values() {
|
||||
write!(w,
|
||||
r#" Type::{} => "{}",
|
||||
write!(
|
||||
w,
|
||||
r#" Type::{} => "{}",
|
||||
"#,
|
||||
type_.variant, type_.name).unwrap();
|
||||
type_.variant,
|
||||
type_.name
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
write!(w,
|
||||
" Type::Other(ref u) => u.name(),
|
||||
write!(
|
||||
w,
|
||||
" Type::Other(ref u) => u.name(),
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
"
|
||||
).unwrap();
|
||||
).unwrap();
|
||||
}
|
||||
|
@ -30,7 +30,9 @@ mod test {
|
||||
let password = b"password";
|
||||
let salt = [0x2a, 0x3d, 0x8f, 0xe0];
|
||||
|
||||
assert_eq!(md5_hash(username, password, salt),
|
||||
"md562af4dd09bbb41884907a838a3233294");
|
||||
assert_eq!(
|
||||
md5_hash(username, password, salt),
|
||||
"md562af4dd09bbb41884907a838a3233294"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -89,12 +89,12 @@ impl ScramSha256 {
|
||||
let mut rng = OsRng::new()?;
|
||||
let nonce = (0..NONCE_LENGTH)
|
||||
.map(|_| {
|
||||
let mut v = rng.gen_range(0x21u8, 0x7e);
|
||||
if v == 0x2c {
|
||||
v = 0x7e
|
||||
}
|
||||
v as char
|
||||
})
|
||||
let mut v = rng.gen_range(0x21u8, 0x7e);
|
||||
if v == 0x2c {
|
||||
v = 0x7e
|
||||
}
|
||||
v as char
|
||||
})
|
||||
.collect::<String>();
|
||||
|
||||
ScramSha256::new_inner(password, nonce)
|
||||
@ -108,12 +108,12 @@ impl ScramSha256 {
|
||||
let password = normalize(password);
|
||||
|
||||
Ok(ScramSha256 {
|
||||
message: message,
|
||||
state: State::Update {
|
||||
nonce: nonce,
|
||||
password: password,
|
||||
},
|
||||
})
|
||||
message: message,
|
||||
state: State::Update {
|
||||
nonce: nonce,
|
||||
password: password,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the message which should be sent to the backend in an `SASLResponse` message.
|
||||
@ -133,8 +133,9 @@ impl ScramSha256 {
|
||||
_ => return Err(io::Error::new(io::ErrorKind::Other, "invalid SCRAM state")),
|
||||
};
|
||||
|
||||
let message = str::from_utf8(message)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
|
||||
let message = str::from_utf8(message).map_err(|e| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, e)
|
||||
})?;
|
||||
|
||||
let parsed = Parser::new(message).server_first_message()?;
|
||||
|
||||
@ -193,14 +194,18 @@ impl ScramSha256 {
|
||||
_ => return Err(io::Error::new(io::ErrorKind::Other, "invalid SCRAM state")),
|
||||
};
|
||||
|
||||
let message = str::from_utf8(message)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
|
||||
let message = str::from_utf8(message).map_err(|e| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, e)
|
||||
})?;
|
||||
|
||||
let parsed = Parser::new(message).server_final_message()?;
|
||||
|
||||
let verifier = match parsed {
|
||||
ServerFinalMessage::Error(e) => {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, format!("SCRAM error: {}", e)))
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("SCRAM error: {}", e),
|
||||
))
|
||||
}
|
||||
ServerFinalMessage::Verifier(verifier) => verifier,
|
||||
};
|
||||
@ -219,7 +224,10 @@ impl ScramSha256 {
|
||||
if hmac.verify(&verifier) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "SCRAM verification error"))
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"SCRAM verification error",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,18 +249,24 @@ impl<'a> Parser<'a> {
|
||||
match self.it.next() {
|
||||
Some((_, c)) if c == target => Ok(()),
|
||||
Some((i, c)) => {
|
||||
let m = format!("unexpected character at byte {}: expected `{}` but got `{}",
|
||||
i,
|
||||
target,
|
||||
c);
|
||||
let m = format!(
|
||||
"unexpected character at byte {}: expected `{}` but got `{}",
|
||||
i,
|
||||
target,
|
||||
c
|
||||
);
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, m))
|
||||
}
|
||||
None => Err(io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF")),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn take_while<F>(&mut self, f: F) -> io::Result<&'a str>
|
||||
where F: Fn(char) -> bool
|
||||
where
|
||||
F: Fn(char) -> bool,
|
||||
{
|
||||
let start = match self.it.peek() {
|
||||
Some(&(i, _)) => i,
|
||||
@ -272,9 +286,9 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn printable(&mut self) -> io::Result<&'a str> {
|
||||
self.take_while(|c| match c {
|
||||
'\x21'...'\x2b' | '\x2d'...'\x7e' => true,
|
||||
_ => false,
|
||||
})
|
||||
'\x21'...'\x2b' | '\x2d'...'\x7e' => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn nonce(&mut self) -> io::Result<&'a str> {
|
||||
@ -285,9 +299,9 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn base64(&mut self) -> io::Result<&'a str> {
|
||||
self.take_while(|c| match c {
|
||||
'a'...'z' | 'A'...'Z' | '0'...'9' | '/' | '+' | '=' => true,
|
||||
_ => false,
|
||||
})
|
||||
'a'...'z' | 'A'...'Z' | '0'...'9' | '/' | '+' | '=' => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn salt(&mut self) -> io::Result<&'a str> {
|
||||
@ -298,11 +312,12 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn posit_number(&mut self) -> io::Result<u32> {
|
||||
let n = self.take_while(|c| match c {
|
||||
'0'...'9' => true,
|
||||
_ => false,
|
||||
})?;
|
||||
n.parse()
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))
|
||||
'0'...'9' => true,
|
||||
_ => false,
|
||||
})?;
|
||||
n.parse().map_err(
|
||||
|e| io::Error::new(io::ErrorKind::InvalidInput, e),
|
||||
)
|
||||
}
|
||||
|
||||
fn iteration_count(&mut self) -> io::Result<u32> {
|
||||
@ -314,8 +329,10 @@ impl<'a> Parser<'a> {
|
||||
fn eof(&mut self) -> io::Result<()> {
|
||||
match self.it.peek() {
|
||||
Some(&(i, _)) => {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
format!("unexpected trailing data at byte {}", i)))
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("unexpected trailing data at byte {}", i),
|
||||
))
|
||||
}
|
||||
None => Ok(()),
|
||||
}
|
||||
@ -330,17 +347,17 @@ impl<'a> Parser<'a> {
|
||||
self.eof()?;
|
||||
|
||||
Ok(ServerFirstMessage {
|
||||
nonce: nonce,
|
||||
salt: salt,
|
||||
iteration_count: iteration_count,
|
||||
})
|
||||
nonce: nonce,
|
||||
salt: salt,
|
||||
iteration_count: iteration_count,
|
||||
})
|
||||
}
|
||||
|
||||
fn value(&mut self) -> io::Result<&'a str> {
|
||||
self.take_while(|c| match c {
|
||||
'\0' | '=' | ',' => false,
|
||||
_ => true,
|
||||
})
|
||||
'\0' | '=' | ',' => false,
|
||||
_ => true,
|
||||
})
|
||||
}
|
||||
|
||||
fn server_error(&mut self) -> io::Result<Option<&'a str>> {
|
||||
|
@ -43,8 +43,9 @@ pub enum IsNull {
|
||||
|
||||
#[inline]
|
||||
fn write_nullable<F, E>(serializer: F, buf: &mut Vec<u8>) -> Result<(), E>
|
||||
where F: FnOnce(&mut Vec<u8>) -> Result<IsNull, E>,
|
||||
E: From<io::Error>
|
||||
where
|
||||
F: FnOnce(&mut Vec<u8>) -> Result<IsNull, E>,
|
||||
E: From<io::Error>,
|
||||
{
|
||||
let base = buf.len();
|
||||
buf.extend_from_slice(&[0; 4]);
|
||||
|
@ -61,7 +61,10 @@ impl Message {
|
||||
let len = (&buf[1..5]).read_u32::<BigEndian>().unwrap();
|
||||
|
||||
if len < 4 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
|
||||
let total_len = len as usize + 1;
|
||||
@ -85,10 +88,10 @@ impl Message {
|
||||
let channel = buf.read_cstr()?;
|
||||
let message = buf.read_cstr()?;
|
||||
Message::NotificationResponse(NotificationResponseBody {
|
||||
process_id: process_id,
|
||||
channel: channel,
|
||||
message: message,
|
||||
})
|
||||
process_id: process_id,
|
||||
channel: channel,
|
||||
message: message,
|
||||
})
|
||||
}
|
||||
b'c' => Message::CopyDone,
|
||||
b'C' => {
|
||||
@ -103,9 +106,9 @@ impl Message {
|
||||
let len = buf.read_u16::<BigEndian>()?;
|
||||
let storage = buf.read_all();
|
||||
Message::DataRow(DataRowBody {
|
||||
storage: storage,
|
||||
len: len,
|
||||
})
|
||||
storage: storage,
|
||||
len: len,
|
||||
})
|
||||
}
|
||||
b'E' => {
|
||||
let storage = buf.read_all();
|
||||
@ -116,29 +119,29 @@ impl Message {
|
||||
let len = buf.read_u16::<BigEndian>()?;
|
||||
let storage = buf.read_all();
|
||||
Message::CopyInResponse(CopyInResponseBody {
|
||||
format: format,
|
||||
len: len,
|
||||
storage: storage,
|
||||
})
|
||||
format: format,
|
||||
len: len,
|
||||
storage: storage,
|
||||
})
|
||||
}
|
||||
b'H' => {
|
||||
let format = buf.read_u8()?;
|
||||
let len = buf.read_u16::<BigEndian>()?;
|
||||
let storage = buf.read_all();
|
||||
Message::CopyOutResponse(CopyOutResponseBody {
|
||||
format: format,
|
||||
len: len,
|
||||
storage: storage,
|
||||
})
|
||||
format: format,
|
||||
len: len,
|
||||
storage: storage,
|
||||
})
|
||||
}
|
||||
b'I' => Message::EmptyQueryResponse,
|
||||
b'K' => {
|
||||
let process_id = buf.read_i32::<BigEndian>()?;
|
||||
let secret_key = buf.read_i32::<BigEndian>()?;
|
||||
Message::BackendKeyData(BackendKeyDataBody {
|
||||
process_id: process_id,
|
||||
secret_key: secret_key,
|
||||
})
|
||||
process_id: process_id,
|
||||
secret_key: secret_key,
|
||||
})
|
||||
}
|
||||
b'n' => Message::NoData,
|
||||
b'N' => {
|
||||
@ -153,9 +156,9 @@ impl Message {
|
||||
5 => {
|
||||
let mut salt = [0; 4];
|
||||
buf.read_exact(&mut salt)?;
|
||||
Message::AuthenticationMd5Password(AuthenticationMd5PasswordBody {
|
||||
salt: salt,
|
||||
})
|
||||
Message::AuthenticationMd5Password(
|
||||
AuthenticationMd5PasswordBody { salt: salt },
|
||||
)
|
||||
}
|
||||
6 => Message::AuthenticationScmCredential,
|
||||
7 => Message::AuthenticationGss,
|
||||
@ -177,8 +180,10 @@ impl Message {
|
||||
Message::AuthenticationSaslFinal(AuthenticationSaslFinalBody(storage))
|
||||
}
|
||||
tag => {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
format!("unknown authentication tag `{}`", tag)));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("unknown authentication tag `{}`", tag),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,38 +192,43 @@ impl Message {
|
||||
let name = buf.read_cstr()?;
|
||||
let value = buf.read_cstr()?;
|
||||
Message::ParameterStatus(ParameterStatusBody {
|
||||
name: name,
|
||||
value: value,
|
||||
})
|
||||
name: name,
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
b't' => {
|
||||
let len = buf.read_u16::<BigEndian>()?;
|
||||
let storage = buf.read_all();
|
||||
Message::ParameterDescription(ParameterDescriptionBody {
|
||||
storage: storage,
|
||||
len: len,
|
||||
})
|
||||
storage: storage,
|
||||
len: len,
|
||||
})
|
||||
}
|
||||
b'T' => {
|
||||
let len = buf.read_u16::<BigEndian>()?;
|
||||
let storage = buf.read_all();
|
||||
Message::RowDescription(RowDescriptionBody {
|
||||
storage: storage,
|
||||
len: len,
|
||||
})
|
||||
storage: storage,
|
||||
len: len,
|
||||
})
|
||||
}
|
||||
b'Z' => {
|
||||
let status = buf.read_u8()?;
|
||||
Message::ReadyForQuery(ReadyForQueryBody { status: status })
|
||||
}
|
||||
tag => {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
format!("unknown message tag `{}`", tag)));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("unknown message tag `{}`", tag),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
if !buf.is_empty() {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Some(message))
|
||||
@ -248,7 +258,10 @@ impl Buffer {
|
||||
self.idx = end + 1;
|
||||
Ok(cstr)
|
||||
}
|
||||
None => Err(io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF")),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,7 +325,10 @@ impl<'a> FallibleIterator for SaslMechanisms<'a> {
|
||||
let value_end = find_null(self.0, 0)?;
|
||||
if value_end == 0 {
|
||||
if self.0.len() != 1 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
Ok(None)
|
||||
} else {
|
||||
@ -416,7 +432,10 @@ impl<'a> FallibleIterator for ColumnFormats<'a> {
|
||||
if self.buf.is_empty() {
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,7 +508,10 @@ impl<'a> FallibleIterator for DataRowRanges<'a> {
|
||||
if self.buf.is_empty() {
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,7 +522,10 @@ impl<'a> FallibleIterator for DataRowRanges<'a> {
|
||||
} else {
|
||||
let len = len as usize;
|
||||
if self.buf.len() < len {
|
||||
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
));
|
||||
}
|
||||
let base = self.len - self.buf.len();
|
||||
self.buf = &self.buf[len as usize..];
|
||||
@ -541,7 +566,10 @@ impl<'a> FallibleIterator for ErrorFields<'a> {
|
||||
if self.buf.is_empty() {
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,9 +578,9 @@ impl<'a> FallibleIterator for ErrorFields<'a> {
|
||||
self.buf = &self.buf[value_end + 1..];
|
||||
|
||||
Ok(Some(ErrorField {
|
||||
type_: type_,
|
||||
value: value,
|
||||
}))
|
||||
type_: type_,
|
||||
value: value,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,7 +665,10 @@ impl<'a> FallibleIterator for Parameters<'a> {
|
||||
if self.buf.is_empty() {
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -710,7 +741,10 @@ impl<'a> FallibleIterator for Fields<'a> {
|
||||
if self.buf.is_empty() {
|
||||
return Ok(None);
|
||||
} else {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid message length"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"invalid message length",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -726,14 +760,14 @@ impl<'a> FallibleIterator for Fields<'a> {
|
||||
let format = self.buf.read_i16::<BigEndian>()?;
|
||||
|
||||
Ok(Some(Field {
|
||||
name: name,
|
||||
table_oid: table_oid,
|
||||
column_id: column_id,
|
||||
type_oid: type_oid,
|
||||
type_size: type_size,
|
||||
type_modifier: type_modifier,
|
||||
format: format,
|
||||
}))
|
||||
name: name,
|
||||
table_oid: table_oid,
|
||||
column_id: column_id,
|
||||
type_oid: type_oid,
|
||||
type_size: type_size,
|
||||
type_modifier: type_modifier,
|
||||
format: format,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,7 +822,10 @@ impl<'a> Field<'a> {
|
||||
fn find_null(buf: &[u8], start: usize) -> io::Result<usize> {
|
||||
match memchr(0, &buf[start..]) {
|
||||
Some(pos) => Ok(pos + start),
|
||||
None => Err(io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF")),
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,19 +51,21 @@ impl<'a> Message<'a> {
|
||||
values,
|
||||
result_formats,
|
||||
} => {
|
||||
let r = bind(portal,
|
||||
statement,
|
||||
formats.iter().cloned(),
|
||||
values,
|
||||
|v, buf| match *v {
|
||||
Some(ref v) => {
|
||||
buf.extend_from_slice(v);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
None => Ok(IsNull::Yes),
|
||||
},
|
||||
result_formats.iter().cloned(),
|
||||
buf);
|
||||
let r = bind(
|
||||
portal,
|
||||
statement,
|
||||
formats.iter().cloned(),
|
||||
values,
|
||||
|v, buf| match *v {
|
||||
Some(ref v) => {
|
||||
buf.extend_from_slice(v);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
None => Ok(IsNull::Yes),
|
||||
},
|
||||
result_formats.iter().cloned(),
|
||||
buf,
|
||||
);
|
||||
match r {
|
||||
Ok(()) => Ok(()),
|
||||
Err(BindError::Conversion(_)) => unreachable!(),
|
||||
@ -104,8 +106,9 @@ impl<'a> Message<'a> {
|
||||
|
||||
#[inline]
|
||||
fn write_body<F, E>(buf: &mut Vec<u8>, f: F) -> Result<(), E>
|
||||
where F: FnOnce(&mut Vec<u8>) -> Result<(), E>,
|
||||
E: From<io::Error>
|
||||
where
|
||||
F: FnOnce(&mut Vec<u8>) -> Result<(), E>,
|
||||
E: From<io::Error>,
|
||||
{
|
||||
let base = buf.len();
|
||||
buf.extend_from_slice(&[0; 4]);
|
||||
@ -137,18 +140,20 @@ impl From<io::Error> for BindError {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bind<I, J, F, T, K>(portal: &str,
|
||||
statement: &str,
|
||||
formats: I,
|
||||
values: J,
|
||||
mut serializer: F,
|
||||
result_formats: K,
|
||||
buf: &mut Vec<u8>)
|
||||
-> Result<(), BindError>
|
||||
where I: IntoIterator<Item = i16>,
|
||||
J: IntoIterator<Item = T>,
|
||||
F: FnMut(T, &mut Vec<u8>) -> Result<IsNull, Box<Error + marker::Sync + Send>>,
|
||||
K: IntoIterator<Item = i16>
|
||||
pub fn bind<I, J, F, T, K>(
|
||||
portal: &str,
|
||||
statement: &str,
|
||||
formats: I,
|
||||
values: J,
|
||||
mut serializer: F,
|
||||
result_formats: K,
|
||||
buf: &mut Vec<u8>,
|
||||
) -> Result<(), BindError>
|
||||
where
|
||||
I: IntoIterator<Item = i16>,
|
||||
J: IntoIterator<Item = T>,
|
||||
F: FnMut(T, &mut Vec<u8>) -> Result<IsNull, Box<Error + marker::Sync + Send>>,
|
||||
K: IntoIterator<Item = i16>,
|
||||
{
|
||||
buf.push(b'B');
|
||||
|
||||
@ -156,9 +161,11 @@ pub fn bind<I, J, F, T, K>(portal: &str,
|
||||
buf.write_cstr(portal)?;
|
||||
buf.write_cstr(statement)?;
|
||||
write_counted(formats, |f, buf| buf.write_i16::<BigEndian>(f), buf)?;
|
||||
write_counted(values,
|
||||
|v, buf| write_nullable(|buf| serializer(v, buf), buf),
|
||||
buf)?;
|
||||
write_counted(
|
||||
values,
|
||||
|v, buf| write_nullable(|buf| serializer(v, buf), buf),
|
||||
buf,
|
||||
)?;
|
||||
write_counted(result_formats, |f, buf| buf.write_i16::<BigEndian>(f), buf)?;
|
||||
|
||||
Ok(())
|
||||
@ -167,9 +174,10 @@ pub fn bind<I, J, F, T, K>(portal: &str,
|
||||
|
||||
#[inline]
|
||||
fn write_counted<I, T, F, E>(items: I, mut serializer: F, buf: &mut Vec<u8>) -> Result<(), E>
|
||||
where I: IntoIterator<Item = T>,
|
||||
F: FnMut(T, &mut Vec<u8>) -> Result<(), E>,
|
||||
E: From<io::Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
F: FnMut(T, &mut Vec<u8>) -> Result<(), E>,
|
||||
E: From<io::Error>,
|
||||
{
|
||||
let base = buf.len();
|
||||
buf.extend_from_slice(&[0; 2]);
|
||||
@ -190,8 +198,7 @@ pub fn cancel_request(process_id: i32, secret_key: i32, buf: &mut Vec<u8>) {
|
||||
buf.write_i32::<BigEndian>(80877102).unwrap();
|
||||
buf.write_i32::<BigEndian>(process_id).unwrap();
|
||||
buf.write_i32::<BigEndian>(secret_key)
|
||||
})
|
||||
.unwrap();
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -246,7 +253,8 @@ pub fn execute(portal: &str, max_rows: i32, buf: &mut Vec<u8>) -> io::Result<()>
|
||||
|
||||
#[inline]
|
||||
pub fn parse<I>(name: &str, query: &str, param_types: I, buf: &mut Vec<u8>) -> io::Result<()>
|
||||
where I: IntoIterator<Item = Oid>
|
||||
where
|
||||
I: IntoIterator<Item = Oid>,
|
||||
{
|
||||
buf.push(b'P');
|
||||
write_body(buf, |buf| {
|
||||
@ -294,7 +302,8 @@ pub fn ssl_request(buf: &mut Vec<u8>) {
|
||||
|
||||
#[inline]
|
||||
pub fn startup_message<'a, I>(parameters: I, buf: &mut Vec<u8>) -> io::Result<()>
|
||||
where I: IntoIterator<Item = (&'a str, &'a str)>
|
||||
where
|
||||
I: IntoIterator<Item = (&'a str, &'a str)>,
|
||||
{
|
||||
write_body(buf, |buf| {
|
||||
buf.write_i32::<BigEndian>(196608).unwrap();
|
||||
@ -327,8 +336,10 @@ impl WriteCStr for Vec<u8> {
|
||||
#[inline]
|
||||
fn write_cstr(&mut self, s: &str) -> Result<(), io::Error> {
|
||||
if s.as_bytes().contains(&0) {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"string contains embedded null"));
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"string contains embedded null",
|
||||
));
|
||||
}
|
||||
self.extend_from_slice(s.as_bytes());
|
||||
self.push(0);
|
||||
|
@ -168,7 +168,8 @@ pub fn float8_from_sql(mut buf: &[u8]) -> Result<f64, StdBox<Error + Sync + Send
|
||||
/// Serializes an `HSTORE` value.
|
||||
#[inline]
|
||||
pub fn hstore_to_sql<'a, I>(values: I, buf: &mut Vec<u8>) -> Result<(), StdBox<Error + Sync + Send>>
|
||||
where I: IntoIterator<Item = (&'a str, Option<&'a str>)>
|
||||
where
|
||||
I: IntoIterator<Item = (&'a str, Option<&'a str>)>,
|
||||
{
|
||||
let base = buf.len();
|
||||
buf.extend_from_slice(&[0; 4]);
|
||||
@ -204,17 +205,18 @@ fn write_pascal_string(s: &str, buf: &mut Vec<u8>) -> Result<(), StdBox<Error +
|
||||
|
||||
/// Deserializes an `HSTORE` value.
|
||||
#[inline]
|
||||
pub fn hstore_from_sql<'a>(mut buf: &'a [u8])
|
||||
-> Result<HstoreEntries<'a>, StdBox<Error + Sync + Send>> {
|
||||
pub fn hstore_from_sql<'a>(
|
||||
mut buf: &'a [u8],
|
||||
) -> Result<HstoreEntries<'a>, StdBox<Error + Sync + Send>> {
|
||||
let count = buf.read_i32::<BigEndian>()?;
|
||||
if count < 0 {
|
||||
return Err("invalid entry count".into());
|
||||
}
|
||||
|
||||
Ok(HstoreEntries {
|
||||
remaining: count,
|
||||
buf: buf,
|
||||
})
|
||||
remaining: count,
|
||||
buf: buf,
|
||||
})
|
||||
}
|
||||
|
||||
/// A fallible iterator over `HSTORE` entries.
|
||||
@ -268,11 +270,13 @@ impl<'a> FallibleIterator for HstoreEntries<'a> {
|
||||
|
||||
/// Serializes a `VARBIT` or `BIT` value.
|
||||
#[inline]
|
||||
pub fn varbit_to_sql<I>(len: usize,
|
||||
v: I,
|
||||
buf: &mut Vec<u8>)
|
||||
-> Result<(), StdBox<Error + Sync + Send>>
|
||||
where I: Iterator<Item = u8>
|
||||
pub fn varbit_to_sql<I>(
|
||||
len: usize,
|
||||
v: I,
|
||||
buf: &mut Vec<u8>,
|
||||
) -> Result<(), StdBox<Error + Sync + Send>>
|
||||
where
|
||||
I: Iterator<Item = u8>,
|
||||
{
|
||||
let len = i32::from_usize(len)?;
|
||||
buf.write_i32::<BigEndian>(len).unwrap();
|
||||
@ -297,9 +301,9 @@ pub fn varbit_from_sql<'a>(mut buf: &'a [u8]) -> Result<Varbit<'a>, StdBox<Error
|
||||
}
|
||||
|
||||
Ok(Varbit {
|
||||
len: len as usize,
|
||||
bytes: buf,
|
||||
})
|
||||
len: len as usize,
|
||||
bytes: buf,
|
||||
})
|
||||
}
|
||||
|
||||
/// A `VARBIT` value.
|
||||
@ -418,16 +422,18 @@ pub fn uuid_from_sql(buf: &[u8]) -> Result<[u8; 16], StdBox<Error + Sync + Send>
|
||||
|
||||
/// Serializes an array value.
|
||||
#[inline]
|
||||
pub fn array_to_sql<T, I, J, F>(dimensions: I,
|
||||
has_nulls: bool,
|
||||
element_type: Oid,
|
||||
elements: J,
|
||||
mut serializer: F,
|
||||
buf: &mut Vec<u8>)
|
||||
-> Result<(), StdBox<Error + Sync + Send>>
|
||||
where I: IntoIterator<Item = ArrayDimension>,
|
||||
J: IntoIterator<Item = T>,
|
||||
F: FnMut(T, &mut Vec<u8>) -> Result<IsNull, StdBox<Error + Sync + Send>>
|
||||
pub fn array_to_sql<T, I, J, F>(
|
||||
dimensions: I,
|
||||
has_nulls: bool,
|
||||
element_type: Oid,
|
||||
elements: J,
|
||||
mut serializer: F,
|
||||
buf: &mut Vec<u8>,
|
||||
) -> Result<(), StdBox<Error + Sync + Send>>
|
||||
where
|
||||
I: IntoIterator<Item = ArrayDimension>,
|
||||
J: IntoIterator<Item = T>,
|
||||
F: FnMut(T, &mut Vec<u8>) -> Result<IsNull, StdBox<Error + Sync + Send>>,
|
||||
{
|
||||
let dimensions_idx = buf.len();
|
||||
buf.extend_from_slice(&[0; 4]);
|
||||
@ -482,12 +488,12 @@ pub fn array_from_sql<'a>(mut buf: &'a [u8]) -> Result<Array<'a>, StdBox<Error +
|
||||
}
|
||||
|
||||
Ok(Array {
|
||||
dimensions: dimensions,
|
||||
has_nulls: has_nulls,
|
||||
element_type: element_type,
|
||||
elements: elements,
|
||||
buf: buf,
|
||||
})
|
||||
dimensions: dimensions,
|
||||
has_nulls: has_nulls,
|
||||
element_type: element_type,
|
||||
elements: elements,
|
||||
buf: buf,
|
||||
})
|
||||
}
|
||||
|
||||
/// A Postgres array.
|
||||
@ -545,9 +551,9 @@ impl<'a> FallibleIterator for ArrayDimensions<'a> {
|
||||
let lower_bound = self.0.read_i32::<BigEndian>()?;
|
||||
|
||||
Ok(Some(ArrayDimension {
|
||||
len: len,
|
||||
lower_bound: lower_bound,
|
||||
}))
|
||||
len: len,
|
||||
lower_bound: lower_bound,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -616,12 +622,14 @@ pub fn empty_range_to_sql(buf: &mut Vec<u8>) {
|
||||
}
|
||||
|
||||
/// Serializes a range value.
|
||||
pub fn range_to_sql<F, G>(lower: F,
|
||||
upper: G,
|
||||
buf: &mut Vec<u8>)
|
||||
-> Result<(), StdBox<Error + Sync + Send>>
|
||||
where F: FnOnce(&mut Vec<u8>) -> Result<RangeBound<IsNull>, StdBox<Error + Sync + Send>>,
|
||||
G: FnOnce(&mut Vec<u8>) -> Result<RangeBound<IsNull>, StdBox<Error + Sync + Send>>
|
||||
pub fn range_to_sql<F, G>(
|
||||
lower: F,
|
||||
upper: G,
|
||||
buf: &mut Vec<u8>,
|
||||
) -> Result<(), StdBox<Error + Sync + Send>>
|
||||
where
|
||||
F: FnOnce(&mut Vec<u8>) -> Result<RangeBound<IsNull>, StdBox<Error + Sync + Send>>,
|
||||
G: FnOnce(&mut Vec<u8>) -> Result<RangeBound<IsNull>, StdBox<Error + Sync + Send>>,
|
||||
{
|
||||
let tag_idx = buf.len();
|
||||
buf.push(0);
|
||||
@ -644,10 +652,12 @@ pub fn range_to_sql<F, G>(lower: F,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_bound<F>(bound: F,
|
||||
buf: &mut Vec<u8>)
|
||||
-> Result<RangeBound<()>, StdBox<Error + Sync + Send>>
|
||||
where F: FnOnce(&mut Vec<u8>) -> Result<RangeBound<IsNull>, StdBox<Error + Sync + Send>>
|
||||
fn write_bound<F>(
|
||||
bound: F,
|
||||
buf: &mut Vec<u8>,
|
||||
) -> Result<RangeBound<()>, StdBox<Error + Sync + Send>>
|
||||
where
|
||||
F: FnOnce(&mut Vec<u8>) -> Result<RangeBound<IsNull>, StdBox<Error + Sync + Send>>,
|
||||
{
|
||||
let base = buf.len();
|
||||
buf.extend_from_slice(&[0; 4]);
|
||||
@ -707,11 +717,12 @@ pub fn range_from_sql<'a>(mut buf: &'a [u8]) -> Result<Range<'a>, StdBox<Error +
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_bound<'a>(buf: &mut &'a [u8],
|
||||
tag: u8,
|
||||
unbounded: u8,
|
||||
inclusive: u8)
|
||||
-> Result<RangeBound<Option<&'a [u8]>>, StdBox<Error + Sync + Send>> {
|
||||
fn read_bound<'a>(
|
||||
buf: &mut &'a [u8],
|
||||
tag: u8,
|
||||
unbounded: u8,
|
||||
inclusive: u8,
|
||||
) -> Result<RangeBound<Option<&'a [u8]>>, StdBox<Error + Sync + Send>> {
|
||||
if tag & unbounded != 0 {
|
||||
Ok(RangeBound::Unbounded)
|
||||
} else {
|
||||
@ -803,9 +814,9 @@ pub fn box_from_sql(mut buf: &[u8]) -> Result<Box, StdBox<Error + Sync + Send>>
|
||||
return Err("invalid buffer size".into());
|
||||
}
|
||||
Ok(Box {
|
||||
upper_right: Point { x: x1, y: y1 },
|
||||
lower_left: Point { x: x2, y: y2 },
|
||||
})
|
||||
upper_right: Point { x: x1, y: y1 },
|
||||
lower_left: Point { x: x2, y: y2 },
|
||||
})
|
||||
}
|
||||
|
||||
/// A Postgres box.
|
||||
@ -831,11 +842,13 @@ impl Box {
|
||||
|
||||
/// Serializes a Postgres path.
|
||||
#[inline]
|
||||
pub fn path_to_sql<I>(closed: bool,
|
||||
points: I,
|
||||
buf: &mut Vec<u8>)
|
||||
-> Result<(), StdBox<Error + Sync + Send>>
|
||||
where I: IntoIterator<Item = (f64, f64)>
|
||||
pub fn path_to_sql<I>(
|
||||
closed: bool,
|
||||
points: I,
|
||||
buf: &mut Vec<u8>,
|
||||
) -> Result<(), StdBox<Error + Sync + Send>>
|
||||
where
|
||||
I: IntoIterator<Item = (f64, f64)>,
|
||||
{
|
||||
buf.push(closed as u8);
|
||||
let points_idx = buf.len();
|
||||
@ -863,10 +876,10 @@ pub fn path_from_sql<'a>(mut buf: &'a [u8]) -> Result<Path<'a>, StdBox<Error + S
|
||||
let points = buf.read_i32::<BigEndian>()?;
|
||||
|
||||
Ok(Path {
|
||||
closed: closed,
|
||||
points: points,
|
||||
buf: buf,
|
||||
})
|
||||
closed: closed,
|
||||
points: points,
|
||||
buf: buf,
|
||||
})
|
||||
}
|
||||
|
||||
/// A Postgres point.
|
||||
@ -988,11 +1001,13 @@ mod test {
|
||||
|
||||
let mut buf = vec![];
|
||||
hstore_to_sql(map.iter().map(|(&k, &v)| (k, v)), &mut buf).unwrap();
|
||||
assert_eq!(hstore_from_sql(&buf)
|
||||
.unwrap()
|
||||
.collect::<HashMap<_, _>>()
|
||||
.unwrap(),
|
||||
map);
|
||||
assert_eq!(
|
||||
hstore_from_sql(&buf)
|
||||
.unwrap()
|
||||
.collect::<HashMap<_, _>>()
|
||||
.unwrap(),
|
||||
map
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1009,30 +1024,33 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn array() {
|
||||
let dimensions = [ArrayDimension {
|
||||
len: 1,
|
||||
lower_bound: 10,
|
||||
},
|
||||
ArrayDimension {
|
||||
len: 2,
|
||||
lower_bound: 0,
|
||||
}];
|
||||
let dimensions = [
|
||||
ArrayDimension {
|
||||
len: 1,
|
||||
lower_bound: 10,
|
||||
},
|
||||
ArrayDimension {
|
||||
len: 2,
|
||||
lower_bound: 0,
|
||||
},
|
||||
];
|
||||
let values = [None, Some(&b"hello"[..])];
|
||||
|
||||
let mut buf = vec![];
|
||||
array_to_sql(dimensions.iter().cloned(),
|
||||
true,
|
||||
10,
|
||||
values.iter().cloned(),
|
||||
|v, buf| match v {
|
||||
Some(v) => {
|
||||
buf.extend_from_slice(v);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
None => Ok(IsNull::Yes),
|
||||
},
|
||||
&mut buf)
|
||||
.unwrap();
|
||||
array_to_sql(
|
||||
dimensions.iter().cloned(),
|
||||
true,
|
||||
10,
|
||||
values.iter().cloned(),
|
||||
|v, buf| match v {
|
||||
Some(v) => {
|
||||
buf.extend_from_slice(v);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
None => Ok(IsNull::Yes),
|
||||
},
|
||||
&mut buf,
|
||||
).unwrap();
|
||||
|
||||
let array = array_from_sql(&buf).unwrap();
|
||||
assert_eq!(array.has_nulls(), true);
|
||||
|
@ -168,14 +168,18 @@ impl DbError {
|
||||
b'H' => hint = Some(field.value().to_owned()),
|
||||
b'P' => {
|
||||
normal_position = Some(field.value().parse::<u32>().map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`P` field did not contain an integer")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"`P` field did not contain an integer",
|
||||
)
|
||||
})?);
|
||||
}
|
||||
b'p' => {
|
||||
internal_position = Some(field.value().parse::<u32>().map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`p` field did not contain an integer")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"`p` field did not contain an integer",
|
||||
)
|
||||
})?);
|
||||
}
|
||||
b'q' => internal_query = Some(field.value().to_owned()),
|
||||
@ -188,18 +192,22 @@ impl DbError {
|
||||
b'F' => file = Some(field.value().to_owned()),
|
||||
b'L' => {
|
||||
line = Some(field.value().parse::<u32>().map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`L` field did not contain an integer")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"`L` field did not contain an integer",
|
||||
)
|
||||
})?);
|
||||
}
|
||||
b'R' => routine = Some(field.value().to_owned()),
|
||||
b'V' => {
|
||||
parsed_severity = Some(Severity::from_str(field.value()).ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`V` field contained an invalid value")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"`V` field contained an invalid value",
|
||||
)
|
||||
})?);
|
||||
}
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,10 +216,12 @@ impl DbError {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "`S` field missing")
|
||||
})?,
|
||||
parsed_severity: parsed_severity,
|
||||
code: code.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`C` field missing"))?,
|
||||
message: message.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`M` field missing"))?,
|
||||
code: code.ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "`C` field missing")
|
||||
})?,
|
||||
message: message.ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "`M` field missing")
|
||||
})?,
|
||||
detail: detail,
|
||||
hint: hint,
|
||||
position: match normal_position {
|
||||
@ -222,8 +232,10 @@ impl DbError {
|
||||
Some(ErrorPosition::Internal {
|
||||
position: position,
|
||||
query: internal_query.ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"`q` field missing but `p` field present")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"`q` field missing but `p` field present",
|
||||
)
|
||||
})?,
|
||||
})
|
||||
}
|
||||
|
@ -168,7 +168,17 @@ impl IntoConnectParams for String {
|
||||
|
||||
impl IntoConnectParams for Url {
|
||||
fn into_connect_params(self) -> Result<ConnectParams, Box<Error + Sync + Send>> {
|
||||
let Url { host, port, user, path: url::Path { path, query: options, .. }, .. } = self;
|
||||
let Url {
|
||||
host,
|
||||
port,
|
||||
user,
|
||||
path: url::Path {
|
||||
path,
|
||||
query: options,
|
||||
..
|
||||
},
|
||||
..
|
||||
} = self;
|
||||
|
||||
let mut builder = ConnectParams::builder();
|
||||
|
||||
@ -199,4 +209,3 @@ impl IntoConnectParams for Url {
|
||||
Ok(builder.build(host))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,14 +32,15 @@ pub struct UserInfo {
|
||||
pub type Query = Vec<(String, String)>;
|
||||
|
||||
impl Url {
|
||||
pub fn new(scheme: String,
|
||||
user: Option<UserInfo>,
|
||||
host: String,
|
||||
port: Option<u16>,
|
||||
path: String,
|
||||
query: Query,
|
||||
fragment: Option<String>)
|
||||
-> Url {
|
||||
pub fn new(
|
||||
scheme: String,
|
||||
user: Option<UserInfo>,
|
||||
host: String,
|
||||
port: Option<u16>,
|
||||
path: String,
|
||||
query: Query,
|
||||
fragment: Option<String>,
|
||||
) -> Url {
|
||||
Url {
|
||||
scheme: scheme,
|
||||
user: user,
|
||||
@ -63,13 +64,15 @@ impl Url {
|
||||
// query and fragment
|
||||
let (query, fragment) = get_query_fragment(rest)?;
|
||||
|
||||
let url = Url::new(scheme.to_owned(),
|
||||
userinfo,
|
||||
host.to_owned(),
|
||||
port,
|
||||
path,
|
||||
query,
|
||||
fragment);
|
||||
let url = Url::new(
|
||||
scheme.to_owned(),
|
||||
userinfo,
|
||||
host.to_owned(),
|
||||
port,
|
||||
path,
|
||||
query,
|
||||
fragment,
|
||||
);
|
||||
Ok(url)
|
||||
}
|
||||
}
|
||||
@ -125,19 +128,23 @@ fn decode_inner(c: &str, full_url: bool) -> DecodeResult<String> {
|
||||
let bytes = match (iter.next(), iter.next()) {
|
||||
(Some(one), Some(two)) => [one, two],
|
||||
_ => {
|
||||
return Err("Malformed input: found '%' without two \
|
||||
return Err(
|
||||
"Malformed input: found '%' without two \
|
||||
trailing bytes"
|
||||
.to_owned())
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let bytes_from_hex = match Vec::<u8>::from_hex(&bytes) {
|
||||
Ok(b) => b,
|
||||
_ => {
|
||||
return Err("Malformed input: found '%' followed by \
|
||||
return Err(
|
||||
"Malformed input: found '%' followed by \
|
||||
invalid hex values. Character '%' must \
|
||||
escaped."
|
||||
.to_owned())
|
||||
.to_owned(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
@ -247,9 +254,7 @@ fn get_authority(rawurl: &str) -> DecodeResult<(Option<UserInfo>, &str, Option<u
|
||||
let mut begin = 2;
|
||||
let mut end = len;
|
||||
|
||||
for (i, c) in rawurl.chars()
|
||||
.enumerate()
|
||||
.skip(2) {
|
||||
for (i, c) in rawurl.chars().enumerate().skip(2) {
|
||||
// deal with input class first
|
||||
match c {
|
||||
'0'...'9' => (),
|
||||
@ -390,7 +395,9 @@ fn get_path(rawurl: &str, is_authority: bool) -> DecodeResult<(String, &str)> {
|
||||
}
|
||||
|
||||
if is_authority && end != 0 && !rawurl.starts_with('/') {
|
||||
Err("Non-empty path must begin with '/' in presence of authority.".to_owned())
|
||||
Err(
|
||||
"Non-empty path must begin with '/' in presence of authority.".to_owned(),
|
||||
)
|
||||
} else {
|
||||
Ok((decode_component(&rawurl[0..end])?, &rawurl[end..len]))
|
||||
}
|
||||
@ -409,7 +416,10 @@ fn get_query_fragment(rawurl: &str) -> DecodeResult<(Query, Option<String>)> {
|
||||
match before_fragment.chars().next() {
|
||||
Some('?') => Ok((query_from_str(&before_fragment[1..])?, fragment)),
|
||||
None => Ok((vec![], fragment)),
|
||||
_ => Err(format!("Query didn't start with '?': '{}..'", before_fragment)),
|
||||
_ => Err(format!(
|
||||
"Query didn't start with '?': '{}..'",
|
||||
before_fragment
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use fallible_iterator::{FallibleIterator};
|
||||
use fallible_iterator::FallibleIterator;
|
||||
use postgres_protocol::message::backend::DataRowBody;
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io;
|
||||
@ -34,13 +34,15 @@ impl<'a> RowIndex for str {
|
||||
// FIXME ASCII-only case insensitivity isn't really the right thing to
|
||||
// do. Postgres itself uses a dubious wrapper around tolower and JDBC
|
||||
// uses the US locale.
|
||||
stmt.iter()
|
||||
.position(|d| d.name().eq_ignore_ascii_case(self))
|
||||
stmt.iter().position(
|
||||
|d| d.name().eq_ignore_ascii_case(self),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> RowIndex for &'a T
|
||||
where T: RowIndex
|
||||
where
|
||||
T: RowIndex,
|
||||
{
|
||||
#[inline]
|
||||
fn idx(&self, columns: &[Column]) -> Option<usize> {
|
||||
@ -58,9 +60,9 @@ impl RowData {
|
||||
pub fn new(body: DataRowBody) -> io::Result<RowData> {
|
||||
let ranges = body.ranges().collect()?;
|
||||
Ok(RowData {
|
||||
body: body,
|
||||
ranges: ranges,
|
||||
})
|
||||
body: body,
|
||||
ranges: ranges,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -21,10 +21,7 @@ impl FromSql for BitVec {
|
||||
}
|
||||
|
||||
impl ToSql for BitVec {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
mut out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, mut out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::varbit_to_sql(self.len(), self.to_bytes().into_iter(), out)?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
@ -12,9 +12,7 @@ fn base() -> NaiveDateTime {
|
||||
}
|
||||
|
||||
impl FromSql for NaiveDateTime {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<NaiveDateTime, Box<Error + Sync + Send>> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDateTime, Box<Error + Sync + Send>> {
|
||||
let t = types::timestamp_from_sql(raw)?;
|
||||
Ok(base() + Duration::microseconds(t))
|
||||
}
|
||||
@ -23,10 +21,7 @@ impl FromSql for NaiveDateTime {
|
||||
}
|
||||
|
||||
impl ToSql for NaiveDateTime {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let time = match self.signed_duration_since(base()).num_microseconds() {
|
||||
Some(time) => time,
|
||||
None => return Err("value too large to transmit".into()),
|
||||
@ -40,9 +35,7 @@ impl ToSql for NaiveDateTime {
|
||||
}
|
||||
|
||||
impl FromSql for DateTime<Utc> {
|
||||
fn from_sql(type_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<DateTime<Utc>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(type_: &Type, raw: &[u8]) -> Result<DateTime<Utc>, Box<Error + Sync + Send>> {
|
||||
let naive = NaiveDateTime::from_sql(type_, raw)?;
|
||||
Ok(DateTime::from_utc(naive, Utc))
|
||||
}
|
||||
@ -51,10 +44,7 @@ impl FromSql for DateTime<Utc> {
|
||||
}
|
||||
|
||||
impl ToSql for DateTime<Utc> {
|
||||
fn to_sql(&self,
|
||||
type_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, type_: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
self.naive_utc().to_sql(type_, w)
|
||||
}
|
||||
|
||||
@ -63,9 +53,7 @@ impl ToSql for DateTime<Utc> {
|
||||
}
|
||||
|
||||
impl FromSql for DateTime<Local> {
|
||||
fn from_sql(type_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<DateTime<Local>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(type_: &Type, raw: &[u8]) -> Result<DateTime<Local>, Box<Error + Sync + Send>> {
|
||||
let utc = DateTime::<Utc>::from_sql(type_, raw)?;
|
||||
Ok(utc.with_timezone(&Local))
|
||||
}
|
||||
@ -74,10 +62,11 @@ impl FromSql for DateTime<Local> {
|
||||
}
|
||||
|
||||
impl ToSql for DateTime<Local> {
|
||||
fn to_sql(&self,
|
||||
type_: &Type,
|
||||
mut w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(
|
||||
&self,
|
||||
type_: &Type,
|
||||
mut w: &mut Vec<u8>,
|
||||
) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
self.with_timezone(&Utc).to_sql(type_, w)
|
||||
}
|
||||
|
||||
@ -86,9 +75,10 @@ impl ToSql for DateTime<Local> {
|
||||
}
|
||||
|
||||
impl FromSql for DateTime<FixedOffset> {
|
||||
fn from_sql(type_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<DateTime<FixedOffset>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(
|
||||
type_: &Type,
|
||||
raw: &[u8],
|
||||
) -> Result<DateTime<FixedOffset>, Box<Error + Sync + Send>> {
|
||||
let utc = DateTime::<Utc>::from_sql(type_, raw)?;
|
||||
Ok(utc.with_timezone(&FixedOffset::east(0)))
|
||||
}
|
||||
@ -97,10 +87,7 @@ impl FromSql for DateTime<FixedOffset> {
|
||||
}
|
||||
|
||||
impl ToSql for DateTime<FixedOffset> {
|
||||
fn to_sql(&self,
|
||||
type_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, type_: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
self.with_timezone(&Utc).to_sql(type_, w)
|
||||
}
|
||||
|
||||
@ -109,9 +96,7 @@ impl ToSql for DateTime<FixedOffset> {
|
||||
}
|
||||
|
||||
impl FromSql for NaiveDate {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<NaiveDate, Box<Error + Sync + Send>> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDate, Box<Error + Sync + Send>> {
|
||||
let jd = types::date_from_sql(raw)?;
|
||||
Ok(base().date() + Duration::days(jd as i64))
|
||||
}
|
||||
@ -120,10 +105,7 @@ impl FromSql for NaiveDate {
|
||||
}
|
||||
|
||||
impl ToSql for NaiveDate {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let jd = self.signed_duration_since(base().date()).num_days();
|
||||
if jd > i32::max_value() as i64 || jd < i32::min_value() as i64 {
|
||||
return Err("value too large to transmit".into());
|
||||
@ -138,9 +120,7 @@ impl ToSql for NaiveDate {
|
||||
}
|
||||
|
||||
impl FromSql for NaiveTime {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<NaiveTime, Box<Error + Sync + Send>> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveTime, Box<Error + Sync + Send>> {
|
||||
let usec = types::time_from_sql(raw)?;
|
||||
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec))
|
||||
}
|
||||
@ -149,10 +129,7 @@ impl FromSql for NaiveTime {
|
||||
}
|
||||
|
||||
impl ToSql for NaiveTime {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let delta = self.signed_duration_since(NaiveTime::from_hms(0, 0, 0));
|
||||
let time = match delta.num_microseconds() {
|
||||
Some(time) => time,
|
||||
|
@ -7,9 +7,7 @@ use postgres_protocol::types;
|
||||
use types::{FromSql, ToSql, Type, IsNull};
|
||||
|
||||
impl FromSql for MacAddress {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<MacAddress, Box<Error + Sync + Send>> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<MacAddress, Box<Error + Sync + Send>> {
|
||||
let bytes = types::macaddr_from_sql(raw)?;
|
||||
Ok(MacAddress::new(bytes))
|
||||
}
|
||||
@ -18,10 +16,7 @@ impl FromSql for MacAddress {
|
||||
}
|
||||
|
||||
impl ToSql for MacAddress {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let mut bytes = [0; 6];
|
||||
bytes.copy_from_slice(self.as_bytes());
|
||||
types::macaddr_to_sql(bytes, w);
|
||||
|
@ -47,11 +47,13 @@ macro_rules! to_sql_checked {
|
||||
// WARNING: this function is not considered part of this crate's public API.
|
||||
// It is subject to change at any time.
|
||||
#[doc(hidden)]
|
||||
pub fn __to_sql_checked<T>(v: &T,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>>
|
||||
where T: ToSql
|
||||
pub fn __to_sql_checked<T>(
|
||||
v: &T,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>,
|
||||
) -> Result<IsNull, Box<Error + Sync + Send>>
|
||||
where
|
||||
T: ToSql,
|
||||
{
|
||||
if !T::accepts(ty) {
|
||||
return Err(Box::new(WrongType(ty.clone())));
|
||||
@ -156,11 +158,11 @@ impl Other {
|
||||
#[doc(hidden)]
|
||||
pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other {
|
||||
Other(Arc::new(OtherInner {
|
||||
name: name,
|
||||
oid: oid,
|
||||
kind: kind,
|
||||
schema: schema,
|
||||
}))
|
||||
name: name,
|
||||
oid: oid,
|
||||
kind: kind,
|
||||
schema: schema,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,9 +212,11 @@ pub struct WrongType(Type);
|
||||
|
||||
impl fmt::Display for WrongType {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt,
|
||||
"cannot convert to or from a Postgres value of type `{}`",
|
||||
self.0)
|
||||
write!(
|
||||
fmt,
|
||||
"cannot convert to or from a Postgres value of type `{}`",
|
||||
self.0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,9 +406,10 @@ simple_from!(f32, float4_from_sql, Type::Float4);
|
||||
simple_from!(f64, float8_from_sql, Type::Float8);
|
||||
|
||||
impl FromSql for HashMap<String, Option<String>> {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<HashMap<String, Option<String>>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(
|
||||
_: &Type,
|
||||
raw: &[u8],
|
||||
) -> Result<HashMap<String, Option<String>>, Box<Error + Sync + Send>> {
|
||||
types::hstore_from_sql(raw)?
|
||||
.map(|(k, v)| (k.to_owned(), v.map(str::to_owned)))
|
||||
.collect()
|
||||
@ -492,24 +497,29 @@ pub trait ToSql: fmt::Debug {
|
||||
/// `NULL`. If this is the case, implementations **must not** write
|
||||
/// anything to `out`.
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>>
|
||||
where Self: Sized;
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Determines if a value of this type can be converted to the specified
|
||||
/// Postgres `Type`.
|
||||
fn accepts(ty: &Type) -> bool where Self: Sized;
|
||||
fn accepts(ty: &Type) -> bool
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// An adaptor method used internally by Rust-Postgres.
|
||||
///
|
||||
/// *All* implementations of this method should be generated by the
|
||||
/// `to_sql_checked!()` macro.
|
||||
fn to_sql_checked(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>>;
|
||||
fn to_sql_checked(
|
||||
&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>,
|
||||
) -> Result<IsNull, Box<Error + Sync + Send>>;
|
||||
}
|
||||
|
||||
impl<'a, T> ToSql for &'a T
|
||||
where T: ToSql
|
||||
where
|
||||
T: ToSql,
|
||||
{
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
(*self).to_sql(ty, out)
|
||||
@ -549,15 +559,17 @@ impl<'a, T: ToSql> ToSql for &'a [T] {
|
||||
lower_bound: 1,
|
||||
};
|
||||
|
||||
types::array_to_sql(Some(dimension),
|
||||
true,
|
||||
member_type.oid(),
|
||||
self.iter(),
|
||||
|e, w| match e.to_sql(member_type, w)? {
|
||||
IsNull::No => Ok(postgres_protocol::IsNull::No),
|
||||
IsNull::Yes => Ok(postgres_protocol::IsNull::Yes),
|
||||
},
|
||||
w)?;
|
||||
types::array_to_sql(
|
||||
Some(dimension),
|
||||
true,
|
||||
member_type.oid(),
|
||||
self.iter(),
|
||||
|e, w| match e.to_sql(member_type, w)? {
|
||||
IsNull::No => Ok(postgres_protocol::IsNull::No),
|
||||
IsNull::Yes => Ok(postgres_protocol::IsNull::Yes),
|
||||
},
|
||||
w,
|
||||
)?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
@ -664,8 +676,10 @@ simple_to!(f64, float8_to_sql, Type::Float8);
|
||||
|
||||
impl ToSql for HashMap<String, Option<String>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::hstore_to_sql(self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))),
|
||||
w)?;
|
||||
types::hstore_to_sql(
|
||||
self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))),
|
||||
w,
|
||||
)?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
|
@ -7,9 +7,7 @@ use std::error::Error;
|
||||
use types::{FromSql, ToSql, IsNull, Type};
|
||||
|
||||
impl FromSql for json::Json {
|
||||
fn from_sql(ty: &Type,
|
||||
mut raw: &[u8])
|
||||
-> Result<json::Json, Box<Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<json::Json, Box<Error + Sync + Send>> {
|
||||
if let Type::Jsonb = *ty {
|
||||
let mut b = [0; 1];
|
||||
raw.read_exact(&mut b)?;
|
||||
@ -25,10 +23,7 @@ impl FromSql for json::Json {
|
||||
}
|
||||
|
||||
impl ToSql for json::Json {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
mut out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
if let Type::Jsonb = *ty {
|
||||
out.push(1);
|
||||
}
|
||||
|
@ -7,9 +7,7 @@ use std::io::{Read, Write};
|
||||
use types::{FromSql, ToSql, IsNull, Type};
|
||||
|
||||
impl FromSql for Value {
|
||||
fn from_sql(ty: &Type,
|
||||
mut raw: &[u8])
|
||||
-> Result<Value, Box<Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<Value, Box<Error + Sync + Send>> {
|
||||
if let Type::Jsonb = *ty {
|
||||
let mut b = [0; 1];
|
||||
raw.read_exact(&mut b)?;
|
||||
@ -25,10 +23,7 @@ impl FromSql for Value {
|
||||
}
|
||||
|
||||
impl ToSql for Value {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
mut out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
if let Type::Jsonb = *ty {
|
||||
out.push(1);
|
||||
}
|
||||
|
@ -16,9 +16,7 @@ pub enum Date<T> {
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Date<T> {
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Self, Box<Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
match types::date_from_sql(raw)? {
|
||||
i32::MAX => Ok(Date::PosInfinity),
|
||||
i32::MIN => Ok(Date::NegInfinity),
|
||||
@ -31,10 +29,7 @@ impl<T: FromSql> FromSql for Date<T> {
|
||||
}
|
||||
}
|
||||
impl<T: ToSql> ToSql for Date<T> {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let value = match *self {
|
||||
Date::PosInfinity => i32::MAX,
|
||||
Date::NegInfinity => i32::MIN,
|
||||
@ -65,9 +60,7 @@ pub enum Timestamp<T> {
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Timestamp<T> {
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Self, Box<Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
match types::timestamp_from_sql(raw)? {
|
||||
i64::MAX => Ok(Timestamp::PosInfinity),
|
||||
i64::MIN => Ok(Timestamp::NegInfinity),
|
||||
@ -81,10 +74,7 @@ impl<T: FromSql> FromSql for Timestamp<T> {
|
||||
}
|
||||
|
||||
impl<T: ToSql> ToSql for Timestamp<T> {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let value = match *self {
|
||||
Timestamp::PosInfinity => i64::MAX,
|
||||
Timestamp::NegInfinity => i64::MIN,
|
||||
|
@ -13,9 +13,7 @@ const NSEC_PER_USEC: i64 = 1_000;
|
||||
const TIME_SEC_CONVERSION: i64 = 946684800;
|
||||
|
||||
impl FromSql for Timespec {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Timespec, Box<Error + Sync + Send>> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Timespec, Box<Error + Sync + Send>> {
|
||||
let t = types::timestamp_from_sql(raw)?;
|
||||
let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION;
|
||||
let mut usec = t % USEC_PER_SEC;
|
||||
@ -32,10 +30,7 @@ impl FromSql for Timespec {
|
||||
}
|
||||
|
||||
impl ToSql for Timespec {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let t = (self.sec - TIME_SEC_CONVERSION) * USEC_PER_SEC + self.nsec as i64 / NSEC_PER_USEC;
|
||||
types::timestamp_to_sql(t, w);
|
||||
Ok(IsNull::No)
|
||||
|
@ -16,10 +16,7 @@ impl FromSql for Uuid {
|
||||
}
|
||||
|
||||
impl ToSql for Uuid {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::uuid_to_sql(*self.as_bytes(), w);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ use postgres::{Connection, TlsMode};
|
||||
#[bench]
|
||||
fn bench_naiive_execute(b: &mut test::Bencher) {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();
|
||||
conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[])
|
||||
.unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let stmt = conn.prepare("UPDATE foo SET id = 1").unwrap();
|
||||
@ -20,9 +21,8 @@ fn bench_naiive_execute(b: &mut test::Bencher) {
|
||||
#[bench]
|
||||
fn bench_execute(b: &mut test::Bencher) {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();
|
||||
conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[])
|
||||
.unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
conn.execute("UPDATE foo SET id = 1", &[]).unwrap()
|
||||
});
|
||||
b.iter(|| conn.execute("UPDATE foo SET id = 1", &[]).unwrap());
|
||||
}
|
||||
|
@ -178,15 +178,17 @@ impl HandleNotice for LoggingNoticeHandler {
|
||||
/// });
|
||||
/// postgres::cancel_query(url, TlsMode::None, &cancel_data).unwrap();
|
||||
/// ```
|
||||
pub fn cancel_query<T>(params: T,
|
||||
tls: TlsMode,
|
||||
data: &CancelData)
|
||||
-> result::Result<(), ConnectError>
|
||||
where T: IntoConnectParams
|
||||
pub fn cancel_query<T>(
|
||||
params: T,
|
||||
tls: TlsMode,
|
||||
data: &CancelData,
|
||||
) -> result::Result<(), ConnectError>
|
||||
where
|
||||
T: IntoConnectParams,
|
||||
{
|
||||
let params = params
|
||||
.into_connect_params()
|
||||
.map_err(ConnectError::ConnectParams)?;
|
||||
let params = params.into_connect_params().map_err(
|
||||
ConnectError::ConnectParams,
|
||||
)?;
|
||||
let mut socket = priv_io::initialize_stream(¶ms, tls)?;
|
||||
|
||||
let mut buf = vec![];
|
||||
@ -198,13 +200,17 @@ pub fn cancel_query<T>(params: T,
|
||||
}
|
||||
|
||||
fn bad_response() -> io::Error {
|
||||
io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"the server returned an unexpected response")
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"the server returned an unexpected response",
|
||||
)
|
||||
}
|
||||
|
||||
fn desynchronized() -> io::Error {
|
||||
io::Error::new(io::ErrorKind::Other,
|
||||
"communication with the server has desynchronized due to an earlier IO error")
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"communication with the server has desynchronized due to an earlier IO error",
|
||||
)
|
||||
}
|
||||
|
||||
/// Specifies the TLS support requested for a new connection.
|
||||
@ -252,18 +258,20 @@ impl Drop for InnerConnection {
|
||||
|
||||
impl InnerConnection {
|
||||
fn connect<T>(params: T, tls: TlsMode) -> result::Result<InnerConnection, ConnectError>
|
||||
where T: IntoConnectParams
|
||||
where
|
||||
T: IntoConnectParams,
|
||||
{
|
||||
let params = params
|
||||
.into_connect_params()
|
||||
.map_err(ConnectError::ConnectParams)?;
|
||||
let params = params.into_connect_params().map_err(
|
||||
ConnectError::ConnectParams,
|
||||
)?;
|
||||
let stream = priv_io::initialize_stream(¶ms, tls)?;
|
||||
|
||||
let user = match params.user() {
|
||||
Some(user) => user,
|
||||
None => {
|
||||
return Err(ConnectError::ConnectParams("User missing from connection parameters"
|
||||
.into()));
|
||||
return Err(ConnectError::ConnectParams(
|
||||
"User missing from connection parameters".into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -299,8 +307,9 @@ impl InnerConnection {
|
||||
}
|
||||
|
||||
let options = options.iter().map(|&(ref a, ref b)| (&**a, &**b));
|
||||
conn.stream
|
||||
.write_message(|buf| frontend::startup_message(options, buf))?;
|
||||
conn.stream.write_message(
|
||||
|buf| frontend::startup_message(options, buf),
|
||||
)?;
|
||||
conn.stream.flush()?;
|
||||
|
||||
conn.handle_auth(user)?;
|
||||
@ -332,17 +341,20 @@ impl InnerConnection {
|
||||
}
|
||||
}
|
||||
backend::Message::ParameterStatus(body) => {
|
||||
self.parameters
|
||||
.insert(body.name()?.to_owned(), body.value()?.to_owned());
|
||||
self.parameters.insert(
|
||||
body.name()?.to_owned(),
|
||||
body.value()?.to_owned(),
|
||||
);
|
||||
}
|
||||
val => return Ok(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_message_with_notification_timeout(&mut self,
|
||||
timeout: Duration)
|
||||
-> io::Result<Option<backend::Message>> {
|
||||
fn read_message_with_notification_timeout(
|
||||
&mut self,
|
||||
timeout: Duration,
|
||||
) -> io::Result<Option<backend::Message>> {
|
||||
debug_assert!(!self.desynchronized);
|
||||
loop {
|
||||
match try_desync!(self, self.stream.read_message_timeout(timeout)) {
|
||||
@ -352,16 +364,19 @@ impl InnerConnection {
|
||||
}
|
||||
}
|
||||
Some(backend::Message::ParameterStatus(body)) => {
|
||||
self.parameters
|
||||
.insert(body.name()?.to_owned(), body.value()?.to_owned());
|
||||
self.parameters.insert(
|
||||
body.name()?.to_owned(),
|
||||
body.value()?.to_owned(),
|
||||
);
|
||||
}
|
||||
val => return Ok(val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_message_with_notification_nonblocking(&mut self)
|
||||
-> io::Result<Option<backend::Message>> {
|
||||
fn read_message_with_notification_nonblocking(
|
||||
&mut self,
|
||||
) -> io::Result<Option<backend::Message>> {
|
||||
debug_assert!(!self.desynchronized);
|
||||
loop {
|
||||
match try_desync!(self, self.stream.read_message_nonblocking()) {
|
||||
@ -371,8 +386,10 @@ impl InnerConnection {
|
||||
}
|
||||
}
|
||||
Some(backend::Message::ParameterStatus(body)) => {
|
||||
self.parameters
|
||||
.insert(body.name()?.to_owned(), body.value()?.to_owned());
|
||||
self.parameters.insert(
|
||||
body.name()?.to_owned(),
|
||||
body.value()?.to_owned(),
|
||||
);
|
||||
}
|
||||
val => return Ok(val),
|
||||
}
|
||||
@ -383,12 +400,11 @@ impl InnerConnection {
|
||||
loop {
|
||||
match self.read_message_with_notification()? {
|
||||
backend::Message::NotificationResponse(body) => {
|
||||
self.notifications
|
||||
.push_back(Notification {
|
||||
process_id: body.process_id(),
|
||||
channel: body.channel()?.to_owned(),
|
||||
payload: body.message()?.to_owned(),
|
||||
})
|
||||
self.notifications.push_back(Notification {
|
||||
process_id: body.process_id(),
|
||||
channel: body.channel()?.to_owned(),
|
||||
payload: body.message()?.to_owned(),
|
||||
})
|
||||
}
|
||||
val => return Ok(val),
|
||||
}
|
||||
@ -399,50 +415,46 @@ impl InnerConnection {
|
||||
match self.read_message()? {
|
||||
backend::Message::AuthenticationOk => return Ok(()),
|
||||
backend::Message::AuthenticationCleartextPassword => {
|
||||
let pass = user.password()
|
||||
.ok_or_else(|| {
|
||||
ConnectError::ConnectParams("a password was requested but not provided"
|
||||
.into())
|
||||
})?;
|
||||
self.stream
|
||||
.write_message(|buf| frontend::password_message(pass, buf))?;
|
||||
let pass = user.password().ok_or_else(|| {
|
||||
ConnectError::ConnectParams("a password was requested but not provided".into())
|
||||
})?;
|
||||
self.stream.write_message(
|
||||
|buf| frontend::password_message(pass, buf),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
}
|
||||
backend::Message::AuthenticationMd5Password(body) => {
|
||||
let pass = user.password()
|
||||
.ok_or_else(|| {
|
||||
ConnectError::ConnectParams("a password was requested but not provided"
|
||||
.into())
|
||||
})?;
|
||||
let pass = user.password().ok_or_else(|| {
|
||||
ConnectError::ConnectParams("a password was requested but not provided".into())
|
||||
})?;
|
||||
let output =
|
||||
authentication::md5_hash(user.name().as_bytes(), pass.as_bytes(), body.salt());
|
||||
self.stream
|
||||
.write_message(|buf| frontend::password_message(&output, buf))?;
|
||||
self.stream.write_message(
|
||||
|buf| frontend::password_message(&output, buf),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
}
|
||||
backend::Message::AuthenticationSasl(body) => {
|
||||
// count to validate the entire message body.
|
||||
if body.mechanisms()
|
||||
.filter(|m| *m == sasl::SCRAM_SHA_256)
|
||||
.count()? == 0 {
|
||||
return Err(ConnectError::Io(io::Error::new(io::ErrorKind::Other,
|
||||
"unsupported authentication")));
|
||||
.filter(|m| *m == sasl::SCRAM_SHA_256)
|
||||
.count()? == 0
|
||||
{
|
||||
return Err(ConnectError::Io(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"unsupported authentication",
|
||||
)));
|
||||
}
|
||||
|
||||
let pass = user.password()
|
||||
.ok_or_else(|| {
|
||||
ConnectError::ConnectParams("a password was requested but not provided"
|
||||
.into())
|
||||
})?;
|
||||
let pass = user.password().ok_or_else(|| {
|
||||
ConnectError::ConnectParams("a password was requested but not provided".into())
|
||||
})?;
|
||||
|
||||
let mut scram = ScramSha256::new(pass.as_bytes())?;
|
||||
|
||||
self.stream
|
||||
.write_message(|buf| {
|
||||
frontend::sasl_initial_response(sasl::SCRAM_SHA_256,
|
||||
scram.message(),
|
||||
buf)
|
||||
})?;
|
||||
self.stream.write_message(|buf| {
|
||||
frontend::sasl_initial_response(sasl::SCRAM_SHA_256, scram.message(), buf)
|
||||
})?;
|
||||
self.stream.flush()?;
|
||||
|
||||
let body = match self.read_message()? {
|
||||
@ -455,8 +467,9 @@ impl InnerConnection {
|
||||
|
||||
scram.update(body.data())?;
|
||||
|
||||
self.stream
|
||||
.write_message(|buf| frontend::sasl_response(scram.message(), buf))?;
|
||||
self.stream.write_message(|buf| {
|
||||
frontend::sasl_response(scram.message(), buf)
|
||||
})?;
|
||||
self.stream.flush()?;
|
||||
|
||||
let body = match self.read_message()? {
|
||||
@ -473,8 +486,10 @@ impl InnerConnection {
|
||||
backend::Message::AuthenticationScmCredential |
|
||||
backend::Message::AuthenticationGss |
|
||||
backend::Message::AuthenticationSspi => {
|
||||
return Err(ConnectError::Io(io::Error::new(io::ErrorKind::Other,
|
||||
"unsupported authentication")))
|
||||
return Err(ConnectError::Io(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"unsupported authentication",
|
||||
)))
|
||||
}
|
||||
backend::Message::ErrorResponse(body) => return Err(connect_err(&mut body.fields())),
|
||||
_ => return Err(ConnectError::Io(bad_response())),
|
||||
@ -494,12 +509,15 @@ impl InnerConnection {
|
||||
fn raw_prepare(&mut self, stmt_name: &str, query: &str) -> Result<(Vec<Type>, Vec<Column>)> {
|
||||
debug!("preparing query with name `{}`: {}", stmt_name, query);
|
||||
|
||||
self.stream
|
||||
.write_message(|buf| frontend::parse(stmt_name, query, None, buf))?;
|
||||
self.stream
|
||||
.write_message(|buf| frontend::describe(b'S', stmt_name, buf))?;
|
||||
self.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
self.stream.write_message(|buf| {
|
||||
frontend::parse(stmt_name, query, None, buf)
|
||||
})?;
|
||||
self.stream.write_message(
|
||||
|buf| frontend::describe(b'S', stmt_name, buf),
|
||||
)?;
|
||||
self.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
|
||||
match self.read_message()? {
|
||||
@ -534,9 +552,11 @@ impl InnerConnection {
|
||||
Some(body) => {
|
||||
body.fields()
|
||||
.and_then(|field| {
|
||||
Ok(Column::new(field.name().to_owned(),
|
||||
self.get_type(field.type_oid())?))
|
||||
})
|
||||
Ok(Column::new(
|
||||
field.name().to_owned(),
|
||||
self.get_type(field.type_oid())?,
|
||||
))
|
||||
})
|
||||
.collect()?
|
||||
}
|
||||
None => vec![],
|
||||
@ -546,7 +566,8 @@ impl InnerConnection {
|
||||
}
|
||||
|
||||
fn read_rows<F>(&mut self, mut consumer: F) -> Result<bool>
|
||||
where F: FnMut(RowData)
|
||||
where
|
||||
F: FnMut(RowData),
|
||||
{
|
||||
let more_rows;
|
||||
loop {
|
||||
@ -566,12 +587,12 @@ impl InnerConnection {
|
||||
return Err(err(&mut body.fields()));
|
||||
}
|
||||
backend::Message::CopyInResponse(_) => {
|
||||
self.stream
|
||||
.write_message(|buf| {
|
||||
frontend::copy_fail("COPY queries cannot be directly executed", buf)
|
||||
})?;
|
||||
self.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
self.stream.write_message(|buf| {
|
||||
frontend::copy_fail("COPY queries cannot be directly executed", buf)
|
||||
})?;
|
||||
self.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
}
|
||||
backend::Message::CopyOutResponse(_) => {
|
||||
@ -580,9 +601,11 @@ impl InnerConnection {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Err(Error::Io(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"COPY queries cannot be directly \
|
||||
executed")));
|
||||
return Err(Error::Io(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"COPY queries cannot be directly \
|
||||
executed",
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
self.desynchronized = true;
|
||||
@ -594,36 +617,42 @@ impl InnerConnection {
|
||||
Ok(more_rows)
|
||||
}
|
||||
|
||||
fn raw_execute(&mut self,
|
||||
stmt_name: &str,
|
||||
portal_name: &str,
|
||||
row_limit: i32,
|
||||
param_types: &[Type],
|
||||
params: &[&ToSql])
|
||||
-> Result<()> {
|
||||
assert!(param_types.len() == params.len(),
|
||||
"expected {} parameters but got {}",
|
||||
param_types.len(),
|
||||
params.len());
|
||||
debug!("executing statement {} with parameters: {:?}",
|
||||
stmt_name,
|
||||
params);
|
||||
fn raw_execute(
|
||||
&mut self,
|
||||
stmt_name: &str,
|
||||
portal_name: &str,
|
||||
row_limit: i32,
|
||||
param_types: &[Type],
|
||||
params: &[&ToSql],
|
||||
) -> Result<()> {
|
||||
assert!(
|
||||
param_types.len() == params.len(),
|
||||
"expected {} parameters but got {}",
|
||||
param_types.len(),
|
||||
params.len()
|
||||
);
|
||||
debug!(
|
||||
"executing statement {} with parameters: {:?}",
|
||||
stmt_name,
|
||||
params
|
||||
);
|
||||
|
||||
{
|
||||
let r = self.stream
|
||||
.write_message(|buf| {
|
||||
frontend::bind(portal_name,
|
||||
stmt_name,
|
||||
Some(1),
|
||||
params.iter().zip(param_types),
|
||||
|(param, ty), buf| match param.to_sql_checked(ty, buf) {
|
||||
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
|
||||
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Some(1),
|
||||
buf)
|
||||
});
|
||||
let r = self.stream.write_message(|buf| {
|
||||
frontend::bind(
|
||||
portal_name,
|
||||
stmt_name,
|
||||
Some(1),
|
||||
params.iter().zip(param_types),
|
||||
|(param, ty), buf| match param.to_sql_checked(ty, buf) {
|
||||
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
|
||||
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Some(1),
|
||||
buf,
|
||||
)
|
||||
});
|
||||
match r {
|
||||
Ok(()) => {}
|
||||
Err(frontend::BindError::Conversion(e)) => return Err(Error::Conversion(e)),
|
||||
@ -631,10 +660,12 @@ impl InnerConnection {
|
||||
}
|
||||
}
|
||||
|
||||
self.stream
|
||||
.write_message(|buf| frontend::execute(portal_name, row_limit, buf))?;
|
||||
self.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
self.stream.write_message(|buf| {
|
||||
frontend::execute(portal_name, row_limit, buf)
|
||||
})?;
|
||||
self.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
|
||||
match self.read_message()? {
|
||||
@ -660,10 +691,10 @@ impl InnerConnection {
|
||||
let stmt_name = self.make_stmt_name();
|
||||
let (param_types, columns) = self.raw_prepare(&stmt_name, query)?;
|
||||
let info = Arc::new(StatementInfo {
|
||||
name: stmt_name,
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
name: stmt_name,
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
Ok(Statement::new(conn, info, Cell::new(0), false))
|
||||
}
|
||||
|
||||
@ -676,12 +707,14 @@ impl InnerConnection {
|
||||
let stmt_name = self.make_stmt_name();
|
||||
let (param_types, columns) = self.raw_prepare(&stmt_name, query)?;
|
||||
let info = Arc::new(StatementInfo {
|
||||
name: stmt_name,
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
self.cached_statements
|
||||
.insert(query.to_owned(), info.clone());
|
||||
name: stmt_name,
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
self.cached_statements.insert(
|
||||
query.to_owned(),
|
||||
info.clone(),
|
||||
);
|
||||
info
|
||||
}
|
||||
};
|
||||
@ -690,10 +723,12 @@ impl InnerConnection {
|
||||
}
|
||||
|
||||
fn close_statement(&mut self, name: &str, type_: u8) -> Result<()> {
|
||||
self.stream
|
||||
.write_message(|buf| frontend::close(type_, name, buf))?;
|
||||
self.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
self.stream.write_message(
|
||||
|buf| frontend::close(type_, name, buf),
|
||||
)?;
|
||||
self.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
let resp = match self.read_message()? {
|
||||
backend::Message::CloseComplete => Ok(()),
|
||||
@ -723,25 +758,29 @@ impl InnerConnection {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self.raw_prepare(TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, \
|
||||
match self.raw_prepare(
|
||||
TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, \
|
||||
t.typbasetype, n.nspname, t.typrelid \
|
||||
FROM pg_catalog.pg_type t \
|
||||
LEFT OUTER JOIN pg_catalog.pg_range r ON \
|
||||
r.rngtypid = t.oid \
|
||||
INNER JOIN pg_catalog.pg_namespace n ON \
|
||||
t.typnamespace = n.oid \
|
||||
WHERE t.oid = $1") {
|
||||
WHERE t.oid = $1",
|
||||
) {
|
||||
Ok(..) => {}
|
||||
// Range types weren't added until Postgres 9.2, so pg_range may not exist
|
||||
Err(Error::Db(ref e)) if e.code == SqlState::UndefinedTable => {
|
||||
self.raw_prepare(TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, NULL::OID, \
|
||||
self.raw_prepare(
|
||||
TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, NULL::OID, \
|
||||
t.typbasetype, n.nspname, t.typrelid \
|
||||
FROM pg_catalog.pg_type t \
|
||||
INNER JOIN pg_catalog.pg_namespace n \
|
||||
ON t.typnamespace = n.oid \
|
||||
WHERE t.oid = $1")?;
|
||||
WHERE t.oid = $1",
|
||||
)?;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
@ -753,27 +792,39 @@ impl InnerConnection {
|
||||
#[allow(if_not_else)]
|
||||
fn read_type(&mut self, oid: Oid) -> Result<Other> {
|
||||
self.setup_typeinfo_query()?;
|
||||
self.raw_execute(TYPEINFO_QUERY, "", 0, &[Type::Oid], &[&oid])?;
|
||||
self.raw_execute(
|
||||
TYPEINFO_QUERY,
|
||||
"",
|
||||
0,
|
||||
&[Type::Oid],
|
||||
&[&oid],
|
||||
)?;
|
||||
let mut row = None;
|
||||
self.read_rows(|r| row = Some(r))?;
|
||||
|
||||
let get_raw = |i: usize| row.as_ref().and_then(|r| r.get(i));
|
||||
|
||||
let (name, type_, elem_oid, rngsubtype, basetype, schema, relid) = {
|
||||
let name = String::from_sql_nullable(&Type::Name, get_raw(0))
|
||||
.map_err(Error::Conversion)?;
|
||||
let type_ = i8::from_sql_nullable(&Type::Char, get_raw(1))
|
||||
.map_err(Error::Conversion)?;
|
||||
let elem_oid = Oid::from_sql_nullable(&Type::Oid, get_raw(2))
|
||||
.map_err(Error::Conversion)?;
|
||||
let name = String::from_sql_nullable(&Type::Name, get_raw(0)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
let type_ = i8::from_sql_nullable(&Type::Char, get_raw(1)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
let elem_oid = Oid::from_sql_nullable(&Type::Oid, get_raw(2)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
let rngsubtype = Option::<Oid>::from_sql_nullable(&Type::Oid, get_raw(3))
|
||||
.map_err(Error::Conversion)?;
|
||||
let basetype = Oid::from_sql_nullable(&Type::Oid, get_raw(4))
|
||||
.map_err(Error::Conversion)?;
|
||||
let schema = String::from_sql_nullable(&Type::Name, get_raw(5))
|
||||
.map_err(Error::Conversion)?;
|
||||
let relid = Oid::from_sql_nullable(&Type::Oid, get_raw(6))
|
||||
.map_err(Error::Conversion)?;
|
||||
let basetype = Oid::from_sql_nullable(&Type::Oid, get_raw(4)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
let schema = String::from_sql_nullable(&Type::Name, get_raw(5)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
let relid = Oid::from_sql_nullable(&Type::Oid, get_raw(6)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
(name, type_, elem_oid, rngsubtype, basetype, schema, relid)
|
||||
};
|
||||
|
||||
@ -802,19 +853,23 @@ impl InnerConnection {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match self.raw_prepare(TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel \
|
||||
match self.raw_prepare(
|
||||
TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel \
|
||||
FROM pg_catalog.pg_enum \
|
||||
WHERE enumtypid = $1 \
|
||||
ORDER BY enumsortorder") {
|
||||
ORDER BY enumsortorder",
|
||||
) {
|
||||
Ok(..) => {}
|
||||
// Postgres 9.0 doesn't have enumsortorder
|
||||
Err(Error::Db(ref e)) if e.code == SqlState::UndefinedColumn => {
|
||||
self.raw_prepare(TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel \
|
||||
self.raw_prepare(
|
||||
TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel \
|
||||
FROM pg_catalog.pg_enum \
|
||||
WHERE enumtypid = $1 \
|
||||
ORDER BY oid")?;
|
||||
ORDER BY oid",
|
||||
)?;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
@ -825,14 +880,21 @@ impl InnerConnection {
|
||||
|
||||
fn read_enum_variants(&mut self, oid: Oid) -> Result<Vec<String>> {
|
||||
self.setup_typeinfo_enum_query()?;
|
||||
self.raw_execute(TYPEINFO_ENUM_QUERY, "", 0, &[Type::Oid], &[&oid])?;
|
||||
self.raw_execute(
|
||||
TYPEINFO_ENUM_QUERY,
|
||||
"",
|
||||
0,
|
||||
&[Type::Oid],
|
||||
&[&oid],
|
||||
)?;
|
||||
let mut rows = vec![];
|
||||
self.read_rows(|row| rows.push(row))?;
|
||||
|
||||
let mut variants = vec![];
|
||||
for row in rows {
|
||||
variants.push(String::from_sql_nullable(&Type::Name, row.get(0))
|
||||
.map_err(Error::Conversion)?);
|
||||
variants.push(String::from_sql_nullable(&Type::Name, row.get(0)).map_err(
|
||||
Error::Conversion,
|
||||
)?);
|
||||
}
|
||||
|
||||
Ok(variants)
|
||||
@ -843,13 +905,15 @@ impl InnerConnection {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.raw_prepare(TYPEINFO_COMPOSITE_QUERY,
|
||||
"SELECT attname, atttypid \
|
||||
self.raw_prepare(
|
||||
TYPEINFO_COMPOSITE_QUERY,
|
||||
"SELECT attname, atttypid \
|
||||
FROM pg_catalog.pg_attribute \
|
||||
WHERE attrelid = $1 \
|
||||
AND NOT attisdropped \
|
||||
AND attnum > 0 \
|
||||
ORDER BY attnum")?;
|
||||
ORDER BY attnum",
|
||||
)?;
|
||||
|
||||
self.has_typeinfo_composite_query = true;
|
||||
Ok(())
|
||||
@ -857,17 +921,25 @@ impl InnerConnection {
|
||||
|
||||
fn read_composite_fields(&mut self, relid: Oid) -> Result<Vec<Field>> {
|
||||
self.setup_typeinfo_composite_query()?;
|
||||
self.raw_execute(TYPEINFO_COMPOSITE_QUERY, "", 0, &[Type::Oid], &[&relid])?;
|
||||
self.raw_execute(
|
||||
TYPEINFO_COMPOSITE_QUERY,
|
||||
"",
|
||||
0,
|
||||
&[Type::Oid],
|
||||
&[&relid],
|
||||
)?;
|
||||
let mut rows = vec![];
|
||||
self.read_rows(|row| rows.push(row))?;
|
||||
|
||||
let mut fields = vec![];
|
||||
for row in rows {
|
||||
let (name, type_) = {
|
||||
let name = String::from_sql_nullable(&Type::Name, row.get(0))
|
||||
.map_err(Error::Conversion)?;
|
||||
let type_ = Oid::from_sql_nullable(&Type::Oid, row.get(1))
|
||||
.map_err(Error::Conversion)?;
|
||||
let name = String::from_sql_nullable(&Type::Name, row.get(0)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
let type_ = Oid::from_sql_nullable(&Type::Oid, row.get(1)).map_err(
|
||||
Error::Conversion,
|
||||
)?;
|
||||
(name, type_)
|
||||
};
|
||||
let type_ = self.get_type(type_)?;
|
||||
@ -892,8 +964,7 @@ impl InnerConnection {
|
||||
fn quick_query(&mut self, query: &str) -> Result<Vec<Vec<Option<String>>>> {
|
||||
check_desync!(self);
|
||||
debug!("executing query: {}", query);
|
||||
self.stream
|
||||
.write_message(|buf| frontend::query(query, buf))?;
|
||||
self.stream.write_message(|buf| frontend::query(query, buf))?;
|
||||
self.stream.flush()?;
|
||||
|
||||
let mut result = vec![];
|
||||
@ -903,18 +974,18 @@ impl InnerConnection {
|
||||
backend::Message::DataRow(body) => {
|
||||
let row = body.ranges()
|
||||
.map(|r| {
|
||||
r.map(|r| String::from_utf8_lossy(&body.buffer()[r]).into_owned())
|
||||
})
|
||||
r.map(|r| String::from_utf8_lossy(&body.buffer()[r]).into_owned())
|
||||
})
|
||||
.collect()?;
|
||||
result.push(row);
|
||||
}
|
||||
backend::Message::CopyInResponse(_) => {
|
||||
self.stream
|
||||
.write_message(|buf| {
|
||||
frontend::copy_fail("COPY queries cannot be directly executed", buf)
|
||||
})?;
|
||||
self.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
self.stream.write_message(|buf| {
|
||||
frontend::copy_fail("COPY queries cannot be directly executed", buf)
|
||||
})?;
|
||||
self.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
self.stream.flush()?;
|
||||
}
|
||||
backend::Message::ErrorResponse(body) => {
|
||||
@ -929,8 +1000,9 @@ impl InnerConnection {
|
||||
|
||||
fn finish_inner(&mut self) -> Result<()> {
|
||||
check_desync!(self);
|
||||
self.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::terminate(buf)))?;
|
||||
self.stream.write_message(|buf| {
|
||||
Ok::<(), io::Error>(frontend::terminate(buf))
|
||||
})?;
|
||||
self.stream.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
@ -1015,7 +1087,8 @@ impl Connection {
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn connect<T>(params: T, tls: TlsMode) -> result::Result<Connection, ConnectError>
|
||||
where T: IntoConnectParams
|
||||
where
|
||||
T: IntoConnectParams,
|
||||
{
|
||||
InnerConnection::connect(params, tls).map(|conn| Connection(RefCell::new(conn)))
|
||||
}
|
||||
@ -1050,10 +1123,10 @@ impl Connection {
|
||||
pub fn execute(&self, query: &str, params: &[&ToSql]) -> Result<u64> {
|
||||
let (param_types, columns) = self.0.borrow_mut().raw_prepare("", query)?;
|
||||
let info = Arc::new(StatementInfo {
|
||||
name: String::new(),
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
name: String::new(),
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
let stmt = Statement::new(self, info, Cell::new(0), true);
|
||||
stmt.execute(params)
|
||||
}
|
||||
@ -1086,10 +1159,10 @@ impl Connection {
|
||||
pub fn query(&self, query: &str, params: &[&ToSql]) -> Result<Rows<'static>> {
|
||||
let (param_types, columns) = self.0.borrow_mut().raw_prepare("", query)?;
|
||||
let info = Arc::new(StatementInfo {
|
||||
name: String::new(),
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
name: String::new(),
|
||||
param_types: param_types,
|
||||
columns: columns,
|
||||
});
|
||||
let stmt = Statement::new(self, info, Cell::new(0), true);
|
||||
stmt.into_query(params)
|
||||
}
|
||||
@ -1127,8 +1200,10 @@ impl Connection {
|
||||
pub fn transaction_with<'a>(&'a self, config: &transaction::Config) -> Result<Transaction<'a>> {
|
||||
let mut conn = self.0.borrow_mut();
|
||||
check_desync!(conn);
|
||||
assert!(conn.trans_depth == 0,
|
||||
"`transaction` must be called on the active transaction");
|
||||
assert!(
|
||||
conn.trans_depth == 0,
|
||||
"`transaction` must be called on the active transaction"
|
||||
);
|
||||
let mut query = "BEGIN".to_owned();
|
||||
config.build_command(&mut query);
|
||||
conn.quick_query(&query)?;
|
||||
@ -1402,22 +1477,24 @@ trait RowsNew {
|
||||
}
|
||||
|
||||
trait LazyRowsNew<'trans, 'stmt> {
|
||||
fn new(stmt: &'stmt Statement<'stmt>,
|
||||
data: VecDeque<RowData>,
|
||||
name: String,
|
||||
row_limit: i32,
|
||||
more_rows: bool,
|
||||
finished: bool,
|
||||
trans: &'trans Transaction<'trans>)
|
||||
-> LazyRows<'trans, 'stmt>;
|
||||
fn new(
|
||||
stmt: &'stmt Statement<'stmt>,
|
||||
data: VecDeque<RowData>,
|
||||
name: String,
|
||||
row_limit: i32,
|
||||
more_rows: bool,
|
||||
finished: bool,
|
||||
trans: &'trans Transaction<'trans>,
|
||||
) -> LazyRows<'trans, 'stmt>;
|
||||
}
|
||||
|
||||
trait StatementInternals<'conn> {
|
||||
fn new(conn: &'conn Connection,
|
||||
info: Arc<StatementInfo>,
|
||||
next_portal_id: Cell<u32>,
|
||||
finished: bool)
|
||||
-> Statement<'conn>;
|
||||
fn new(
|
||||
conn: &'conn Connection,
|
||||
info: Arc<StatementInfo>,
|
||||
next_portal_id: Cell<u32>,
|
||||
finished: bool,
|
||||
) -> Statement<'conn>;
|
||||
|
||||
fn conn(&self) -> &'conn Connection;
|
||||
|
||||
|
@ -39,8 +39,9 @@ impl MessageStream {
|
||||
}
|
||||
|
||||
pub fn write_message<F, E>(&mut self, f: F) -> Result<(), E>
|
||||
where F: FnOnce(&mut Vec<u8>) -> Result<(), E>,
|
||||
E: From<io::Error>
|
||||
where
|
||||
F: FnOnce(&mut Vec<u8>) -> Result<(), E>,
|
||||
E: From<io::Error>,
|
||||
{
|
||||
self.out_buf.clear();
|
||||
f(&mut self.out_buf)?;
|
||||
@ -59,8 +60,13 @@ impl MessageStream {
|
||||
|
||||
fn read_in(&mut self) -> io::Result<()> {
|
||||
self.in_buf.reserve(1);
|
||||
match self.stream.get_mut().read(unsafe { self.in_buf.bytes_mut() }) {
|
||||
Ok(0) => Err(io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF")),
|
||||
match self.stream.get_mut().read(
|
||||
unsafe { self.in_buf.bytes_mut() },
|
||||
) {
|
||||
Ok(0) => Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)),
|
||||
Ok(n) => {
|
||||
unsafe { self.in_buf.advance_mut(n) };
|
||||
Ok(())
|
||||
@ -69,18 +75,20 @@ impl MessageStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_message_timeout(&mut self,
|
||||
timeout: Duration)
|
||||
-> io::Result<Option<backend::Message>> {
|
||||
pub fn read_message_timeout(
|
||||
&mut self,
|
||||
timeout: Duration,
|
||||
) -> io::Result<Option<backend::Message>> {
|
||||
if self.in_buf.is_empty() {
|
||||
self.set_read_timeout(Some(timeout))?;
|
||||
let r = self.read_in();
|
||||
self.set_read_timeout(None)?;
|
||||
|
||||
match r {
|
||||
Ok(()) => {},
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock ||
|
||||
e.kind() == io::ErrorKind::TimedOut => return Ok(None),
|
||||
Ok(()) => {}
|
||||
Err(ref e)
|
||||
if e.kind() == io::ErrorKind::WouldBlock ||
|
||||
e.kind() == io::ErrorKind::TimedOut => return Ok(None),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
@ -95,7 +103,7 @@ impl MessageStream {
|
||||
self.set_nonblocking(false)?;
|
||||
|
||||
match r {
|
||||
Ok(()) => {},
|
||||
Ok(()) => {}
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(None),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
@ -225,7 +233,9 @@ fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
|
||||
let port = params.port();
|
||||
match *params.host() {
|
||||
Host::Tcp(ref host) => {
|
||||
Ok(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)?)
|
||||
Ok(TcpStream::connect(&(&**host, port)).map(
|
||||
InternalStream::Tcp,
|
||||
)?)
|
||||
}
|
||||
#[cfg(unix)]
|
||||
Host::Unix(ref path) => {
|
||||
@ -234,15 +244,18 @@ fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
Host::Unix(..) => {
|
||||
Err(ConnectError::Io(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"unix sockets are not supported on this system")))
|
||||
Err(ConnectError::Io(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"unix sockets are not supported on this system",
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize_stream(params: &ConnectParams,
|
||||
tls: TlsMode)
|
||||
-> Result<Box<TlsStream>, ConnectError> {
|
||||
pub fn initialize_stream(
|
||||
params: &ConnectParams,
|
||||
tls: TlsMode,
|
||||
) -> Result<Box<TlsStream>, ConnectError> {
|
||||
let mut socket = Stream(open_socket(params)?);
|
||||
|
||||
let (tls_required, handshaker) = match tls {
|
||||
@ -272,5 +285,7 @@ pub fn initialize_stream(params: &ConnectParams,
|
||||
Host::Unix(_) => return Err(ConnectError::Io(::bad_response())),
|
||||
};
|
||||
|
||||
handshaker.tls_handshake(host, socket).map_err(ConnectError::Tls)
|
||||
handshaker.tls_handshake(host, socket).map_err(
|
||||
ConnectError::Tls,
|
||||
)
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ impl<'a, T> Deref for MaybeOwned<'a, T> {
|
||||
pub struct Rows<'compat> {
|
||||
stmt_info: Arc<StatementInfo>,
|
||||
data: Vec<RowData>,
|
||||
_marker: PhantomData<&'compat u8>
|
||||
_marker: PhantomData<&'compat u8>,
|
||||
}
|
||||
|
||||
impl RowsNew for Rows<'static> {
|
||||
@ -196,8 +196,9 @@ impl<'a> Row<'a> {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get<I, T>(&self, idx: I) -> T
|
||||
where I: RowIndex + fmt::Debug,
|
||||
T: FromSql
|
||||
where
|
||||
I: RowIndex + fmt::Debug,
|
||||
T: FromSql,
|
||||
{
|
||||
match self.get_inner(&idx) {
|
||||
Some(Ok(ok)) => ok,
|
||||
@ -215,15 +216,17 @@ impl<'a> Row<'a> {
|
||||
/// if there was an error converting the result value, and `Some(Ok(..))`
|
||||
/// on success.
|
||||
pub fn get_opt<I, T>(&self, idx: I) -> Option<Result<T>>
|
||||
where I: RowIndex,
|
||||
T: FromSql
|
||||
where
|
||||
I: RowIndex,
|
||||
T: FromSql,
|
||||
{
|
||||
self.get_inner(&idx)
|
||||
}
|
||||
|
||||
fn get_inner<I, T>(&self, idx: &I) -> Option<Result<T>>
|
||||
where I: RowIndex,
|
||||
T: FromSql
|
||||
where
|
||||
I: RowIndex,
|
||||
T: FromSql,
|
||||
{
|
||||
let idx = match idx.idx(&self.stmt_info.columns) {
|
||||
Some(idx) => idx,
|
||||
@ -244,7 +247,8 @@ impl<'a> Row<'a> {
|
||||
///
|
||||
/// Panics if the index does not reference a column.
|
||||
pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]>
|
||||
where I: RowIndex + fmt::Debug
|
||||
where
|
||||
I: RowIndex + fmt::Debug,
|
||||
{
|
||||
match idx.idx(&self.stmt_info.columns) {
|
||||
Some(idx) => self.data.get(idx),
|
||||
@ -281,7 +285,9 @@ impl<'a> RowIndex for &'a str {
|
||||
// FIXME ASCII-only case insensitivity isn't really the right thing to
|
||||
// do. Postgres itself uses a dubious wrapper around tolower and JDBC
|
||||
// uses the US locale.
|
||||
columns.iter().position(|d| d.name().eq_ignore_ascii_case(*self))
|
||||
columns.iter().position(
|
||||
|d| d.name().eq_ignore_ascii_case(*self),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,14 +303,15 @@ pub struct LazyRows<'trans, 'stmt> {
|
||||
}
|
||||
|
||||
impl<'trans, 'stmt> LazyRowsNew<'trans, 'stmt> for LazyRows<'trans, 'stmt> {
|
||||
fn new(stmt: &'stmt Statement<'stmt>,
|
||||
data: VecDeque<RowData>,
|
||||
name: String,
|
||||
row_limit: i32,
|
||||
more_rows: bool,
|
||||
finished: bool,
|
||||
trans: &'trans Transaction<'trans>)
|
||||
-> LazyRows<'trans, 'stmt> {
|
||||
fn new(
|
||||
stmt: &'stmt Statement<'stmt>,
|
||||
data: VecDeque<RowData>,
|
||||
name: String,
|
||||
row_limit: i32,
|
||||
more_rows: bool,
|
||||
finished: bool,
|
||||
trans: &'trans Transaction<'trans>,
|
||||
) -> LazyRows<'trans, 'stmt> {
|
||||
LazyRows {
|
||||
stmt: stmt,
|
||||
data: data,
|
||||
@ -346,10 +353,18 @@ impl<'trans, 'stmt> LazyRows<'trans, 'stmt> {
|
||||
fn execute(&mut self) -> Result<()> {
|
||||
let mut conn = self.stmt.conn().0.borrow_mut();
|
||||
|
||||
conn.stream.write_message(|buf| frontend::execute(&self.name, self.row_limit, buf))?;
|
||||
conn.stream.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
conn.stream.write_message(|buf| {
|
||||
frontend::execute(&self.name, self.row_limit, buf)
|
||||
})?;
|
||||
conn.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
conn.stream.flush()?;
|
||||
conn.read_rows(|row| self.data.push_back(row)).map(|more_rows| self.more_rows = more_rows)
|
||||
conn.read_rows(|row| self.data.push_back(row)).map(
|
||||
|more_rows| {
|
||||
self.more_rows = more_rows
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a slice describing the columns of the `LazyRows`.
|
||||
@ -375,14 +390,12 @@ impl<'trans, 'stmt> FallibleIterator for LazyRows<'trans, 'stmt> {
|
||||
self.execute()?;
|
||||
}
|
||||
|
||||
let row = self.data
|
||||
.pop_front()
|
||||
.map(|r| {
|
||||
Row {
|
||||
stmt_info: &**self.stmt.info(),
|
||||
data: MaybeOwned::Owned(r),
|
||||
}
|
||||
});
|
||||
let row = self.data.pop_front().map(|r| {
|
||||
Row {
|
||||
stmt_info: &**self.stmt.info(),
|
||||
data: MaybeOwned::Owned(r),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(row)
|
||||
}
|
||||
|
@ -37,11 +37,12 @@ impl<'conn> Drop for Statement<'conn> {
|
||||
}
|
||||
|
||||
impl<'conn> StatementInternals<'conn> for Statement<'conn> {
|
||||
fn new(conn: &'conn Connection,
|
||||
info: Arc<StatementInfo>,
|
||||
next_portal_id: Cell<u32>,
|
||||
finished: bool)
|
||||
-> Statement<'conn> {
|
||||
fn new(
|
||||
conn: &'conn Connection,
|
||||
info: Arc<StatementInfo>,
|
||||
next_portal_id: Cell<u32>,
|
||||
finished: bool,
|
||||
) -> Statement<'conn> {
|
||||
Statement {
|
||||
conn: conn,
|
||||
info: info,
|
||||
@ -79,21 +80,25 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
|
||||
#[allow(type_complexity)]
|
||||
fn inner_query<F>(&self,
|
||||
portal_name: &str,
|
||||
row_limit: i32,
|
||||
params: &[&ToSql],
|
||||
acceptor: F)
|
||||
-> Result<bool>
|
||||
where F: FnMut(RowData)
|
||||
fn inner_query<F>(
|
||||
&self,
|
||||
portal_name: &str,
|
||||
row_limit: i32,
|
||||
params: &[&ToSql],
|
||||
acceptor: F,
|
||||
) -> Result<bool>
|
||||
where
|
||||
F: FnMut(RowData),
|
||||
{
|
||||
let mut conn = self.conn.0.borrow_mut();
|
||||
|
||||
conn.raw_execute(&self.info.name,
|
||||
portal_name,
|
||||
row_limit,
|
||||
self.param_types(),
|
||||
params)?;
|
||||
conn.raw_execute(
|
||||
&self.info.name,
|
||||
portal_name,
|
||||
row_limit,
|
||||
self.param_types(),
|
||||
params,
|
||||
)?;
|
||||
|
||||
conn.read_rows(acceptor)
|
||||
}
|
||||
@ -131,7 +136,13 @@ impl<'conn> Statement<'conn> {
|
||||
pub fn execute(&self, params: &[&ToSql]) -> Result<u64> {
|
||||
let mut conn = self.conn.0.borrow_mut();
|
||||
check_desync!(conn);
|
||||
conn.raw_execute(&self.info.name, "", 0, self.param_types(), params)?;
|
||||
conn.raw_execute(
|
||||
&self.info.name,
|
||||
"",
|
||||
0,
|
||||
self.param_types(),
|
||||
params,
|
||||
)?;
|
||||
|
||||
let num;
|
||||
loop {
|
||||
@ -153,8 +164,9 @@ impl<'conn> Statement<'conn> {
|
||||
conn.stream.write_message(|buf| {
|
||||
frontend::copy_fail("COPY queries cannot be directly executed", buf)
|
||||
})?;
|
||||
conn.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
conn.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
conn.stream.flush()?;
|
||||
}
|
||||
backend::Message::CopyOutResponse(_) => {
|
||||
@ -226,18 +238,23 @@ impl<'conn> Statement<'conn> {
|
||||
/// `Connection` as this `Statement`, if the `Transaction` is not
|
||||
/// active, or if the number of parameters provided does not match the
|
||||
/// number of parameters expected.
|
||||
pub fn lazy_query<'trans, 'stmt>(&'stmt self,
|
||||
trans: &'trans Transaction,
|
||||
params: &[&ToSql],
|
||||
row_limit: i32)
|
||||
-> Result<LazyRows<'trans, 'stmt>> {
|
||||
assert!(self.conn as *const _ == trans.conn() as *const _,
|
||||
"the `Transaction` passed to `lazy_query` must be associated with the same \
|
||||
`Connection` as the `Statement`");
|
||||
pub fn lazy_query<'trans, 'stmt>(
|
||||
&'stmt self,
|
||||
trans: &'trans Transaction,
|
||||
params: &[&ToSql],
|
||||
row_limit: i32,
|
||||
) -> Result<LazyRows<'trans, 'stmt>> {
|
||||
assert!(
|
||||
self.conn as *const _ == trans.conn() as *const _,
|
||||
"the `Transaction` passed to `lazy_query` must be associated with the same \
|
||||
`Connection` as the `Statement`"
|
||||
);
|
||||
let conn = self.conn.0.borrow();
|
||||
check_desync!(conn);
|
||||
assert!(conn.trans_depth == trans.depth(),
|
||||
"`lazy_query` must be passed the active transaction");
|
||||
assert!(
|
||||
conn.trans_depth == trans.depth(),
|
||||
"`lazy_query` must be passed the active transaction"
|
||||
);
|
||||
drop(conn);
|
||||
|
||||
let id = self.next_portal_id.get();
|
||||
@ -245,11 +262,21 @@ impl<'conn> Statement<'conn> {
|
||||
let portal_name = format!("{}p{}", self.info.name, id);
|
||||
|
||||
let mut rows = VecDeque::new();
|
||||
let more_rows = self.inner_query(&portal_name,
|
||||
row_limit,
|
||||
params,
|
||||
|row| rows.push_back(row))?;
|
||||
Ok(LazyRows::new(self, rows, portal_name, row_limit, more_rows, false, trans))
|
||||
let more_rows = self.inner_query(
|
||||
&portal_name,
|
||||
row_limit,
|
||||
params,
|
||||
|row| rows.push_back(row),
|
||||
)?;
|
||||
Ok(LazyRows::new(
|
||||
self,
|
||||
rows,
|
||||
portal_name,
|
||||
row_limit,
|
||||
more_rows,
|
||||
false,
|
||||
trans,
|
||||
))
|
||||
}
|
||||
|
||||
/// Executes a `COPY FROM STDIN` statement, returning the number of rows
|
||||
@ -275,14 +302,18 @@ impl<'conn> Statement<'conn> {
|
||||
/// ```
|
||||
pub fn copy_in<R: ReadWithInfo>(&self, params: &[&ToSql], r: &mut R) -> Result<u64> {
|
||||
let mut conn = self.conn.0.borrow_mut();
|
||||
conn.raw_execute(&self.info.name, "", 0, self.param_types(), params)?;
|
||||
conn.raw_execute(
|
||||
&self.info.name,
|
||||
"",
|
||||
0,
|
||||
self.param_types(),
|
||||
params,
|
||||
)?;
|
||||
|
||||
let (format, column_formats) = match conn.read_message()? {
|
||||
backend::Message::CopyInResponse(body) => {
|
||||
let format = body.format();
|
||||
let column_formats = body.column_formats()
|
||||
.map(|f| Format::from_u16(f))
|
||||
.collect()?;
|
||||
let column_formats = body.column_formats().map(|f| Format::from_u16(f)).collect()?;
|
||||
(format, column_formats)
|
||||
}
|
||||
backend::Message::ErrorResponse(body) => {
|
||||
@ -292,10 +323,12 @@ impl<'conn> Statement<'conn> {
|
||||
_ => {
|
||||
loop {
|
||||
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
|
||||
return Err(Error::Io(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"called `copy_in` on a \
|
||||
return Err(Error::Io(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"called `copy_in` on a \
|
||||
non-`COPY FROM STDIN` \
|
||||
statement")));
|
||||
statement",
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -311,14 +344,20 @@ impl<'conn> Statement<'conn> {
|
||||
match fill_copy_buf(&mut buf, r, &info) {
|
||||
Ok(0) => break,
|
||||
Ok(len) => {
|
||||
conn.stream.write_message(|out| frontend::copy_data(&buf[..len], out))?;
|
||||
conn.stream.write_message(
|
||||
|out| frontend::copy_data(&buf[..len], out),
|
||||
)?;
|
||||
}
|
||||
Err(err) => {
|
||||
conn.stream.write_message(|buf| frontend::copy_fail("", buf))?;
|
||||
conn.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::copy_done(buf)))?;
|
||||
conn.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
conn.stream.write_message(
|
||||
|buf| frontend::copy_fail("", buf),
|
||||
)?;
|
||||
conn.stream.write_message(|buf| {
|
||||
Ok::<(), io::Error>(frontend::copy_done(buf))
|
||||
})?;
|
||||
conn.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
conn.stream.flush()?;
|
||||
match conn.read_message()? {
|
||||
backend::Message::ErrorResponse(_) => {
|
||||
@ -335,8 +374,12 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
}
|
||||
|
||||
conn.stream.write_message(|buf| Ok::<(), io::Error>(frontend::copy_done(buf)))?;
|
||||
conn.stream.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
conn.stream.write_message(|buf| {
|
||||
Ok::<(), io::Error>(frontend::copy_done(buf))
|
||||
})?;
|
||||
conn.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
conn.stream.flush()?;
|
||||
|
||||
let num = match conn.read_message()? {
|
||||
@ -379,21 +422,30 @@ impl<'conn> Statement<'conn> {
|
||||
/// ```
|
||||
pub fn copy_out<'a, W: WriteWithInfo>(&'a self, params: &[&ToSql], w: &mut W) -> Result<u64> {
|
||||
let mut conn = self.conn.0.borrow_mut();
|
||||
conn.raw_execute(&self.info.name, "", 0, self.param_types(), params)?;
|
||||
conn.raw_execute(
|
||||
&self.info.name,
|
||||
"",
|
||||
0,
|
||||
self.param_types(),
|
||||
params,
|
||||
)?;
|
||||
|
||||
let (format, column_formats) = match conn.read_message()? {
|
||||
backend::Message::CopyOutResponse(body) => {
|
||||
let format = body.format();
|
||||
let column_formats = body.column_formats()
|
||||
.map(|f| Format::from_u16(f))
|
||||
.collect()?;
|
||||
let column_formats = body.column_formats().map(|f| Format::from_u16(f)).collect()?;
|
||||
(format, column_formats)
|
||||
}
|
||||
backend::Message::CopyInResponse(_) => {
|
||||
conn.stream.write_message(|buf| frontend::copy_fail("", buf))?;
|
||||
conn.stream
|
||||
.write_message(|buf| Ok::<(), io::Error>(frontend::copy_done(buf)))?;
|
||||
conn.stream.write_message(|buf| Ok::<(), io::Error>(frontend::sync(buf)))?;
|
||||
conn.stream.write_message(
|
||||
|buf| frontend::copy_fail("", buf),
|
||||
)?;
|
||||
conn.stream.write_message(|buf| {
|
||||
Ok::<(), io::Error>(frontend::copy_done(buf))
|
||||
})?;
|
||||
conn.stream.write_message(
|
||||
|buf| Ok::<(), io::Error>(frontend::sync(buf)),
|
||||
)?;
|
||||
conn.stream.flush()?;
|
||||
match conn.read_message()? {
|
||||
backend::Message::ErrorResponse(_) => {
|
||||
@ -405,9 +457,11 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
}
|
||||
conn.wait_for_ready()?;
|
||||
return Err(Error::Io(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"called `copy_out` on a non-`COPY TO \
|
||||
STDOUT` statement")));
|
||||
return Err(Error::Io(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"called `copy_out` on a non-`COPY TO \
|
||||
STDOUT` statement",
|
||||
)));
|
||||
}
|
||||
backend::Message::ErrorResponse(body) => {
|
||||
conn.wait_for_ready()?;
|
||||
@ -416,9 +470,11 @@ impl<'conn> Statement<'conn> {
|
||||
_ => {
|
||||
loop {
|
||||
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
|
||||
return Err(Error::Io(io::Error::new(io::ErrorKind::InvalidInput,
|
||||
"called `copy_out` on a \
|
||||
non-`COPY TO STDOUT` statement")));
|
||||
return Err(Error::Io(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"called `copy_out` on a \
|
||||
non-`COPY TO STDOUT` statement",
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -440,7 +496,8 @@ impl<'conn> Statement<'conn> {
|
||||
Err(e) => {
|
||||
loop {
|
||||
if let backend::Message::ReadyForQuery(_) =
|
||||
conn.read_message()? {
|
||||
conn.read_message()?
|
||||
{
|
||||
return Err(Error::Io(e));
|
||||
}
|
||||
}
|
||||
@ -455,16 +512,14 @@ impl<'conn> Statement<'conn> {
|
||||
}
|
||||
backend::Message::ErrorResponse(body) => {
|
||||
loop {
|
||||
if let backend::Message::ReadyForQuery(_) =
|
||||
conn.read_message()? {
|
||||
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
|
||||
return Err(err(&mut body.fields()));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
loop {
|
||||
if let backend::Message::ReadyForQuery(_) =
|
||||
conn.read_message()? {
|
||||
if let backend::Message::ReadyForQuery(_) = conn.read_message()? {
|
||||
return Err(Error::Io(bad_response()));
|
||||
}
|
||||
}
|
||||
|
@ -31,18 +31,19 @@ pub trait TlsHandshake: fmt::Debug {
|
||||
///
|
||||
/// The host portion of the connection parameters is provided for hostname
|
||||
/// verification.
|
||||
fn tls_handshake(&self,
|
||||
host: &str,
|
||||
stream: Stream)
|
||||
-> Result<Box<TlsStream>, Box<Error + Sync + Send>>;
|
||||
fn tls_handshake(
|
||||
&self,
|
||||
host: &str,
|
||||
stream: Stream,
|
||||
) -> Result<Box<TlsStream>, Box<Error + Sync + Send>>;
|
||||
}
|
||||
|
||||
impl<T: TlsHandshake + ?Sized> TlsHandshake for Box<T> {
|
||||
fn tls_handshake(&self,
|
||||
host: &str,
|
||||
stream: Stream)
|
||||
-> Result<Box<TlsStream>, Box<Error + Sync + Send>> {
|
||||
fn tls_handshake(
|
||||
&self,
|
||||
host: &str,
|
||||
stream: Stream,
|
||||
) -> Result<Box<TlsStream>, Box<Error + Sync + Send>> {
|
||||
(**self).tls_handshake(host, stream)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,10 +54,11 @@ impl From<TlsConnector> for NativeTls {
|
||||
}
|
||||
|
||||
impl TlsHandshake for NativeTls {
|
||||
fn tls_handshake(&self,
|
||||
domain: &str,
|
||||
stream: Stream)
|
||||
-> Result<Box<TlsStream>, Box<Error + Send + Sync>> {
|
||||
fn tls_handshake(
|
||||
&self,
|
||||
domain: &str,
|
||||
stream: Stream,
|
||||
) -> Result<Box<TlsStream>, Box<Error + Send + Sync>> {
|
||||
let stream = self.0.connect(domain, stream)?;
|
||||
Ok(Box::new(stream))
|
||||
}
|
||||
|
@ -70,10 +70,11 @@ impl From<SslConnector> for OpenSsl {
|
||||
}
|
||||
|
||||
impl TlsHandshake for OpenSsl {
|
||||
fn tls_handshake(&self,
|
||||
domain: &str,
|
||||
stream: Stream)
|
||||
-> Result<Box<TlsStream>, Box<Error + Send + Sync>> {
|
||||
fn tls_handshake(
|
||||
&self,
|
||||
domain: &str,
|
||||
stream: Stream,
|
||||
) -> Result<Box<TlsStream>, Box<Error + Send + Sync>> {
|
||||
let stream = if self.disable_verification {
|
||||
self.connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(stream)?
|
||||
} else {
|
||||
|
@ -38,14 +38,16 @@ impl Schannel {
|
||||
}
|
||||
|
||||
impl TlsHandshake for Schannel {
|
||||
fn tls_handshake(&self,
|
||||
host: &str,
|
||||
stream: Stream)
|
||||
-> Result<Box<TlsStream>, Box<Error + Sync + Send>> {
|
||||
fn tls_handshake(
|
||||
&self,
|
||||
host: &str,
|
||||
stream: Stream,
|
||||
) -> Result<Box<TlsStream>, Box<Error + Sync + Send>> {
|
||||
let creds = SchannelCred::builder().acquire(Direction::Outbound)?;
|
||||
let stream = tls_stream::Builder::new()
|
||||
.domain(host)
|
||||
.connect(creds, stream)?;
|
||||
let stream = tls_stream::Builder::new().domain(host).connect(
|
||||
creds,
|
||||
stream,
|
||||
)?;
|
||||
Ok(Box::new(stream))
|
||||
}
|
||||
}
|
||||
|
@ -45,10 +45,11 @@ impl From<ClientBuilder> for SecurityFramework {
|
||||
}
|
||||
|
||||
impl TlsHandshake for SecurityFramework {
|
||||
fn tls_handshake(&self,
|
||||
domain: &str,
|
||||
stream: Stream)
|
||||
-> Result<Box<TlsStream>, Box<Error + Send + Sync>> {
|
||||
fn tls_handshake(
|
||||
&self,
|
||||
domain: &str,
|
||||
stream: Stream,
|
||||
) -> Result<Box<TlsStream>, Box<Error + Send + Sync>> {
|
||||
let stream = self.0.handshake(domain, stream)?;
|
||||
Ok(Box::new(stream))
|
||||
}
|
||||
|
@ -256,8 +256,10 @@ impl<'conn> Transaction<'conn> {
|
||||
pub fn savepoint<'a>(&'a self, name: &str) -> Result<Transaction<'a>> {
|
||||
let mut conn = self.conn.0.borrow_mut();
|
||||
check_desync!(conn);
|
||||
assert!(conn.trans_depth == self.depth,
|
||||
"`savepoint` may only be called on the active transaction");
|
||||
assert!(
|
||||
conn.trans_depth == self.depth,
|
||||
"`savepoint` may only be called on the active transaction"
|
||||
);
|
||||
conn.quick_query(&format!("SAVEPOINT {}", name))?;
|
||||
conn.trans_depth += 1;
|
||||
Ok(Transaction {
|
||||
|
@ -1,8 +1,8 @@
|
||||
//! Traits dealing with Postgres data types
|
||||
|
||||
#[doc(inline)]
|
||||
pub use postgres_shared::types::{Oid, Type, Date, Timestamp, Kind, Field, Other,
|
||||
WasNull, WrongType, FromSql, IsNull, ToSql};
|
||||
pub use postgres_shared::types::{Oid, Type, Date, Timestamp, Kind, Field, Other, WasNull,
|
||||
WrongType, FromSql, IsNull, ToSql};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use postgres_shared::types::__to_sql_checked;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,10 @@ fn test_bit_params() {
|
||||
let mut bv = BitVec::from_bytes(&[0b0110_1001, 0b0000_0111]);
|
||||
bv.pop();
|
||||
bv.pop();
|
||||
test_type("BIT(14)", &[(Some(bv), "B'01101001000001'"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"BIT(14)",
|
||||
&[(Some(bv), "B'01101001000001'"), (None, "NULL")],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -17,7 +19,12 @@ fn test_varbit_params() {
|
||||
let mut bv = BitVec::from_bytes(&[0b0110_1001, 0b0000_0111]);
|
||||
bv.pop();
|
||||
bv.pop();
|
||||
test_type("VARBIT", &[(Some(bv), "B'01101001000001'"),
|
||||
(Some(BitVec::from_bytes(&[])), "B''"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"VARBIT",
|
||||
&[
|
||||
(Some(bv), "B'01101001000001'"),
|
||||
(Some(BitVec::from_bytes(&[])), "B''"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -8,87 +8,145 @@ use postgres::types::{Date, Timestamp};
|
||||
#[test]
|
||||
fn test_naive_date_time_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Option<NaiveDateTime>, &'a str) {
|
||||
(Some(NaiveDateTime::parse_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()), time)
|
||||
(
|
||||
Some(
|
||||
NaiveDateTime::parse_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap(),
|
||||
),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIMESTAMP",
|
||||
&[make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"TIMESTAMP",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_special_naive_date_time_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Timestamp<NaiveDateTime>, &'a str) {
|
||||
(Timestamp::Value(NaiveDateTime::parse_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()),
|
||||
time)
|
||||
(
|
||||
Timestamp::Value(
|
||||
NaiveDateTime::parse_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap(),
|
||||
),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIMESTAMP",
|
||||
&[make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'")]);
|
||||
test_type(
|
||||
"TIMESTAMP",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_time_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Option<DateTime<Utc>>, &'a str) {
|
||||
(Some(Utc.datetime_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()), time)
|
||||
(
|
||||
Some(
|
||||
Utc.datetime_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'")
|
||||
.unwrap(),
|
||||
),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIMESTAMP WITH TIME ZONE",
|
||||
&[make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"TIMESTAMP WITH TIME ZONE",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_special_date_time_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Timestamp<DateTime<Utc>>, &'a str) {
|
||||
(Timestamp::Value(Utc.datetime_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap()), time)
|
||||
(
|
||||
Timestamp::Value(
|
||||
Utc.datetime_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'")
|
||||
.unwrap(),
|
||||
),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIMESTAMP WITH TIME ZONE",
|
||||
&[make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'")]);
|
||||
test_type(
|
||||
"TIMESTAMP WITH TIME ZONE",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.010000000'"),
|
||||
make_check("'1965-09-25 11:19:33.100314000'"),
|
||||
make_check("'2010-02-09 23:11:45.120200000'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Option<NaiveDate>, &'a str) {
|
||||
(Some(NaiveDate::parse_from_str(time, "'%Y-%m-%d'").unwrap()), time)
|
||||
(
|
||||
Some(NaiveDate::parse_from_str(time, "'%Y-%m-%d'").unwrap()),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("DATE",
|
||||
&[make_check("'1970-01-01'"),
|
||||
make_check("'1965-09-25'"),
|
||||
make_check("'2010-02-09'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"DATE",
|
||||
&[
|
||||
make_check("'1970-01-01'"),
|
||||
make_check("'1965-09-25'"),
|
||||
make_check("'2010-02-09'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_special_date_params() {
|
||||
fn make_check<'a>(date: &'a str) -> (Date<NaiveDate>, &'a str) {
|
||||
(Date::Value(NaiveDate::parse_from_str(date, "'%Y-%m-%d'").unwrap()), date)
|
||||
(
|
||||
Date::Value(NaiveDate::parse_from_str(date, "'%Y-%m-%d'").unwrap()),
|
||||
date,
|
||||
)
|
||||
}
|
||||
test_type("DATE",
|
||||
&[make_check("'1970-01-01'"),
|
||||
make_check("'1965-09-25'"),
|
||||
make_check("'2010-02-09'"),
|
||||
(Date::PosInfinity, "'infinity'"),
|
||||
(Date::NegInfinity, "'-infinity'")]);
|
||||
test_type(
|
||||
"DATE",
|
||||
&[
|
||||
make_check("'1970-01-01'"),
|
||||
make_check("'1965-09-25'"),
|
||||
make_check("'2010-02-09'"),
|
||||
(Date::PosInfinity, "'infinity'"),
|
||||
(Date::NegInfinity, "'-infinity'"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Option<NaiveTime>, &'a str) {
|
||||
(Some(NaiveTime::parse_from_str(time, "'%H:%M:%S.%f'").unwrap()), time)
|
||||
(
|
||||
Some(NaiveTime::parse_from_str(time, "'%H:%M:%S.%f'").unwrap()),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIME",
|
||||
&[make_check("'00:00:00.010000000'"),
|
||||
make_check("'11:19:33.100314000'"),
|
||||
make_check("'23:11:45.120200000'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"TIME",
|
||||
&[
|
||||
make_check("'00:00:00.010000000'"),
|
||||
make_check("'11:19:33.100314000'"),
|
||||
make_check("'23:11:45.120200000'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -4,6 +4,14 @@ use types::test_type;
|
||||
|
||||
#[test]
|
||||
fn test_eui48_params() {
|
||||
test_type("MACADDR", &[(Some(eui48::MacAddress::parse_str("12-34-56-AB-CD-EF").unwrap()),
|
||||
"'12-34-56-ab-cd-ef'"), (None, "NULL")])
|
||||
test_type(
|
||||
"MACADDR",
|
||||
&[
|
||||
(
|
||||
Some(eui48::MacAddress::parse_str("12-34-56-AB-CD-EF").unwrap()),
|
||||
"'12-34-56-ab-cd-ef'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -5,24 +5,50 @@ use types::test_type;
|
||||
|
||||
#[test]
|
||||
fn test_point_params() {
|
||||
test_type("POINT",
|
||||
&[(Some(Point::new(0.0, 0.0)), "POINT(0, 0)"),
|
||||
(Some(Point::new(-3.14, 1.618)), "POINT(-3.14, 1.618)"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"POINT",
|
||||
&[
|
||||
(Some(Point::new(0.0, 0.0)), "POINT(0, 0)"),
|
||||
(Some(Point::new(-3.14, 1.618)), "POINT(-3.14, 1.618)"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_box_params() {
|
||||
test_type("BOX",
|
||||
&[(Some(Bbox{xmax: 160.0, ymax: 69701.5615, xmin: -3.14, ymin: 1.618}),
|
||||
"BOX(POINT(160.0, 69701.5615), POINT(-3.14, 1.618))"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"BOX",
|
||||
&[
|
||||
(
|
||||
Some(Bbox {
|
||||
xmax: 160.0,
|
||||
ymax: 69701.5615,
|
||||
xmin: -3.14,
|
||||
ymin: 1.618,
|
||||
}),
|
||||
"BOX(POINT(160.0, 69701.5615), POINT(-3.14, 1.618))",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_params() {
|
||||
let points = vec![Point::new(0.0, 0.0), Point::new(-3.14, 1.618), Point::new(160.0, 69701.5615)];
|
||||
test_type("PATH",
|
||||
&[(Some(LineString(points)),"path '((0, 0), (-3.14, 1.618), (160.0, 69701.5615))'"),
|
||||
(None, "NULL")]);
|
||||
let points = vec![
|
||||
Point::new(0.0, 0.0),
|
||||
Point::new(-3.14, 1.618),
|
||||
Point::new(160.0, 69701.5615),
|
||||
];
|
||||
test_type(
|
||||
"PATH",
|
||||
&[
|
||||
(
|
||||
Some(LineString(points)),
|
||||
"path '((0, 0), (-3.14, 1.618), (160.0, 69701.5615))'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -27,7 +27,10 @@ mod chrono;
|
||||
mod geo;
|
||||
|
||||
fn test_type<T: PartialEq + FromSql + ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
));
|
||||
for &(ref val, ref repr) in checks.iter() {
|
||||
let stmt = or_panic!(conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)));
|
||||
let result = or_panic!(stmt.query(&[])).iter().next().unwrap().get(0);
|
||||
@ -41,7 +44,10 @@ fn test_type<T: PartialEq + FromSql + ToSql, S: fmt::Display>(sql_type: &str, ch
|
||||
|
||||
#[test]
|
||||
fn test_ref_tosql() {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
));
|
||||
let stmt = conn.prepare("SELECT $1::Int").unwrap();
|
||||
let num: &ToSql = &&7;
|
||||
stmt.query(&[num]).unwrap();
|
||||
@ -49,8 +55,10 @@ fn test_ref_tosql() {
|
||||
|
||||
#[test]
|
||||
fn test_bool_params() {
|
||||
test_type("BOOL",
|
||||
&[(Some(true), "'t'"), (Some(false), "'f'"), (None, "NULL")]);
|
||||
test_type(
|
||||
"BOOL",
|
||||
&[(Some(true), "'t'"), (Some(false), "'f'"), (None, "NULL")],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -60,120 +68,190 @@ fn test_i8_params() {
|
||||
|
||||
#[test]
|
||||
fn test_name_params() {
|
||||
test_type("NAME",
|
||||
&[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"NAME",
|
||||
&[
|
||||
(Some("hello world".to_owned()), "'hello world'"),
|
||||
(
|
||||
Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i16_params() {
|
||||
test_type("SMALLINT",
|
||||
&[(Some(15001i16), "15001"),
|
||||
(Some(-15001i16), "-15001"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"SMALLINT",
|
||||
&[
|
||||
(Some(15001i16), "15001"),
|
||||
(Some(-15001i16), "-15001"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i32_params() {
|
||||
test_type("INT",
|
||||
&[(Some(2147483548i32), "2147483548"),
|
||||
(Some(-2147483548i32), "-2147483548"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"INT",
|
||||
&[
|
||||
(Some(2147483548i32), "2147483548"),
|
||||
(Some(-2147483548i32), "-2147483548"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_oid_params() {
|
||||
test_type("OID",
|
||||
&[(Some(2147483548u32), "2147483548"),
|
||||
(Some(4000000000), "4000000000"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"OID",
|
||||
&[
|
||||
(Some(2147483548u32), "2147483548"),
|
||||
(Some(4000000000), "4000000000"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i64_params() {
|
||||
test_type("BIGINT",
|
||||
&[(Some(9223372036854775708i64), "9223372036854775708"),
|
||||
(Some(-9223372036854775708i64), "-9223372036854775708"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"BIGINT",
|
||||
&[
|
||||
(Some(9223372036854775708i64), "9223372036854775708"),
|
||||
(Some(-9223372036854775708i64), "-9223372036854775708"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_params() {
|
||||
test_type("REAL",
|
||||
&[(Some(f32::INFINITY), "'infinity'"),
|
||||
(Some(f32::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(1000.55), "1000.55"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"REAL",
|
||||
&[
|
||||
(Some(f32::INFINITY), "'infinity'"),
|
||||
(Some(f32::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(1000.55), "1000.55"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64_params() {
|
||||
test_type("DOUBLE PRECISION",
|
||||
&[(Some(f64::INFINITY), "'infinity'"),
|
||||
(Some(f64::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(10000.55), "10000.55"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"DOUBLE PRECISION",
|
||||
&[
|
||||
(Some(f64::INFINITY), "'infinity'"),
|
||||
(Some(f64::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(10000.55), "10000.55"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_varchar_params() {
|
||||
test_type("VARCHAR",
|
||||
&[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"VARCHAR",
|
||||
&[
|
||||
(Some("hello world".to_owned()), "'hello world'"),
|
||||
(
|
||||
Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_text_params() {
|
||||
test_type("TEXT",
|
||||
&[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"TEXT",
|
||||
&[
|
||||
(Some("hello world".to_owned()), "'hello world'"),
|
||||
(
|
||||
Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bpchar_params() {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
));
|
||||
or_panic!(conn.execute(
|
||||
"CREATE TEMPORARY TABLE foo (
|
||||
id SERIAL PRIMARY KEY,
|
||||
b CHAR(5)
|
||||
)",
|
||||
&[]));
|
||||
or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
|
||||
&[&Some("12345"), &Some("123"), &None::<&'static str>]));
|
||||
&[],
|
||||
));
|
||||
or_panic!(conn.execute(
|
||||
"INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
|
||||
&[&Some("12345"), &Some("123"), &None::<&'static str>],
|
||||
));
|
||||
let stmt = or_panic!(conn.prepare("SELECT b FROM foo ORDER BY id"));
|
||||
let res = or_panic!(stmt.query(&[]));
|
||||
|
||||
assert_eq!(vec![Some("12345".to_owned()), Some("123 ".to_owned()), None],
|
||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
||||
assert_eq!(
|
||||
vec![Some("12345".to_owned()), Some("123 ".to_owned()), None],
|
||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_citext_params() {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
));
|
||||
or_panic!(conn.execute(
|
||||
"CREATE TEMPORARY TABLE foo (
|
||||
id SERIAL PRIMARY KEY,
|
||||
b CITEXT
|
||||
)",
|
||||
&[]));
|
||||
or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
|
||||
&[&Some("foobar"), &Some("FooBar"), &None::<&'static str>]));
|
||||
let stmt = or_panic!(conn.prepare("SELECT id FROM foo WHERE b = 'FOOBAR' ORDER BY id"));
|
||||
&[],
|
||||
));
|
||||
or_panic!(conn.execute(
|
||||
"INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
|
||||
&[
|
||||
&Some("foobar"),
|
||||
&Some("FooBar"),
|
||||
&None::<&'static str>,
|
||||
],
|
||||
));
|
||||
let stmt = or_panic!(conn.prepare(
|
||||
"SELECT id FROM foo WHERE b = 'FOOBAR' ORDER BY id",
|
||||
));
|
||||
let res = or_panic!(stmt.query(&[]));
|
||||
|
||||
assert_eq!(vec![Some(1i32), Some(2i32)],
|
||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
||||
assert_eq!(
|
||||
vec![Some(1i32), Some(2i32)],
|
||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytea_params() {
|
||||
test_type("BYTEA",
|
||||
&[(Some(vec![0u8, 1, 2, 3, 254, 255]), "'\\x00010203feff'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"BYTEA",
|
||||
&[
|
||||
(Some(vec![0u8, 1, 2, 3, 254, 255]), "'\\x00010203feff'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -185,26 +263,42 @@ fn test_hstore_params() {
|
||||
map
|
||||
})
|
||||
}
|
||||
test_type("hstore",
|
||||
&[(Some(make_map!("a".to_owned() => Some("1".to_owned()))), "'a=>1'"),
|
||||
(Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
|
||||
test_type(
|
||||
"hstore",
|
||||
&[
|
||||
(
|
||||
Some(make_map!("a".to_owned() => Some("1".to_owned()))),
|
||||
"'a=>1'",
|
||||
),
|
||||
(
|
||||
Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
|
||||
"hola".to_owned() => Some("mundo!".to_owned()),
|
||||
"what".to_owned() => None)),
|
||||
"'hello=>world!,hola=>mundo!,what=>NULL'"),
|
||||
(None, "NULL")]);
|
||||
"'hello=>world!,hola=>mundo!,what=>NULL'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_params() {
|
||||
test_type("integer[]",
|
||||
&[(Some(vec![1i32, 2i32]), "ARRAY[1,2]"),
|
||||
(Some(vec![1i32]), "ARRAY[1]"),
|
||||
(Some(vec![]), "ARRAY[]"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"integer[]",
|
||||
&[
|
||||
(Some(vec![1i32, 2i32]), "ARRAY[1,2]"),
|
||||
(Some(vec![1i32]), "ARRAY[1]"),
|
||||
(Some(vec![]), "ARRAY[]"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
fn test_nan_param<T: PartialEq + ToSql + FromSql>(sql_type: &str) {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
));
|
||||
let stmt = or_panic!(conn.prepare(&*format!("SELECT 'NaN'::{}", sql_type)));
|
||||
let result = or_panic!(stmt.query(&[]));
|
||||
let val: T = result.iter().next().unwrap().get(0);
|
||||
@ -223,7 +317,10 @@ fn test_f64_nan_param() {
|
||||
|
||||
#[test]
|
||||
fn test_pg_database_datname() {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
));
|
||||
let stmt = or_panic!(conn.prepare("SELECT datname FROM pg_database"));
|
||||
let result = or_panic!(stmt.query(&[]));
|
||||
|
||||
@ -235,18 +332,21 @@ fn test_pg_database_datname() {
|
||||
#[test]
|
||||
fn test_slice() {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, f VARCHAR);
|
||||
INSERT INTO foo (f) VALUES ('a'), ('b'), ('c'), ('d');")
|
||||
.unwrap();
|
||||
conn.batch_execute(
|
||||
"CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, f VARCHAR);
|
||||
INSERT INTO foo (f) VALUES ('a'), ('b'), ('c'), ('d');",
|
||||
).unwrap();
|
||||
|
||||
let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)")
|
||||
.unwrap();
|
||||
let result = stmt.query(&[&&[1i32, 3, 4][..]]).unwrap();
|
||||
assert_eq!(vec!["a".to_owned(), "c".to_owned(), "d".to_owned()],
|
||||
result
|
||||
.iter()
|
||||
.map(|r| r.get::<_, String>(0))
|
||||
.collect::<Vec<_>>());
|
||||
assert_eq!(
|
||||
vec!["a".to_owned(), "c".to_owned(), "d".to_owned()],
|
||||
result
|
||||
.iter()
|
||||
.map(|r| r.get::<_, String>(0))
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -282,10 +382,11 @@ fn domain() {
|
||||
struct SessionId(Vec<u8>);
|
||||
|
||||
impl ToSql for SessionId {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> result::Result<IsNull, Box<error::Error + Sync + Send>> {
|
||||
fn to_sql(
|
||||
&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>,
|
||||
) -> result::Result<IsNull, Box<error::Error + Sync + Send>> {
|
||||
let inner = match *ty.kind() {
|
||||
Kind::Domain(ref inner) => inner,
|
||||
_ => unreachable!(),
|
||||
@ -295,19 +396,20 @@ fn domain() {
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
ty.name() == "session_id" &&
|
||||
match *ty.kind() {
|
||||
Kind::Domain(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
match *ty.kind() {
|
||||
Kind::Domain(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for SessionId {
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> result::Result<Self, Box<error::Error + Sync + Send>> {
|
||||
fn from_sql(
|
||||
ty: &Type,
|
||||
raw: &[u8],
|
||||
) -> result::Result<Self, Box<error::Error + Sync + Send>> {
|
||||
Vec::<u8>::from_sql(ty, raw).map(SessionId)
|
||||
}
|
||||
|
||||
@ -318,9 +420,10 @@ fn domain() {
|
||||
}
|
||||
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.batch_execute("CREATE DOMAIN pg_temp.session_id AS bytea CHECK(octet_length(VALUE) = 16);
|
||||
CREATE TABLE pg_temp.foo (id pg_temp.session_id);")
|
||||
.unwrap();
|
||||
conn.batch_execute(
|
||||
"CREATE DOMAIN pg_temp.session_id AS bytea CHECK(octet_length(VALUE) = 16);
|
||||
CREATE TABLE pg_temp.foo (id pg_temp.session_id);",
|
||||
).unwrap();
|
||||
|
||||
let id = SessionId(b"0123456789abcdef".to_vec());
|
||||
conn.execute("INSERT INTO pg_temp.foo (id) VALUES ($1)", &[&id])
|
||||
@ -332,12 +435,13 @@ fn domain() {
|
||||
#[test]
|
||||
fn composite() {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.batch_execute("CREATE TYPE pg_temp.inventory_item AS (
|
||||
conn.batch_execute(
|
||||
"CREATE TYPE pg_temp.inventory_item AS (
|
||||
name TEXT,
|
||||
supplier INTEGER,
|
||||
price NUMERIC
|
||||
)")
|
||||
.unwrap();
|
||||
)",
|
||||
).unwrap();
|
||||
|
||||
let stmt = conn.prepare("SELECT $1::inventory_item").unwrap();
|
||||
let type_ = &stmt.param_types()[0];
|
||||
@ -366,8 +470,10 @@ fn enum_() {
|
||||
assert_eq!(type_.name(), "mood");
|
||||
match *type_.kind() {
|
||||
Kind::Enum(ref variants) => {
|
||||
assert_eq!(variants,
|
||||
&["sad".to_owned(), "ok".to_owned(), "happy".to_owned()]);
|
||||
assert_eq!(
|
||||
variants,
|
||||
&["sad".to_owned(), "ok".to_owned(), "happy".to_owned()]
|
||||
);
|
||||
}
|
||||
_ => panic!("bad type"),
|
||||
}
|
||||
|
@ -6,18 +6,36 @@ use types::test_type;
|
||||
|
||||
#[test]
|
||||
fn test_json_params() {
|
||||
test_type("JSON", &[(Some(Json::from_str("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'"),
|
||||
(Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"JSON",
|
||||
&[
|
||||
(
|
||||
Some(Json::from_str("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'",
|
||||
),
|
||||
(
|
||||
Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jsonb_params() {
|
||||
test_type("JSONB", &[(Some(Json::from_str("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'"),
|
||||
(Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"JSONB",
|
||||
&[
|
||||
(
|
||||
Some(Json::from_str("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'",
|
||||
),
|
||||
(
|
||||
Some(Json::from_str("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -5,18 +5,36 @@ use types::test_type;
|
||||
|
||||
#[test]
|
||||
fn test_json_params() {
|
||||
test_type("JSON", &[(Some(serde_json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'"),
|
||||
(Some(serde_json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"JSON",
|
||||
&[
|
||||
(
|
||||
Some(serde_json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'",
|
||||
),
|
||||
(
|
||||
Some(serde_json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jsonb_params() {
|
||||
test_type("JSONB", &[(Some(serde_json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'"),
|
||||
(Some(serde_json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"JSONB",
|
||||
&[
|
||||
(
|
||||
Some(serde_json::from_str::<Value>("[10, 11, 12]").unwrap()),
|
||||
"'[10, 11, 12]'",
|
||||
),
|
||||
(
|
||||
Some(serde_json::from_str::<Value>("{\"f\": \"asd\"}").unwrap()),
|
||||
"'{\"f\": \"asd\"}'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -8,36 +8,65 @@ use postgres::types::Timestamp;
|
||||
#[test]
|
||||
fn test_tm_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Option<Timespec>, &'a str) {
|
||||
(Some(time::strptime(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap().to_timespec()), time)
|
||||
(
|
||||
Some(
|
||||
time::strptime(time, "'%Y-%m-%d %H:%M:%S.%f'")
|
||||
.unwrap()
|
||||
.to_timespec(),
|
||||
),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIMESTAMP",
|
||||
&[make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(None, "NULL")]);
|
||||
test_type("TIMESTAMP WITH TIME ZONE",
|
||||
&[make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(None, "NULL")]);
|
||||
test_type(
|
||||
"TIMESTAMP",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
test_type(
|
||||
"TIMESTAMP WITH TIME ZONE",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(None, "NULL"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_special_tm_params() {
|
||||
fn make_check<'a>(time: &'a str) -> (Timestamp<Timespec>, &'a str) {
|
||||
(Timestamp::Value(time::strptime(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap().to_timespec()),
|
||||
time)
|
||||
(
|
||||
Timestamp::Value(
|
||||
time::strptime(time, "'%Y-%m-%d %H:%M:%S.%f'")
|
||||
.unwrap()
|
||||
.to_timespec(),
|
||||
),
|
||||
time,
|
||||
)
|
||||
}
|
||||
test_type("TIMESTAMP",
|
||||
&[make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'")]);
|
||||
test_type("TIMESTAMP WITH TIME ZONE",
|
||||
&[make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'")]);
|
||||
test_type(
|
||||
"TIMESTAMP",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'"),
|
||||
],
|
||||
);
|
||||
test_type(
|
||||
"TIMESTAMP WITH TIME ZONE",
|
||||
&[
|
||||
make_check("'1970-01-01 00:00:00.01'"),
|
||||
make_check("'1965-09-25 11:19:33.100314'"),
|
||||
make_check("'2010-02-09 23:11:45.1202'"),
|
||||
(Timestamp::PosInfinity, "'infinity'"),
|
||||
(Timestamp::NegInfinity, "'-infinity'"),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,16 @@ use types::test_type;
|
||||
|
||||
#[test]
|
||||
fn test_uuid_params() {
|
||||
test_type("UUID", &[(Some(uuid::Uuid::parse_str("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11").unwrap()),
|
||||
"'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'"),
|
||||
(None, "NULL")])
|
||||
test_type(
|
||||
"UUID",
|
||||
&[
|
||||
(
|
||||
Some(
|
||||
uuid::Uuid::parse_str("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11").unwrap(),
|
||||
),
|
||||
"'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'",
|
||||
),
|
||||
(None, "NULL"),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
@ -137,21 +137,29 @@ pub enum TlsMode {
|
||||
///
|
||||
/// Only the host and port of the connection info are used. See
|
||||
/// `Connection::connect` for details of the `params` argument.
|
||||
pub fn cancel_query<T>(params: T,
|
||||
tls_mode: TlsMode,
|
||||
cancel_data: CancelData,
|
||||
handle: &Handle)
|
||||
-> BoxFuture<(), ConnectError>
|
||||
where T: IntoConnectParams
|
||||
pub fn cancel_query<T>(
|
||||
params: T,
|
||||
tls_mode: TlsMode,
|
||||
cancel_data: CancelData,
|
||||
handle: &Handle,
|
||||
) -> BoxFuture<(), ConnectError>
|
||||
where
|
||||
T: IntoConnectParams,
|
||||
{
|
||||
let params = match params.into_connect_params() {
|
||||
Ok(params) => {
|
||||
Either::A(stream::connect(params.host().clone(), params.port(), tls_mode, handle))
|
||||
Either::A(stream::connect(
|
||||
params.host().clone(),
|
||||
params.port(),
|
||||
tls_mode,
|
||||
handle,
|
||||
))
|
||||
}
|
||||
Err(e) => Either::B(Err(ConnectError::ConnectParams(e)).into_future()),
|
||||
};
|
||||
|
||||
params.and_then(move |c| {
|
||||
params
|
||||
.and_then(move |c| {
|
||||
let mut buf = vec![];
|
||||
frontend::cancel_request(cancel_data.process_id, cancel_data.secret_key, &mut buf);
|
||||
c.send(buf).map_err(ConnectError::Io)
|
||||
@ -177,31 +185,29 @@ impl InnerConnection {
|
||||
fn read(self) -> IoFuture<(backend::Message, InnerConnection)> {
|
||||
self.into_future()
|
||||
.map_err(|e| e.0)
|
||||
.and_then(|(m, mut s)| {
|
||||
match m {
|
||||
Some(backend::Message::NotificationResponse(body)) => {
|
||||
let process_id = body.process_id();
|
||||
let channel = match body.channel() {
|
||||
Ok(channel) => channel.to_owned(),
|
||||
Err(e) => return Either::A(Err(e).into_future()),
|
||||
};
|
||||
let message = match body.message() {
|
||||
Ok(channel) => channel.to_owned(),
|
||||
Err(e) => return Either::A(Err(e).into_future()),
|
||||
};
|
||||
let notification = Notification {
|
||||
process_id: process_id,
|
||||
channel: channel,
|
||||
payload: message,
|
||||
};
|
||||
s.notifications.push_back(notification);
|
||||
Either::B(s.read())
|
||||
}
|
||||
Some(m) => Either::A(Ok((m, s)).into_future()),
|
||||
None => {
|
||||
let err = io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF");
|
||||
Either::A(Err(err).into_future())
|
||||
}
|
||||
.and_then(|(m, mut s)| match m {
|
||||
Some(backend::Message::NotificationResponse(body)) => {
|
||||
let process_id = body.process_id();
|
||||
let channel = match body.channel() {
|
||||
Ok(channel) => channel.to_owned(),
|
||||
Err(e) => return Either::A(Err(e).into_future()),
|
||||
};
|
||||
let message = match body.message() {
|
||||
Ok(channel) => channel.to_owned(),
|
||||
Err(e) => return Either::A(Err(e).into_future()),
|
||||
};
|
||||
let notification = Notification {
|
||||
process_id: process_id,
|
||||
channel: channel,
|
||||
payload: message,
|
||||
};
|
||||
s.notifications.push_back(notification);
|
||||
Either::B(s.read())
|
||||
}
|
||||
Some(m) => Either::A(Ok((m, s)).into_future()),
|
||||
None => {
|
||||
let err = io::Error::new(io::ErrorKind::UnexpectedEof, "unexpected EOF");
|
||||
Either::A(Err(err).into_future())
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
@ -247,8 +253,7 @@ pub struct Connection(InnerConnection);
|
||||
// FIXME fill out
|
||||
impl fmt::Debug for Connection {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("Connection")
|
||||
.finish()
|
||||
fmt.debug_struct("Connection").finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,48 +276,54 @@ impl Connection {
|
||||
/// path contains non-UTF 8 characters, a `ConnectParams` struct should be
|
||||
/// created manually and passed in. Note that Postgres does not support TLS
|
||||
/// over Unix sockets.
|
||||
pub fn connect<T>(params: T,
|
||||
tls_mode: TlsMode,
|
||||
handle: &Handle)
|
||||
-> BoxFuture<Connection, ConnectError>
|
||||
where T: IntoConnectParams
|
||||
pub fn connect<T>(
|
||||
params: T,
|
||||
tls_mode: TlsMode,
|
||||
handle: &Handle,
|
||||
) -> BoxFuture<Connection, ConnectError>
|
||||
where
|
||||
T: IntoConnectParams,
|
||||
{
|
||||
let fut = match params.into_connect_params() {
|
||||
Ok(params) => {
|
||||
Either::A(stream::connect(params.host().clone(), params.port(), tls_mode, handle)
|
||||
.map(|s| (s, params)))
|
||||
Either::A(
|
||||
stream::connect(params.host().clone(), params.port(), tls_mode, handle)
|
||||
.map(|s| (s, params)),
|
||||
)
|
||||
}
|
||||
Err(e) => Either::B(Err(ConnectError::ConnectParams(e)).into_future()),
|
||||
};
|
||||
|
||||
fut.map(|(s, params)| {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
(Connection(InnerConnection {
|
||||
stream: s,
|
||||
close_sender: sender,
|
||||
close_receiver: receiver,
|
||||
parameters: HashMap::new(),
|
||||
types: HashMap::new(),
|
||||
notifications: VecDeque::new(),
|
||||
cancel_data: CancelData {
|
||||
process_id: 0,
|
||||
secret_key: 0,
|
||||
},
|
||||
has_typeinfo_query: false,
|
||||
has_typeinfo_enum_query: false,
|
||||
has_typeinfo_composite_query: false,
|
||||
}),
|
||||
params)
|
||||
})
|
||||
.and_then(|(s, params)| s.startup(params))
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
(
|
||||
Connection(InnerConnection {
|
||||
stream: s,
|
||||
close_sender: sender,
|
||||
close_receiver: receiver,
|
||||
parameters: HashMap::new(),
|
||||
types: HashMap::new(),
|
||||
notifications: VecDeque::new(),
|
||||
cancel_data: CancelData {
|
||||
process_id: 0,
|
||||
secret_key: 0,
|
||||
},
|
||||
has_typeinfo_query: false,
|
||||
has_typeinfo_enum_query: false,
|
||||
has_typeinfo_composite_query: false,
|
||||
}),
|
||||
params,
|
||||
)
|
||||
}).and_then(|(s, params)| s.startup(params))
|
||||
.and_then(|(s, params)| s.handle_auth(params))
|
||||
.and_then(|s| s.finish_startup())
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn startup(self,
|
||||
params: ConnectParams)
|
||||
-> BoxFuture<(Connection, ConnectParams), ConnectError> {
|
||||
fn startup(
|
||||
self,
|
||||
params: ConnectParams,
|
||||
) -> BoxFuture<(Connection, ConnectParams), ConnectError> {
|
||||
let mut buf = vec![];
|
||||
let result = {
|
||||
let options = [("client_encoding", "UTF8"), ("timezone", "GMT")];
|
||||
@ -348,27 +359,35 @@ impl Connection {
|
||||
.map_err(Into::into)
|
||||
}
|
||||
None => {
|
||||
Err(ConnectError::ConnectParams("password was required but not \
|
||||
Err(ConnectError::ConnectParams(
|
||||
"password was required but not \
|
||||
provided"
|
||||
.into()))
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
backend::Message::AuthenticationMd5Password(body) => {
|
||||
match params.user().and_then(|u| u.password().map(|p| (u.name(), p))) {
|
||||
match params.user().and_then(
|
||||
|u| u.password().map(|p| (u.name(), p)),
|
||||
) {
|
||||
Some((user, pass)) => {
|
||||
let pass = authentication::md5_hash(user.as_bytes(),
|
||||
pass.as_bytes(),
|
||||
body.salt());
|
||||
let pass = authentication::md5_hash(
|
||||
user.as_bytes(),
|
||||
pass.as_bytes(),
|
||||
body.salt(),
|
||||
);
|
||||
let mut buf = vec![];
|
||||
frontend::password_message(&pass, &mut buf)
|
||||
.map(|()| Some(buf))
|
||||
.map_err(Into::into)
|
||||
}
|
||||
None => {
|
||||
Err(ConnectError::ConnectParams("password was required but not \
|
||||
Err(ConnectError::ConnectParams(
|
||||
"password was required but not \
|
||||
provided"
|
||||
.into()))
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -428,9 +447,10 @@ impl Connection {
|
||||
}
|
||||
|
||||
// This has its own read_rows since it will need to handle multiple query completions
|
||||
fn simple_read_rows(self,
|
||||
mut rows: Vec<RowData>)
|
||||
-> BoxFuture<(Vec<RowData>, Connection), Error> {
|
||||
fn simple_read_rows(
|
||||
self,
|
||||
mut rows: Vec<RowData>,
|
||||
) -> BoxFuture<(Vec<RowData>, Connection), Error> {
|
||||
self.0
|
||||
.read()
|
||||
.map_err(Error::Io)
|
||||
@ -457,7 +477,8 @@ impl Connection {
|
||||
}
|
||||
|
||||
fn ready<T>(self, t: T) -> BoxFuture<(T, Connection), Error>
|
||||
where T: 'static + Send
|
||||
where
|
||||
T: 'static + Send,
|
||||
{
|
||||
self.0
|
||||
.read()
|
||||
@ -485,7 +506,9 @@ impl Connection {
|
||||
frontend::sync(&mut buf);
|
||||
messages.push(buf);
|
||||
self.0
|
||||
.send_all(futures::stream::iter(messages.into_iter().map(Ok::<_, io::Error>)))
|
||||
.send_all(futures::stream::iter(
|
||||
messages.into_iter().map(Ok::<_, io::Error>),
|
||||
))
|
||||
.map_err(Error::Io)
|
||||
.and_then(|s| Connection(s.0).finish_close_gc())
|
||||
.boxed()
|
||||
@ -505,7 +528,8 @@ impl Connection {
|
||||
}
|
||||
|
||||
fn ready_err<T>(self, body: ErrorResponseBody) -> BoxFuture<T, Error>
|
||||
where T: 'static + Send
|
||||
where
|
||||
T: 'static + Send,
|
||||
{
|
||||
DbError::new(&mut body.fields())
|
||||
.map_err(Error::Io)
|
||||
@ -529,15 +553,14 @@ impl Connection {
|
||||
/// data in the statement. Do not form statements via string concatenation
|
||||
/// and feed them into this method.
|
||||
pub fn batch_execute(self, query: &str) -> BoxFuture<Connection, Error> {
|
||||
self.simple_query(query)
|
||||
.map(|r| r.1)
|
||||
.boxed()
|
||||
self.simple_query(query).map(|r| r.1).boxed()
|
||||
}
|
||||
|
||||
fn raw_prepare(self,
|
||||
name: &str,
|
||||
query: &str)
|
||||
-> BoxFuture<(Vec<Type>, Vec<Column>, Connection), Error> {
|
||||
fn raw_prepare(
|
||||
self,
|
||||
name: &str,
|
||||
query: &str,
|
||||
) -> BoxFuture<(Vec<Type>, Vec<Column>, Connection), Error> {
|
||||
let mut parse = vec![];
|
||||
let mut describe = vec![];
|
||||
let mut sync = vec![];
|
||||
@ -605,17 +628,19 @@ impl Connection {
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn get_types<T, U, I, F, G>(self,
|
||||
mut raw: I,
|
||||
mut out: Vec<U>,
|
||||
mut get_oid: F,
|
||||
mut build: G)
|
||||
-> BoxFuture<(Vec<U>, Connection), Error>
|
||||
where T: 'static + Send,
|
||||
U: 'static + Send,
|
||||
I: 'static + Send + Iterator<Item = T>,
|
||||
F: 'static + Send + FnMut(&T) -> Oid,
|
||||
G: 'static + Send + FnMut(T, Type) -> U
|
||||
fn get_types<T, U, I, F, G>(
|
||||
self,
|
||||
mut raw: I,
|
||||
mut out: Vec<U>,
|
||||
mut get_oid: F,
|
||||
mut build: G,
|
||||
) -> BoxFuture<(Vec<U>, Connection), Error>
|
||||
where
|
||||
T: 'static + Send,
|
||||
U: 'static + Send,
|
||||
I: 'static + Send + Iterator<Item = T>,
|
||||
F: 'static + Send + FnMut(&T) -> Oid,
|
||||
G: 'static + Send + FnMut(T, Type) -> U,
|
||||
{
|
||||
match raw.next() {
|
||||
Some(v) => {
|
||||
@ -651,7 +676,9 @@ impl Connection {
|
||||
|
||||
fn get_unknown_type(self, oid: Oid) -> BoxFuture<(Other, Connection), Error> {
|
||||
self.setup_typeinfo_query()
|
||||
.and_then(move |c| c.raw_execute(TYPEINFO_QUERY, "", &[Type::Oid], &[&oid]))
|
||||
.and_then(move |c| {
|
||||
c.raw_execute(TYPEINFO_QUERY, "", &[Type::Oid], &[&oid])
|
||||
})
|
||||
.and_then(|c| c.read_rows().collect())
|
||||
.and_then(move |(r, c)| {
|
||||
let get = |idx| r.get(0).and_then(|r| r.get(idx));
|
||||
@ -688,22 +715,42 @@ impl Connection {
|
||||
let kind = if type_ == b'p' as i8 {
|
||||
Either::A(Ok((Kind::Pseudo, c)).into_future())
|
||||
} else if type_ == b'e' as i8 {
|
||||
Either::B(c.get_enum_variants(oid).map(|(v, c)| (Kind::Enum(v), c)).boxed())
|
||||
Either::B(
|
||||
c.get_enum_variants(oid)
|
||||
.map(|(v, c)| (Kind::Enum(v), c))
|
||||
.boxed(),
|
||||
)
|
||||
} else if basetype != 0 {
|
||||
Either::B(c.get_type(basetype).map(|(t, c)| (Kind::Domain(t), c)).boxed())
|
||||
Either::B(
|
||||
c.get_type(basetype)
|
||||
.map(|(t, c)| (Kind::Domain(t), c))
|
||||
.boxed(),
|
||||
)
|
||||
} else if elem_oid != 0 {
|
||||
Either::B(c.get_type(elem_oid).map(|(t, c)| (Kind::Array(t), c)).boxed())
|
||||
Either::B(
|
||||
c.get_type(elem_oid)
|
||||
.map(|(t, c)| (Kind::Array(t), c))
|
||||
.boxed(),
|
||||
)
|
||||
} else if relid != 0 {
|
||||
Either::B(c.get_composite_fields(relid)
|
||||
.map(|(f, c)| (Kind::Composite(f), c))
|
||||
.boxed())
|
||||
Either::B(
|
||||
c.get_composite_fields(relid)
|
||||
.map(|(f, c)| (Kind::Composite(f), c))
|
||||
.boxed(),
|
||||
)
|
||||
} else if let Some(rngsubtype) = rngsubtype {
|
||||
Either::B(c.get_type(rngsubtype).map(|(t, c)| (Kind::Range(t), c)).boxed())
|
||||
Either::B(
|
||||
c.get_type(rngsubtype)
|
||||
.map(|(t, c)| (Kind::Range(t), c))
|
||||
.boxed(),
|
||||
)
|
||||
} else {
|
||||
Either::A(Ok((Kind::Simple, c)).into_future())
|
||||
};
|
||||
|
||||
Either::B(kind.map(move |(k, c)| (Other::new(name, oid, k, schema), c)))
|
||||
Either::B(kind.map(
|
||||
move |(k, c)| (Other::new(name, oid, k, schema), c),
|
||||
))
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
@ -713,16 +760,17 @@ impl Connection {
|
||||
return Ok(self).into_future().boxed();
|
||||
}
|
||||
|
||||
self.raw_prepare(TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, \
|
||||
self.raw_prepare(
|
||||
TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, r.rngsubtype, \
|
||||
t.typbasetype, n.nspname, t.typrelid \
|
||||
FROM pg_catalog.pg_type t \
|
||||
LEFT OUTER JOIN pg_catalog.pg_range r ON \
|
||||
r.rngtypid = t.oid \
|
||||
INNER JOIN pg_catalog.pg_namespace n ON \
|
||||
t.typnamespace = n.oid \
|
||||
WHERE t.oid = $1")
|
||||
.or_else(|e| {
|
||||
WHERE t.oid = $1",
|
||||
).or_else(|e| {
|
||||
match e {
|
||||
// Range types weren't added until Postgres 9.2, so pg_range may not exist
|
||||
Error::Db(e, c) => {
|
||||
@ -730,14 +778,16 @@ impl Connection {
|
||||
return Either::B(Err(Error::Db(e, c)).into_future());
|
||||
}
|
||||
|
||||
Either::A(c.raw_prepare(TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, \
|
||||
Either::A(c.raw_prepare(
|
||||
TYPEINFO_QUERY,
|
||||
"SELECT t.typname, t.typtype, t.typelem, \
|
||||
NULL::OID, t.typbasetype, n.nspname, \
|
||||
t.typrelid \
|
||||
FROM pg_catalog.pg_type t \
|
||||
INNER JOIN pg_catalog.pg_namespace n \
|
||||
ON t.typnamespace = n.oid \
|
||||
WHERE t.oid = $1"))
|
||||
WHERE t.oid = $1",
|
||||
))
|
||||
}
|
||||
e => Either::B(Err(e).into_future()),
|
||||
}
|
||||
@ -751,7 +801,9 @@ impl Connection {
|
||||
|
||||
fn get_enum_variants(self, oid: Oid) -> BoxFuture<(Vec<String>, Connection), Error> {
|
||||
self.setup_typeinfo_enum_query()
|
||||
.and_then(move |c| c.raw_execute(TYPEINFO_ENUM_QUERY, "", &[Type::Oid], &[&oid]))
|
||||
.and_then(move |c| {
|
||||
c.raw_execute(TYPEINFO_ENUM_QUERY, "", &[Type::Oid], &[&oid])
|
||||
})
|
||||
.and_then(|c| c.read_rows().collect())
|
||||
.and_then(|(r, c)| {
|
||||
let mut variants = vec![];
|
||||
@ -772,20 +824,23 @@ impl Connection {
|
||||
return Ok(self).into_future().boxed();
|
||||
}
|
||||
|
||||
self.raw_prepare(TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel \
|
||||
self.raw_prepare(
|
||||
TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel \
|
||||
FROM pg_catalog.pg_enum \
|
||||
WHERE enumtypid = $1 \
|
||||
ORDER BY enumsortorder")
|
||||
.or_else(|e| match e {
|
||||
ORDER BY enumsortorder",
|
||||
).or_else(|e| match e {
|
||||
Error::Db(e, c) => {
|
||||
if e.code != SqlState::UndefinedColumn {
|
||||
return Either::B(Err(Error::Db(e, c)).into_future());
|
||||
}
|
||||
|
||||
Either::A(c.raw_prepare(TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel FROM pg_catalog.pg_enum WHERE \
|
||||
enumtypid = $1 ORDER BY oid"))
|
||||
Either::A(c.raw_prepare(
|
||||
TYPEINFO_ENUM_QUERY,
|
||||
"SELECT enumlabel FROM pg_catalog.pg_enum WHERE \
|
||||
enumtypid = $1 ORDER BY oid",
|
||||
))
|
||||
}
|
||||
e => Either::B(Err(e).into_future()),
|
||||
})
|
||||
@ -803,8 +858,9 @@ impl Connection {
|
||||
})
|
||||
.and_then(|c| c.read_rows().collect())
|
||||
.and_then(|(r, c)| {
|
||||
futures::stream::iter(r.into_iter().map(Ok))
|
||||
.fold((vec![], c), |(mut fields, c), row| {
|
||||
futures::stream::iter(r.into_iter().map(Ok)).fold(
|
||||
(vec![], c),
|
||||
|(mut fields, c), row| {
|
||||
let name = match String::from_sql_nullable(&Type::Name, row.get(0)) {
|
||||
Ok(name) => name,
|
||||
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
|
||||
@ -813,12 +869,12 @@ impl Connection {
|
||||
Ok(oid) => oid,
|
||||
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
|
||||
};
|
||||
Either::B(c.get_type(oid)
|
||||
.map(move |(ty, c)| {
|
||||
fields.push(Field::new(name, ty));
|
||||
(fields, c)
|
||||
}))
|
||||
})
|
||||
Either::B(c.get_type(oid).map(move |(ty, c)| {
|
||||
fields.push(Field::new(name, ty));
|
||||
(fields, c)
|
||||
}))
|
||||
},
|
||||
)
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
@ -828,46 +884,52 @@ impl Connection {
|
||||
return Ok(self).into_future().boxed();
|
||||
}
|
||||
|
||||
self.raw_prepare(TYPEINFO_COMPOSITE_QUERY,
|
||||
"SELECT attname, atttypid \
|
||||
self.raw_prepare(
|
||||
TYPEINFO_COMPOSITE_QUERY,
|
||||
"SELECT attname, atttypid \
|
||||
FROM pg_catalog.pg_attribute \
|
||||
WHERE attrelid = $1 \
|
||||
AND NOT attisdropped \
|
||||
AND attnum > 0 \
|
||||
ORDER BY attnum")
|
||||
.map(|(_, _, mut c)| {
|
||||
ORDER BY attnum",
|
||||
).map(|(_, _, mut c)| {
|
||||
c.0.has_typeinfo_composite_query = true;
|
||||
c
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn raw_execute(self,
|
||||
stmt: &str,
|
||||
portal: &str,
|
||||
param_types: &[Type],
|
||||
params: &[&ToSql])
|
||||
-> BoxFuture<Connection, Error> {
|
||||
assert!(param_types.len() == params.len(),
|
||||
"expected {} parameters but got {}",
|
||||
param_types.len(),
|
||||
params.len());
|
||||
fn raw_execute(
|
||||
self,
|
||||
stmt: &str,
|
||||
portal: &str,
|
||||
param_types: &[Type],
|
||||
params: &[&ToSql],
|
||||
) -> BoxFuture<Connection, Error> {
|
||||
assert!(
|
||||
param_types.len() == params.len(),
|
||||
"expected {} parameters but got {}",
|
||||
param_types.len(),
|
||||
params.len()
|
||||
);
|
||||
|
||||
let mut bind = vec![];
|
||||
let mut execute = vec![];
|
||||
let mut sync = vec![];
|
||||
frontend::sync(&mut sync);
|
||||
let r = frontend::bind(portal,
|
||||
stmt,
|
||||
Some(1),
|
||||
params.iter().zip(param_types),
|
||||
|(param, ty), buf| match param.to_sql_checked(ty, buf) {
|
||||
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
|
||||
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Some(1),
|
||||
&mut bind);
|
||||
let r = frontend::bind(
|
||||
portal,
|
||||
stmt,
|
||||
Some(1),
|
||||
params.iter().zip(param_types),
|
||||
|(param, ty), buf| match param.to_sql_checked(ty, buf) {
|
||||
Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes),
|
||||
Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Some(1),
|
||||
&mut bind,
|
||||
);
|
||||
let r = match r {
|
||||
Ok(()) => Ok(self),
|
||||
Err(frontend::BindError::Conversion(e)) => Err(Error::Conversion(e, self)),
|
||||
@ -875,11 +937,10 @@ impl Connection {
|
||||
};
|
||||
|
||||
r.and_then(|s| {
|
||||
frontend::execute(portal, 0, &mut execute)
|
||||
frontend::execute(portal, 0, &mut execute)
|
||||
.map(|()| s)
|
||||
.map_err(Error::Io)
|
||||
})
|
||||
.into_future()
|
||||
}).into_future()
|
||||
.and_then(|s| {
|
||||
let it = Some(bind)
|
||||
.into_iter()
|
||||
@ -901,43 +962,35 @@ impl Connection {
|
||||
self.0
|
||||
.read()
|
||||
.map_err(Error::Io)
|
||||
.and_then(|(m, s)| {
|
||||
match m {
|
||||
backend::Message::DataRow(_) => Connection(s).finish_execute().boxed(),
|
||||
backend::Message::CommandComplete(body) => {
|
||||
body.tag()
|
||||
.map(|tag| {
|
||||
tag.split_whitespace()
|
||||
.last()
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.map_err(Error::Io)
|
||||
.into_future()
|
||||
.and_then(|n| Connection(s).ready(n))
|
||||
.boxed()
|
||||
}
|
||||
backend::Message::EmptyQueryResponse => Connection(s).ready(0).boxed(),
|
||||
backend::Message::ErrorResponse(body) => Connection(s).ready_err(body).boxed(),
|
||||
_ => Err(bad_message()).into_future().boxed(),
|
||||
.and_then(|(m, s)| match m {
|
||||
backend::Message::DataRow(_) => Connection(s).finish_execute().boxed(),
|
||||
backend::Message::CommandComplete(body) => {
|
||||
body.tag()
|
||||
.map(|tag| {
|
||||
tag.split_whitespace().last().unwrap().parse().unwrap_or(0)
|
||||
})
|
||||
.map_err(Error::Io)
|
||||
.into_future()
|
||||
.and_then(|n| Connection(s).ready(n))
|
||||
.boxed()
|
||||
}
|
||||
backend::Message::EmptyQueryResponse => Connection(s).ready(0).boxed(),
|
||||
backend::Message::ErrorResponse(body) => Connection(s).ready_err(body).boxed(),
|
||||
_ => Err(bad_message()).into_future().boxed(),
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn read_rows(self) -> BoxStateStream<RowData, Connection, Error> {
|
||||
futures_state_stream::unfold(self, |c| {
|
||||
c.read_row()
|
||||
.and_then(|(r, c)| match r {
|
||||
Some(data) => {
|
||||
let event = StreamEvent::Next((data, c));
|
||||
Either::A(Ok(event).into_future())
|
||||
}
|
||||
None => Either::B(c.ready(()).map(|((), c)| StreamEvent::Done(c))),
|
||||
})
|
||||
c.read_row().and_then(|(r, c)| match r {
|
||||
Some(data) => {
|
||||
let event = StreamEvent::Next((data, c));
|
||||
Either::A(Ok(event).into_future())
|
||||
}
|
||||
None => Either::B(c.ready(()).map(|((), c)| StreamEvent::Done(c))),
|
||||
})
|
||||
.boxed()
|
||||
}).boxed()
|
||||
}
|
||||
|
||||
fn read_row(self) -> BoxFuture<(Option<RowData>, Connection), Error> {
|
||||
@ -948,10 +1001,12 @@ impl Connection {
|
||||
let c = Connection(s);
|
||||
match m {
|
||||
backend::Message::DataRow(body) => {
|
||||
Either::A(RowData::new(body)
|
||||
.map(|r| (Some(r), c))
|
||||
.map_err(Error::Io)
|
||||
.into_future())
|
||||
Either::A(
|
||||
RowData::new(body)
|
||||
.map(|r| (Some(r), c))
|
||||
.map_err(Error::Io)
|
||||
.into_future(),
|
||||
)
|
||||
}
|
||||
backend::Message::EmptyQueryResponse |
|
||||
backend::Message::CommandComplete(_) => Either::A(Ok((None, c)).into_future()),
|
||||
@ -981,10 +1036,11 @@ impl Connection {
|
||||
///
|
||||
/// Panics if the number of parameters provided does not match the number
|
||||
/// expected.
|
||||
pub fn execute(self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql])
|
||||
-> BoxFuture<(u64, Connection), Error> {
|
||||
pub fn execute(
|
||||
self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql],
|
||||
) -> BoxFuture<(u64, Connection), Error> {
|
||||
self.raw_execute(statement.name(), "", statement.parameters(), params)
|
||||
.and_then(|conn| conn.finish_execute())
|
||||
.boxed()
|
||||
@ -996,10 +1052,11 @@ impl Connection {
|
||||
///
|
||||
/// Panics if the number of parameters provided does not match the number
|
||||
/// expected.
|
||||
pub fn query(self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql])
|
||||
-> BoxStateStream<Row, Connection, Error> {
|
||||
pub fn query(
|
||||
self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql],
|
||||
) -> BoxStateStream<Row, Connection, Error> {
|
||||
let columns = statement.columns_arc().clone();
|
||||
self.raw_execute(statement.name(), "", statement.parameters(), params)
|
||||
.map(|c| c.read_rows().map(move |r| Row::new(columns.clone(), r)))
|
||||
@ -1077,7 +1134,8 @@ fn connect_err(fields: &mut ErrorFields) -> ConnectError {
|
||||
}
|
||||
|
||||
fn bad_message<T>() -> T
|
||||
where T: From<io::Error>
|
||||
where
|
||||
T: From<io::Error>,
|
||||
{
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "unexpected message").into()
|
||||
}
|
||||
@ -1087,11 +1145,12 @@ trait RowNew {
|
||||
}
|
||||
|
||||
trait StatementNew {
|
||||
fn new(close_sender: Sender<(u8, String)>,
|
||||
name: String,
|
||||
params: Vec<Type>,
|
||||
columns: Arc<Vec<Column>>)
|
||||
-> Statement;
|
||||
fn new(
|
||||
close_sender: Sender<(u8, String)>,
|
||||
name: String,
|
||||
params: Vec<Type>,
|
||||
columns: Arc<Vec<Column>>,
|
||||
) -> Statement;
|
||||
|
||||
fn columns_arc(&self) -> &Arc<Vec<Column>>;
|
||||
|
||||
|
@ -48,8 +48,9 @@ impl Row {
|
||||
/// Panics if the index does not reference a column or the return type is
|
||||
/// not compatible with the Postgres type.
|
||||
pub fn get<T, I>(&self, idx: I) -> T
|
||||
where T: FromSql,
|
||||
I: RowIndex + fmt::Debug
|
||||
where
|
||||
T: FromSql,
|
||||
I: RowIndex + fmt::Debug,
|
||||
{
|
||||
match self.try_get(&idx) {
|
||||
Ok(Some(v)) => v,
|
||||
@ -67,8 +68,9 @@ impl Row {
|
||||
/// if there was an error converting the result value, and `Some(Ok(..))`
|
||||
/// on success.
|
||||
pub fn try_get<T, I>(&self, idx: I) -> Result<Option<T>, Box<Error + Sync + Send>>
|
||||
where T: FromSql,
|
||||
I: RowIndex
|
||||
where
|
||||
T: FromSql,
|
||||
I: RowIndex,
|
||||
{
|
||||
let idx = match idx.idx(&self.columns) {
|
||||
Some(idx) => idx,
|
||||
|
@ -19,11 +19,12 @@ pub struct Statement {
|
||||
}
|
||||
|
||||
impl StatementNew for Statement {
|
||||
fn new(close_sender: Sender<(u8, String)>,
|
||||
name: String,
|
||||
params: Vec<Type>,
|
||||
columns: Arc<Vec<Column>>)
|
||||
-> Statement {
|
||||
fn new(
|
||||
close_sender: Sender<(u8, String)>,
|
||||
name: String,
|
||||
params: Vec<Type>,
|
||||
columns: Arc<Vec<Column>>,
|
||||
) -> Statement {
|
||||
Statement {
|
||||
close_sender: close_sender,
|
||||
name: name,
|
||||
|
@ -20,31 +20,39 @@ use tls::TlsStream;
|
||||
|
||||
pub type PostgresStream = Framed<Box<TlsStream>, PostgresCodec>;
|
||||
|
||||
pub fn connect(host: Host,
|
||||
port: u16,
|
||||
tls_mode: TlsMode,
|
||||
handle: &Handle)
|
||||
-> BoxFuture<PostgresStream, ConnectError> {
|
||||
pub fn connect(
|
||||
host: Host,
|
||||
port: u16,
|
||||
tls_mode: TlsMode,
|
||||
handle: &Handle,
|
||||
) -> BoxFuture<PostgresStream, ConnectError> {
|
||||
let inner = match host {
|
||||
Host::Tcp(ref host) => {
|
||||
Either::A(tokio_dns::tcp_connect((&**host, port), handle.remote().clone())
|
||||
.map(|s| Stream(InnerStream::Tcp(s)))
|
||||
.map_err(ConnectError::Io))
|
||||
Either::A(
|
||||
tokio_dns::tcp_connect((&**host, port), handle.remote().clone())
|
||||
.map(|s| Stream(InnerStream::Tcp(s)))
|
||||
.map_err(ConnectError::Io),
|
||||
)
|
||||
}
|
||||
#[cfg(unix)]
|
||||
Host::Unix(ref host) => {
|
||||
let addr = host.join(format!(".s.PGSQL.{}", port));
|
||||
Either::B(UnixStream::connect(addr, handle)
|
||||
.map(|s| Stream(InnerStream::Unix(s)))
|
||||
.map_err(ConnectError::Io)
|
||||
.into_future())
|
||||
Either::B(
|
||||
UnixStream::connect(addr, handle)
|
||||
.map(|s| Stream(InnerStream::Unix(s)))
|
||||
.map_err(ConnectError::Io)
|
||||
.into_future(),
|
||||
)
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
Host::Unix(_) => {
|
||||
Either::B(Err(ConnectError::ConnectParams("unix sockets are not supported on this \
|
||||
Either::B(
|
||||
Err(ConnectError::ConnectParams(
|
||||
"unix sockets are not supported on this \
|
||||
platform"
|
||||
.into()))
|
||||
.into_future())
|
||||
.into(),
|
||||
)).into_future(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
@ -52,7 +60,8 @@ pub fn connect(host: Host,
|
||||
TlsMode::Require(h) => (true, h),
|
||||
TlsMode::Prefer(h) => (false, h),
|
||||
TlsMode::None => {
|
||||
return inner.map(|s| {
|
||||
return inner
|
||||
.map(|s| {
|
||||
let s: Box<TlsStream> = Box::new(s);
|
||||
s.framed(PostgresCodec)
|
||||
})
|
||||
@ -60,29 +69,34 @@ pub fn connect(host: Host,
|
||||
}
|
||||
};
|
||||
|
||||
inner.map(|s| s.framed(SslCodec))
|
||||
inner
|
||||
.map(|s| s.framed(SslCodec))
|
||||
.and_then(|s| {
|
||||
let mut buf = vec![];
|
||||
frontend::ssl_request(&mut buf);
|
||||
s.send(buf)
|
||||
.map_err(ConnectError::Io)
|
||||
s.send(buf).map_err(ConnectError::Io)
|
||||
})
|
||||
.and_then(|s| s.into_future().map_err(|e| ConnectError::Io(e.0)))
|
||||
.and_then(move |(m, s)| {
|
||||
let s = s.into_inner();
|
||||
match (m, required) {
|
||||
(Some(b'N'), true) => {
|
||||
Either::A(Err(ConnectError::Tls("the server does not support TLS".into()))
|
||||
.into_future())
|
||||
Either::A(
|
||||
Err(ConnectError::Tls("the server does not support TLS".into()))
|
||||
.into_future(),
|
||||
)
|
||||
}
|
||||
(Some(b'N'), false) => {
|
||||
let s: Box<TlsStream> = Box::new(s);
|
||||
Either::A(Ok(s).into_future())
|
||||
}
|
||||
(None, _) => {
|
||||
Either::A(Err(ConnectError::Io(io::Error::new(io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF")))
|
||||
.into_future())
|
||||
Either::A(
|
||||
Err(ConnectError::Io(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
))).into_future(),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
let host = match host {
|
||||
@ -144,7 +158,8 @@ impl AsyncRead for Stream {
|
||||
}
|
||||
|
||||
fn read_buf<B>(&mut self, buf: &mut B) -> Poll<usize, io::Error>
|
||||
where B: BufMut
|
||||
where
|
||||
B: BufMut,
|
||||
{
|
||||
match self.0 {
|
||||
InnerStream::Tcp(ref mut s) => s.read_buf(buf),
|
||||
|
@ -14,9 +14,11 @@ use types::{ToSql, FromSql, Type, IsNull, Kind};
|
||||
fn md5_user() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://md5_user:password@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://md5_user:password@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
l.run(done).unwrap();
|
||||
}
|
||||
|
||||
@ -24,9 +26,11 @@ fn md5_user() {
|
||||
fn md5_user_no_pass() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://md5_user@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://md5_user@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
match l.run(done) {
|
||||
Err(ConnectError::ConnectParams(_)) => {}
|
||||
Err(e) => panic!("unexpected error {}", e),
|
||||
@ -38,9 +42,11 @@ fn md5_user_no_pass() {
|
||||
fn md5_user_wrong_pass() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://md5_user:foobar@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://md5_user:foobar@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
match l.run(done) {
|
||||
Err(ConnectError::Db(ref e)) if e.code == SqlState::InvalidPassword => {}
|
||||
Err(e) => panic!("unexpected error {}", e),
|
||||
@ -52,9 +58,11 @@ fn md5_user_wrong_pass() {
|
||||
fn pass_user() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://pass_user:password@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://pass_user:password@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
l.run(done).unwrap();
|
||||
}
|
||||
|
||||
@ -62,9 +70,11 @@ fn pass_user() {
|
||||
fn pass_user_no_pass() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://pass_user@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://pass_user@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
match l.run(done) {
|
||||
Err(ConnectError::ConnectParams(_)) => {}
|
||||
Err(e) => panic!("unexpected error {}", e),
|
||||
@ -76,9 +86,11 @@ fn pass_user_no_pass() {
|
||||
fn pass_user_wrong_pass() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://pass_user:foobar@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://pass_user:foobar@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
match l.run(done) {
|
||||
Err(ConnectError::Db(ref e)) if e.code == SqlState::InvalidPassword => {}
|
||||
Err(e) => panic!("unexpected error {}", e),
|
||||
@ -90,7 +102,11 @@ fn pass_user_wrong_pass() {
|
||||
fn batch_execute_ok() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &l.handle())
|
||||
.then(|c| c.unwrap().batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL);"));
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute(
|
||||
"CREATE TEMPORARY TABLE foo (id SERIAL);",
|
||||
)
|
||||
});
|
||||
l.run(done).unwrap();
|
||||
}
|
||||
|
||||
@ -99,9 +115,10 @@ fn batch_execute_err() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &l.handle())
|
||||
.then(|r| {
|
||||
r.unwrap()
|
||||
.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL); INSERT INTO foo DEFAULT \
|
||||
VALUES;")
|
||||
r.unwrap().batch_execute(
|
||||
"CREATE TEMPORARY TABLE foo (id SERIAL); INSERT INTO foo DEFAULT \
|
||||
VALUES;",
|
||||
)
|
||||
})
|
||||
.and_then(|c| c.batch_execute("SELECT * FROM bogo"))
|
||||
.then(|r| match r {
|
||||
@ -120,7 +137,9 @@ fn prepare_execute() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &l.handle())
|
||||
.then(|c| {
|
||||
c.unwrap().prepare("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, name VARCHAR)")
|
||||
c.unwrap().prepare(
|
||||
"CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, name VARCHAR)",
|
||||
)
|
||||
})
|
||||
.and_then(|(s, c)| c.execute(&s, &[]))
|
||||
.and_then(|(n, c)| {
|
||||
@ -146,8 +165,10 @@ fn query() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &l.handle())
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL, name VARCHAR);
|
||||
INSERT INTO foo (name) VALUES ('joe'), ('bob')")
|
||||
c.unwrap().batch_execute(
|
||||
"CREATE TEMPORARY TABLE foo (id SERIAL, name VARCHAR);
|
||||
INSERT INTO foo (name) VALUES ('joe'), ('bob')",
|
||||
)
|
||||
})
|
||||
.and_then(|c| c.prepare("SELECT id, name FROM foo ORDER BY id"))
|
||||
.and_then(|(s, c)| c.query(&s, &[]).collect())
|
||||
@ -166,23 +187,32 @@ fn query() {
|
||||
#[test]
|
||||
fn transaction() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let done =
|
||||
Connection::connect("postgres://postgres@localhost", TlsMode::None, &l.handle())
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL, name VARCHAR);")
|
||||
})
|
||||
.then(|c| c.unwrap().transaction())
|
||||
.then(|t| t.unwrap().batch_execute("INSERT INTO foo (name) VALUES ('joe');"))
|
||||
.then(|t| t.unwrap().rollback())
|
||||
.then(|c| c.unwrap().transaction())
|
||||
.then(|t| t.unwrap().batch_execute("INSERT INTO foo (name) VALUES ('bob');"))
|
||||
.then(|t| t.unwrap().commit())
|
||||
.then(|c| c.unwrap().prepare("SELECT name FROM foo"))
|
||||
.and_then(|(s, c)| c.query(&s, &[]).collect())
|
||||
.map(|(r, _)| {
|
||||
assert_eq!(r.len(), 1);
|
||||
assert_eq!(r[0].get::<String, _>("name"), "bob");
|
||||
});
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &l.handle())
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute(
|
||||
"CREATE TEMPORARY TABLE foo (id SERIAL, name VARCHAR);",
|
||||
)
|
||||
})
|
||||
.then(|c| c.unwrap().transaction())
|
||||
.then(|t| {
|
||||
t.unwrap().batch_execute(
|
||||
"INSERT INTO foo (name) VALUES ('joe');",
|
||||
)
|
||||
})
|
||||
.then(|t| t.unwrap().rollback())
|
||||
.then(|c| c.unwrap().transaction())
|
||||
.then(|t| {
|
||||
t.unwrap().batch_execute(
|
||||
"INSERT INTO foo (name) VALUES ('bob');",
|
||||
)
|
||||
})
|
||||
.then(|t| t.unwrap().commit())
|
||||
.then(|c| c.unwrap().prepare("SELECT name FROM foo"))
|
||||
.and_then(|(s, c)| c.query(&s, &[]).collect())
|
||||
.map(|(r, _)| {
|
||||
assert_eq!(r.len(), 1);
|
||||
assert_eq!(r[0].get::<String, _>("name"), "bob");
|
||||
});
|
||||
l.run(done).unwrap();
|
||||
}
|
||||
|
||||
@ -195,9 +225,11 @@ fn unix_socket() {
|
||||
.and_then(|(s, c)| c.query(&s, &[]).collect())
|
||||
.then(|r| {
|
||||
let r = r.unwrap().0;
|
||||
let params = ConnectParams::builder()
|
||||
.user("postgres", None)
|
||||
.build(Host::Unix(PathBuf::from(r[0].get::<String, _>(0))));
|
||||
let params = ConnectParams::builder().user("postgres", None).build(
|
||||
Host::Unix(
|
||||
PathBuf::from(r[0].get::<String, _>(0)),
|
||||
),
|
||||
);
|
||||
Connection::connect(params, TlsMode::None, &handle)
|
||||
})
|
||||
.then(|c| c.unwrap().batch_execute(""));
|
||||
@ -209,9 +241,11 @@ fn ssl_user_ssl_required() {
|
||||
let mut l = Core::new().unwrap();
|
||||
let handle = l.handle();
|
||||
|
||||
let done = Connection::connect("postgres://ssl_user@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle);
|
||||
let done = Connection::connect(
|
||||
"postgres://ssl_user@localhost/postgres",
|
||||
TlsMode::None,
|
||||
&handle,
|
||||
);
|
||||
|
||||
match l.run(done) {
|
||||
Err(ConnectError::Db(e)) => assert!(e.code == SqlState::InvalidAuthorizationSpecification),
|
||||
@ -227,14 +261,18 @@ fn openssl_required() {
|
||||
use tls::openssl::OpenSsl;
|
||||
|
||||
let mut builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
|
||||
builder.builder_mut().set_ca_file("../.travis/server.crt").unwrap();
|
||||
builder
|
||||
.builder_mut()
|
||||
.set_ca_file("../.travis/server.crt")
|
||||
.unwrap();
|
||||
let negotiator = OpenSsl::from(builder.build());
|
||||
|
||||
let mut l = Core::new().unwrap();
|
||||
let done = Connection::connect("postgres://ssl_user@localhost/postgres",
|
||||
TlsMode::Require(Box::new(negotiator)),
|
||||
&l.handle())
|
||||
.then(|c| c.unwrap().prepare("SELECT 1"))
|
||||
let done = Connection::connect(
|
||||
"postgres://ssl_user@localhost/postgres",
|
||||
TlsMode::Require(Box::new(negotiator)),
|
||||
&l.handle(),
|
||||
).then(|c| c.unwrap().prepare("SELECT 1"))
|
||||
.and_then(|(s, c)| c.query(&s, &[]).collect())
|
||||
.map(|(r, _)| assert_eq!(r[0].get::<i32, _>(0), 1));
|
||||
l.run(done).unwrap();
|
||||
@ -246,10 +284,11 @@ fn domain() {
|
||||
struct SessionId(Vec<u8>);
|
||||
|
||||
impl ToSql for SessionId {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<StdError + Sync + Send>> {
|
||||
fn to_sql(
|
||||
&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>,
|
||||
) -> Result<IsNull, Box<StdError + Sync + Send>> {
|
||||
let inner = match *ty.kind() {
|
||||
Kind::Domain(ref inner) => inner,
|
||||
_ => unreachable!(),
|
||||
@ -282,10 +321,12 @@ fn domain() {
|
||||
let handle = l.handle();
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &handle)
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute("CREATE DOMAIN pg_temp.session_id AS bytea \
|
||||
c.unwrap().batch_execute(
|
||||
"CREATE DOMAIN pg_temp.session_id AS bytea \
|
||||
CHECK(octet_length(VALUE) = 16);
|
||||
CREATE \
|
||||
TABLE pg_temp.foo (id pg_temp.session_id);")
|
||||
TABLE pg_temp.foo (id pg_temp.session_id);",
|
||||
)
|
||||
})
|
||||
.and_then(|c| c.prepare("INSERT INTO pg_temp.foo (id) VALUES ($1)"))
|
||||
.and_then(|(s, c)| {
|
||||
@ -309,11 +350,13 @@ fn composite() {
|
||||
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &handle)
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute("CREATE TYPE pg_temp.inventory_item AS (
|
||||
c.unwrap().batch_execute(
|
||||
"CREATE TYPE pg_temp.inventory_item AS (
|
||||
name TEXT,
|
||||
supplier INTEGER,
|
||||
price NUMERIC
|
||||
)")
|
||||
)",
|
||||
)
|
||||
})
|
||||
.and_then(|c| c.prepare("SELECT $1::inventory_item"))
|
||||
.map(|(s, _)| {
|
||||
@ -341,7 +384,9 @@ fn enum_() {
|
||||
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &handle)
|
||||
.then(|c| {
|
||||
c.unwrap().batch_execute("CREATE TYPE pg_temp.mood AS ENUM ('sad', 'ok', 'happy');")
|
||||
c.unwrap().batch_execute(
|
||||
"CREATE TYPE pg_temp.mood AS ENUM ('sad', 'ok', 'happy');",
|
||||
)
|
||||
})
|
||||
.and_then(|c| c.prepare("SELECT $1::mood"))
|
||||
.map(|(s, _)| {
|
||||
@ -349,8 +394,10 @@ fn enum_() {
|
||||
assert_eq!(type_.name(), "mood");
|
||||
match *type_.kind() {
|
||||
Kind::Enum(ref variants) => {
|
||||
assert_eq!(variants,
|
||||
&["sad".to_owned(), "ok".to_owned(), "happy".to_owned()]);
|
||||
assert_eq!(
|
||||
variants,
|
||||
&["sad".to_owned(), "ok".to_owned(), "happy".to_owned()]
|
||||
);
|
||||
}
|
||||
_ => panic!("bad type"),
|
||||
}
|
||||
@ -373,10 +420,12 @@ fn cancel() {
|
||||
.into_future()
|
||||
.then(move |r| {
|
||||
assert!(r.is_ok());
|
||||
cancel_query("postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
cancel_data,
|
||||
&handle)
|
||||
cancel_query(
|
||||
"postgres://postgres@localhost",
|
||||
TlsMode::None,
|
||||
cancel_data,
|
||||
&handle,
|
||||
)
|
||||
})
|
||||
.then(Ok::<_, ()>);
|
||||
c.batch_execute("SELECT pg_sleep(10)")
|
||||
@ -401,10 +450,13 @@ fn notifications() {
|
||||
let done = Connection::connect("postgres://postgres@localhost", TlsMode::None, &handle)
|
||||
.then(|c| c.unwrap().batch_execute("LISTEN test_notifications"))
|
||||
.and_then(|c1| {
|
||||
Connection::connect("postgres://postgres@localhost", TlsMode::None, &handle)
|
||||
.then(|c2| {
|
||||
c2.unwrap().batch_execute("NOTIFY test_notifications, 'foo'").map(|_| c1)
|
||||
})
|
||||
Connection::connect("postgres://postgres@localhost", TlsMode::None, &handle).then(
|
||||
|c2| {
|
||||
c2.unwrap()
|
||||
.batch_execute("NOTIFY test_notifications, 'foo'")
|
||||
.map(|_| c1)
|
||||
},
|
||||
)
|
||||
})
|
||||
.and_then(|c| c.notifications().into_future().map_err(|(e, _)| e))
|
||||
.map(|(n, _)| {
|
||||
|
@ -31,8 +31,9 @@ impl TlsStream for Stream {
|
||||
/// A trait implemented by types that can manage TLS encryption for a stream.
|
||||
pub trait Handshake: 'static + Sync + Send {
|
||||
/// Performs a TLS handshake, returning a wrapped stream.
|
||||
fn handshake(self: Box<Self>,
|
||||
host: &str,
|
||||
stream: Stream)
|
||||
-> BoxFuture<Box<TlsStream>, Box<Error + Sync + Send>>;
|
||||
fn handshake(
|
||||
self: Box<Self>,
|
||||
host: &str,
|
||||
stream: Stream,
|
||||
) -> BoxFuture<Box<TlsStream>, Box<Error + Sync + Send>>;
|
||||
}
|
||||
|
@ -38,10 +38,11 @@ impl From<SslConnector> for OpenSsl {
|
||||
}
|
||||
|
||||
impl Handshake for OpenSsl {
|
||||
fn handshake(self: Box<Self>,
|
||||
host: &str,
|
||||
stream: Stream)
|
||||
-> BoxFuture<Box<TlsStream>, Box<Error + Sync + Send>> {
|
||||
fn handshake(
|
||||
self: Box<Self>,
|
||||
host: &str,
|
||||
stream: Stream,
|
||||
) -> BoxFuture<Box<TlsStream>, Box<Error + Sync + Send>> {
|
||||
self.0
|
||||
.connect_async(host, stream)
|
||||
.map(|s| {
|
||||
|
@ -39,10 +39,11 @@ impl Transaction {
|
||||
}
|
||||
|
||||
/// Like `Connection::execute`.
|
||||
pub fn execute(self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql])
|
||||
-> BoxFuture<(u64, Transaction), Error<Transaction>> {
|
||||
pub fn execute(
|
||||
self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql],
|
||||
) -> BoxFuture<(u64, Transaction), Error<Transaction>> {
|
||||
self.0
|
||||
.execute(statement, params)
|
||||
.map(|(n, c)| (n, Transaction(c)))
|
||||
@ -51,10 +52,11 @@ impl Transaction {
|
||||
}
|
||||
|
||||
/// Like `Connection::query`.
|
||||
pub fn query(self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql])
|
||||
-> BoxStateStream<Row, Transaction, Error<Transaction>> {
|
||||
pub fn query(
|
||||
self,
|
||||
statement: &Statement,
|
||||
params: &[&ToSql],
|
||||
) -> BoxStateStream<Row, Transaction, Error<Transaction>> {
|
||||
self.0
|
||||
.query(statement, params)
|
||||
.map_state(Transaction)
|
||||
@ -73,10 +75,7 @@ impl Transaction {
|
||||
}
|
||||
|
||||
fn finish(self, query: &str) -> BoxFuture<Connection, Error> {
|
||||
self.0
|
||||
.simple_query(query)
|
||||
.map(|(_, c)| c)
|
||||
.boxed()
|
||||
self.0.simple_query(query).map(|(_, c)| c).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
//! Postgres types
|
||||
|
||||
#[doc(inline)]
|
||||
pub use postgres_shared::types::{Oid, Type, Date, Timestamp, Kind, Field, Other, WasNull, WrongType,
|
||||
FromSql, IsNull, ToSql};
|
||||
pub use postgres_shared::types::{Oid, Type, Date, Timestamp, Kind, Field, Other, WasNull,
|
||||
WrongType, FromSql, IsNull, ToSql};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use postgres_shared::types::__to_sql_checked;
|
||||
|
Loading…
Reference in New Issue
Block a user