Allow FromSql to borrow from the buffer
This allows for in-place deserialization of text and bytea values in particular. Row::get_bytes is removed since it previously existed for this use case. Closes #281
This commit is contained in:
parent
520aacab7e
commit
fcbed9175b
@ -23,7 +23,7 @@ jobs:
|
||||
build:
|
||||
working_directory: ~/build
|
||||
docker:
|
||||
- image: rust:1.21.0
|
||||
- image: rust:1.23.0
|
||||
environment:
|
||||
RUSTFLAGS: -D warnings
|
||||
- image: sfackler/rust-postgres-test:3
|
||||
|
@ -3,8 +3,6 @@ extern crate marksman_escape;
|
||||
extern crate phf_codegen;
|
||||
extern crate regex;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::path::Path;
|
||||
|
||||
mod sqlstate;
|
||||
|
@ -1,11 +1,9 @@
|
||||
use marksman_escape::Escape;
|
||||
use regex::Regex;
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::Path;
|
||||
use marksman_escape::Escape;
|
||||
|
||||
use snake_to_camel;
|
||||
|
||||
@ -178,8 +176,7 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
w,
|
||||
" {} => Some(Inner::{}),
|
||||
",
|
||||
oid,
|
||||
type_.variant
|
||||
oid, type_.variant
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@ -194,14 +191,12 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
",
|
||||
).unwrap();
|
||||
|
||||
|
||||
for (oid, type_) in types {
|
||||
write!(
|
||||
w,
|
||||
" Inner::{} => {},
|
||||
",
|
||||
type_.variant,
|
||||
oid
|
||||
type_.variant, oid
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@ -231,8 +226,7 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
V
|
||||
}}
|
||||
",
|
||||
type_.variant,
|
||||
kind
|
||||
type_.variant, kind
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
@ -252,8 +246,7 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
|
||||
w,
|
||||
r#" Inner::{} => "{}",
|
||||
"#,
|
||||
type_.variant,
|
||||
type_.name
|
||||
type_.variant, type_.name
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
use fallible_iterator::FallibleIterator;
|
||||
use postgres_protocol::message::backend::DataRowBody;
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
use std::io;
|
||||
use std::ops::Range;
|
||||
|
||||
use stmt::Column;
|
||||
use rows::sealed::Sealed;
|
||||
use stmt::Column;
|
||||
|
||||
mod sealed {
|
||||
use stmt::Column;
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate bit_vec;
|
||||
|
||||
use postgres_protocol::types;
|
||||
use self::bit_vec::BitVec;
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
|
||||
use types::{FromSql, IsNull, ToSql, Type, BIT, VARBIT};
|
||||
|
||||
impl FromSql for BitVec {
|
||||
impl<'a> FromSql<'a> for BitVec {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<BitVec, Box<Error + Sync + Send>> {
|
||||
let varbit = types::varbit_from_sql(raw)?;
|
||||
let mut bitvec = BitVec::from_bytes(varbit.bytes());
|
||||
|
@ -1,8 +1,8 @@
|
||||
extern crate chrono;
|
||||
|
||||
use postgres_protocol::types;
|
||||
use self::chrono::{DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime,
|
||||
Utc};
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
|
||||
use types::{FromSql, IsNull, ToSql, Type, DATE, TIME, TIMESTAMP, TIMESTAMPTZ};
|
||||
@ -11,7 +11,7 @@ fn base() -> NaiveDateTime {
|
||||
NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0)
|
||||
}
|
||||
|
||||
impl FromSql for NaiveDateTime {
|
||||
impl<'a> FromSql<'a> for NaiveDateTime {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDateTime, Box<Error + Sync + Send>> {
|
||||
let t = types::timestamp_from_sql(raw)?;
|
||||
Ok(base() + Duration::microseconds(t))
|
||||
@ -34,7 +34,7 @@ impl ToSql for NaiveDateTime {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for DateTime<Utc> {
|
||||
impl<'a> FromSql<'a> for DateTime<Utc> {
|
||||
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))
|
||||
@ -52,7 +52,7 @@ impl ToSql for DateTime<Utc> {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for DateTime<Local> {
|
||||
impl<'a> FromSql<'a> for DateTime<Local> {
|
||||
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))
|
||||
@ -70,7 +70,7 @@ impl ToSql for DateTime<Local> {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for DateTime<FixedOffset> {
|
||||
impl<'a> FromSql<'a> for DateTime<FixedOffset> {
|
||||
fn from_sql(
|
||||
type_: &Type,
|
||||
raw: &[u8],
|
||||
@ -91,7 +91,7 @@ impl ToSql for DateTime<FixedOffset> {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for NaiveDate {
|
||||
impl<'a> FromSql<'a> for NaiveDate {
|
||||
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))
|
||||
@ -115,7 +115,7 @@ impl ToSql for NaiveDate {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for NaiveTime {
|
||||
impl<'a> FromSql<'a> for NaiveTime {
|
||||
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))
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate eui48;
|
||||
|
||||
use self::eui48::MacAddress;
|
||||
use std::error::Error;
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
|
||||
use types::{FromSql, ToSql, Type, IsNull, MACADDR};
|
||||
use types::{FromSql, IsNull, ToSql, Type, MACADDR};
|
||||
|
||||
impl FromSql for MacAddress {
|
||||
impl<'a> FromSql<'a> for MacAddress {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<MacAddress, Box<Error + Sync + Send>> {
|
||||
let bytes = types::macaddr_from_sql(raw)?;
|
||||
Ok(MacAddress::new(bytes))
|
||||
|
@ -1,13 +1,13 @@
|
||||
extern crate geo;
|
||||
|
||||
use postgres_protocol::types;
|
||||
use self::geo::{Bbox, LineString, Point};
|
||||
use std::error::Error;
|
||||
use fallible_iterator::FallibleIterator;
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
|
||||
use types::{FromSql, ToSql, IsNull, Type, POINT, BOX, PATH};
|
||||
use types::{FromSql, IsNull, ToSql, Type, BOX, PATH, POINT};
|
||||
|
||||
impl FromSql for Point<f64> {
|
||||
impl<'a> FromSql<'a> for Point<f64> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
let point = types::point_from_sql(raw)?;
|
||||
Ok(Point::new(point.x(), point.y()))
|
||||
@ -26,7 +26,7 @@ impl ToSql for Point<f64> {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for Bbox<f64> {
|
||||
impl<'a> FromSql<'a> for Bbox<f64> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
let bbox = types::box_from_sql(raw)?;
|
||||
Ok(Bbox {
|
||||
@ -50,7 +50,7 @@ impl ToSql for Bbox<f64> {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for LineString<f64> {
|
||||
impl<'a> FromSql<'a> for LineString<f64> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
let path = types::path_from_sql(raw)?;
|
||||
let points = path.points().map(|p| Point::new(p.x(), p.y())).collect()?;
|
||||
|
@ -14,8 +14,8 @@ use types::type_gen::{Inner, Other};
|
||||
#[doc(inline)]
|
||||
pub use postgres_protocol::Oid;
|
||||
|
||||
pub use types::type_gen::consts::*;
|
||||
pub use types::special::{Date, Timestamp};
|
||||
pub use types::type_gen::consts::*;
|
||||
|
||||
/// Generates a simple implementation of `ToSql::accepts` which accepts the
|
||||
/// types passed to it.
|
||||
@ -68,20 +68,20 @@ where
|
||||
|
||||
#[cfg(feature = "with-bit-vec")]
|
||||
mod bit_vec;
|
||||
#[cfg(feature = "with-uuid")]
|
||||
mod uuid;
|
||||
#[cfg(feature = "with-time")]
|
||||
mod time;
|
||||
#[cfg(feature = "with-rustc-serialize")]
|
||||
mod rustc_serialize;
|
||||
#[cfg(feature = "with-serde_json")]
|
||||
mod serde_json;
|
||||
#[cfg(feature = "with-chrono")]
|
||||
mod chrono;
|
||||
#[cfg(feature = "with-eui48")]
|
||||
mod eui48;
|
||||
#[cfg(feature = "with-geo")]
|
||||
mod geo;
|
||||
#[cfg(feature = "with-rustc-serialize")]
|
||||
mod rustc_serialize;
|
||||
#[cfg(feature = "with-serde_json")]
|
||||
mod serde_json;
|
||||
#[cfg(feature = "with-time")]
|
||||
mod time;
|
||||
#[cfg(feature = "with-uuid")]
|
||||
mod uuid;
|
||||
|
||||
mod special;
|
||||
mod type_gen;
|
||||
@ -254,8 +254,8 @@ impl WrongType {
|
||||
/// | `i64` | BIGINT, BIGSERIAL |
|
||||
/// | `f32` | REAL |
|
||||
/// | `f64` | DOUBLE PRECISION |
|
||||
/// | `String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN |
|
||||
/// | `Vec<u8>` | BYTEA |
|
||||
/// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN |
|
||||
/// | `&[u8]`/`Vec<u8>` | BYTEA |
|
||||
/// | `HashMap<String, Option<String>>` | HSTORE |
|
||||
///
|
||||
/// In addition, some implementations are provided for types in third party
|
||||
@ -290,13 +290,13 @@ impl WrongType {
|
||||
///
|
||||
/// `FromSql` is implemented for `Vec<T>` where `T` implements `FromSql`, and
|
||||
/// corresponds to one-dimensional Postgres arrays.
|
||||
pub trait FromSql: Sized {
|
||||
pub trait FromSql<'a>: Sized {
|
||||
/// Creates a new value of this type from a buffer of data of the specified
|
||||
/// Postgres `Type` in its binary format.
|
||||
///
|
||||
/// The caller of this method is responsible for ensuring that this type
|
||||
/// is compatible with the Postgres `Type`.
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>>;
|
||||
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<Error + Sync + Send>>;
|
||||
|
||||
/// Creates a new value of this type from a `NULL` SQL value.
|
||||
///
|
||||
@ -312,7 +312,10 @@ pub trait FromSql: Sized {
|
||||
|
||||
/// A convenience function that delegates to `from_sql` and `from_sql_null` depending on the
|
||||
/// value of `raw`.
|
||||
fn from_sql_nullable(ty: &Type, raw: Option<&[u8]>) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
fn from_sql_nullable(
|
||||
ty: &Type,
|
||||
raw: Option<&'a [u8]>,
|
||||
) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
match raw {
|
||||
Some(raw) => Self::from_sql(ty, raw),
|
||||
None => Self::from_sql_null(ty),
|
||||
@ -324,8 +327,19 @@ pub trait FromSql: Sized {
|
||||
fn accepts(ty: &Type) -> bool;
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Option<T> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Option<T>, Box<Error + Sync + Send>> {
|
||||
/// A trait for types which can be created from a Postgres value without borrowing any data.
|
||||
///
|
||||
/// This is primarily useful for trait bounds on functions.
|
||||
pub trait FromSqlOwned: for<'a> FromSql<'a> {}
|
||||
|
||||
impl<T> FromSqlOwned for T
|
||||
where
|
||||
T: for<'a> FromSql<'a>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a, T: FromSql<'a>> FromSql<'a> for Option<T> {
|
||||
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Option<T>, Box<Error + Sync + Send>> {
|
||||
<T as FromSql>::from_sql(ty, raw).map(Some)
|
||||
}
|
||||
|
||||
@ -338,8 +352,8 @@ impl<T: FromSql> FromSql for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Vec<T> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Vec<T>, Box<Error + Sync + Send>> {
|
||||
impl<'a, T: FromSql<'a>> FromSql<'a> for Vec<T> {
|
||||
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Vec<T>, Box<Error + Sync + Send>> {
|
||||
let member_type = match *ty.kind() {
|
||||
Kind::Array(ref member) => member,
|
||||
_ => panic!("expected array type"),
|
||||
@ -364,19 +378,37 @@ impl<T: FromSql> FromSql for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for Vec<u8> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Vec<u8>, Box<Error + Sync + Send>> {
|
||||
impl<'a> FromSql<'a> for Vec<u8> {
|
||||
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<Vec<u8>, Box<Error + Sync + Send>> {
|
||||
Ok(types::bytea_from_sql(raw).to_owned())
|
||||
}
|
||||
|
||||
accepts!(BYTEA);
|
||||
}
|
||||
|
||||
impl FromSql for String {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<String, Box<Error + Sync + Send>> {
|
||||
impl<'a> FromSql<'a> for &'a [u8] {
|
||||
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a [u8], Box<Error + Sync + Send>> {
|
||||
Ok(types::bytea_from_sql(raw))
|
||||
}
|
||||
|
||||
accepts!(BYTEA);
|
||||
}
|
||||
|
||||
impl<'a> FromSql<'a> for String {
|
||||
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<String, Box<Error + Sync + Send>> {
|
||||
types::text_from_sql(raw).map(|b| b.to_owned())
|
||||
}
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
<&str as FromSql>::accepts(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromSql<'a> for &'a str {
|
||||
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a str, Box<Error + Sync + Send>> {
|
||||
types::text_from_sql(raw)
|
||||
}
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
match *ty {
|
||||
VARCHAR | TEXT | BPCHAR | NAME | UNKNOWN => true,
|
||||
@ -388,10 +420,8 @@ impl FromSql for String {
|
||||
|
||||
macro_rules! simple_from {
|
||||
($t:ty, $f:ident, $($expected:pat),+) => {
|
||||
impl FromSql for $t {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<$t, Box<Error + Sync + Send>> {
|
||||
impl<'a> FromSql<'a> for $t {
|
||||
fn from_sql(_: &Type, raw: &'a [u8]) -> Result<$t, Box<Error + Sync + Send>> {
|
||||
types::$f(raw)
|
||||
}
|
||||
|
||||
@ -409,10 +439,10 @@ simple_from!(i64, int8_from_sql, INT8);
|
||||
simple_from!(f32, float4_from_sql, FLOAT4);
|
||||
simple_from!(f64, float8_from_sql, FLOAT8);
|
||||
|
||||
impl FromSql for HashMap<String, Option<String>> {
|
||||
impl<'a> FromSql<'a> for HashMap<String, Option<String>> {
|
||||
fn from_sql(
|
||||
_: &Type,
|
||||
raw: &[u8],
|
||||
raw: &'a [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)))
|
||||
@ -449,10 +479,8 @@ pub enum IsNull {
|
||||
/// | `i64` | BIGINT, BIGSERIAL |
|
||||
/// | `f32` | REAL |
|
||||
/// | `f64` | DOUBLE PRECISION |
|
||||
/// | `String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME |
|
||||
/// | `&str` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME |
|
||||
/// | `Vec<u8>` | BYTEA |
|
||||
/// | `&[u8]` | BYTEA |
|
||||
/// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME |
|
||||
/// | `&[u8]`/Vec<u8>` | BYTEA |
|
||||
/// | `HashMap<String, Option<String>>` | HSTORE |
|
||||
///
|
||||
/// In addition, some implementations are provided for types in third party
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate rustc_serialize;
|
||||
|
||||
use self::rustc_serialize::json;
|
||||
use std::io::{Read, Write};
|
||||
use std::error::Error;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use types::{FromSql, IsNull, ToSql, Type, JSON, JSONB};
|
||||
|
||||
impl FromSql for json::Json {
|
||||
impl<'a> FromSql<'a> for json::Json {
|
||||
fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<json::Json, Box<Error + Sync + Send>> {
|
||||
if *ty == JSONB {
|
||||
let mut b = [0; 1];
|
||||
|
@ -6,7 +6,7 @@ use std::io::{Read, Write};
|
||||
|
||||
use types::{FromSql, IsNull, ToSql, Type, JSON, JSONB};
|
||||
|
||||
impl FromSql for Value {
|
||||
impl<'a> FromSql<'a> for Value {
|
||||
fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<Value, Box<Error + Sync + Send>> {
|
||||
if *ty == JSONB {
|
||||
let mut b = [0; 1];
|
||||
|
@ -1,8 +1,8 @@
|
||||
use postgres_protocol::types;
|
||||
use std::{i32, i64};
|
||||
use std::error::Error;
|
||||
use std::{i32, i64};
|
||||
|
||||
use types::{Type, FromSql, ToSql, IsNull, DATE, TIMESTAMP, TIMESTAMPTZ};
|
||||
use types::{FromSql, IsNull, ToSql, Type, DATE, TIMESTAMP, TIMESTAMPTZ};
|
||||
|
||||
/// A wrapper that can be used to represent infinity with `Type::Date` types.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
@ -15,8 +15,8 @@ pub enum Date<T> {
|
||||
Value(T),
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Date<T> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
impl<'a, T: FromSql<'a>> FromSql<'a> for Date<T> {
|
||||
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
match types::date_from_sql(raw)? {
|
||||
i32::MAX => Ok(Date::PosInfinity),
|
||||
i32::MIN => Ok(Date::NegInfinity),
|
||||
@ -28,6 +28,7 @@ impl<T: FromSql> FromSql for Date<T> {
|
||||
*ty == DATE && T::accepts(ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToSql> ToSql for Date<T> {
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let value = match *self {
|
||||
@ -59,8 +60,8 @@ pub enum Timestamp<T> {
|
||||
Value(T),
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Timestamp<T> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
impl<'a, T: FromSql<'a>> FromSql<'a> for Timestamp<T> {
|
||||
fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
match types::timestamp_from_sql(raw)? {
|
||||
i64::MAX => Ok(Timestamp::PosInfinity),
|
||||
i64::MIN => Ok(Timestamp::NegInfinity),
|
||||
@ -71,7 +72,7 @@ impl<T: FromSql> FromSql for Timestamp<T> {
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
match *ty {
|
||||
TIMESTAMP | TIMESTAMPTZ if T::accepts(ty) => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,7 +92,7 @@ impl<T: ToSql> ToSql for Timestamp<T> {
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
match *ty {
|
||||
TIMESTAMP | TIMESTAMPTZ if T::accepts(ty) => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
extern crate time;
|
||||
|
||||
use self::time::Timespec;
|
||||
use std::error::Error;
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
|
||||
use types::{Type, FromSql, ToSql, IsNull, TIMESTAMP, TIMESTAMPTZ};
|
||||
use types::{FromSql, IsNull, ToSql, Type, TIMESTAMP, TIMESTAMPTZ};
|
||||
|
||||
const USEC_PER_SEC: i64 = 1_000_000;
|
||||
const NSEC_PER_USEC: i64 = 1_000;
|
||||
@ -12,7 +12,7 @@ const NSEC_PER_USEC: i64 = 1_000;
|
||||
// Number of seconds from 1970-01-01 to 2000-01-01
|
||||
const TIME_SEC_CONVERSION: i64 = 946684800;
|
||||
|
||||
impl FromSql for Timespec {
|
||||
impl<'a> FromSql<'a> for Timespec {
|
||||
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;
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate uuid;
|
||||
|
||||
use postgres_protocol::types;
|
||||
use self::uuid::Uuid;
|
||||
use postgres_protocol::types;
|
||||
use std::error::Error;
|
||||
|
||||
use types::{FromSql, ToSql, Type, IsNull, UUID};
|
||||
use types::{FromSql, IsNull, ToSql, Type, UUID};
|
||||
|
||||
impl FromSql for Uuid {
|
||||
impl<'a> FromSql<'a> for Uuid {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Uuid, Box<Error + Sync + Send>> {
|
||||
let bytes = types::uuid_from_sql(raw)?;
|
||||
Ok(Uuid::from_bytes(&bytes).unwrap())
|
||||
|
@ -80,6 +80,11 @@ extern crate postgres_shared;
|
||||
extern crate socket2;
|
||||
|
||||
use fallible_iterator::FallibleIterator;
|
||||
use postgres_protocol::authentication;
|
||||
use postgres_protocol::authentication::sasl::{self, ScramSha256};
|
||||
use postgres_protocol::message::backend::{self, ErrorFields};
|
||||
use postgres_protocol::message::frontend;
|
||||
use postgres_shared::rows::RowData;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt;
|
||||
@ -88,38 +93,33 @@ use std::mem;
|
||||
use std::result;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use postgres_protocol::authentication;
|
||||
use postgres_protocol::authentication::sasl::{self, ScramSha256};
|
||||
use postgres_protocol::message::backend::{self, ErrorFields};
|
||||
use postgres_protocol::message::frontend;
|
||||
use postgres_shared::rows::RowData;
|
||||
|
||||
use error::{DbError, UNDEFINED_COLUMN, UNDEFINED_TABLE};
|
||||
use tls::TlsHandshake;
|
||||
use notification::{Notification, Notifications};
|
||||
use params::{IntoConnectParams, User};
|
||||
use priv_io::MessageStream;
|
||||
use rows::Rows;
|
||||
use stmt::{Column, Statement};
|
||||
use tls::TlsHandshake;
|
||||
use transaction::{IsolationLevel, Transaction};
|
||||
use types::{Field, FromSql, IsNull, Kind, Oid, ToSql, Type, CHAR, NAME, OID};
|
||||
|
||||
#[doc(inline)]
|
||||
pub use error::Error;
|
||||
#[doc(inline)]
|
||||
pub use postgres_shared::CancelData;
|
||||
#[doc(inline)]
|
||||
pub use postgres_shared::{error, types};
|
||||
#[doc(inline)]
|
||||
pub use error::Error;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
mod priv_io;
|
||||
pub mod tls;
|
||||
pub mod notification;
|
||||
pub mod params;
|
||||
mod priv_io;
|
||||
pub mod rows;
|
||||
pub mod stmt;
|
||||
pub mod tls;
|
||||
pub mod transaction;
|
||||
|
||||
const TYPEINFO_QUERY: &'static str = "__typeinfo";
|
||||
|
@ -13,11 +13,11 @@ use std::sync::Arc;
|
||||
#[doc(inline)]
|
||||
pub use postgres_shared::rows::RowIndex;
|
||||
|
||||
use {Error, Result, StatementInfo};
|
||||
use error;
|
||||
use stmt::{Column, Statement};
|
||||
use transaction::Transaction;
|
||||
use types::{FromSql, WrongType};
|
||||
use stmt::{Statement, Column};
|
||||
use {Error, Result, StatementInfo};
|
||||
|
||||
enum MaybeOwned<'a, T: 'a> {
|
||||
Borrowed(&'a T),
|
||||
@ -113,11 +113,9 @@ impl<'a> Iterator for Iter<'a> {
|
||||
type Item = Row<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Row<'a>> {
|
||||
self.iter.next().map(|row| {
|
||||
Row {
|
||||
stmt_info: self.stmt_info,
|
||||
data: MaybeOwned::Borrowed(row),
|
||||
}
|
||||
self.iter.next().map(|row| Row {
|
||||
stmt_info: self.stmt_info,
|
||||
data: MaybeOwned::Borrowed(row),
|
||||
})
|
||||
}
|
||||
|
||||
@ -128,11 +126,9 @@ impl<'a> Iterator for Iter<'a> {
|
||||
|
||||
impl<'a> DoubleEndedIterator for Iter<'a> {
|
||||
fn next_back(&mut self) -> Option<Row<'a>> {
|
||||
self.iter.next_back().map(|row| {
|
||||
Row {
|
||||
stmt_info: self.stmt_info,
|
||||
data: MaybeOwned::Borrowed(row),
|
||||
}
|
||||
self.iter.next_back().map(|row| Row {
|
||||
stmt_info: self.stmt_info,
|
||||
data: MaybeOwned::Borrowed(row),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -191,10 +187,10 @@ impl<'a> Row<'a> {
|
||||
/// println!("{}: {}", foo, bar);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get<I, T>(&self, idx: I) -> T
|
||||
pub fn get<'b, I, T>(&'b self, idx: I) -> T
|
||||
where
|
||||
I: RowIndex + fmt::Debug,
|
||||
T: FromSql,
|
||||
T: FromSql<'b>,
|
||||
{
|
||||
match self.get_inner(&idx) {
|
||||
Some(Ok(ok)) => ok,
|
||||
@ -211,18 +207,18 @@ impl<'a> Row<'a> {
|
||||
/// Returns `None` if the index does not reference a column, `Some(Err(..))`
|
||||
/// 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>>
|
||||
pub fn get_opt<'b, I, T>(&'b self, idx: I) -> Option<Result<T>>
|
||||
where
|
||||
I: RowIndex,
|
||||
T: FromSql,
|
||||
T: FromSql<'b>,
|
||||
{
|
||||
self.get_inner(&idx)
|
||||
}
|
||||
|
||||
fn get_inner<I, T>(&self, idx: &I) -> Option<Result<T>>
|
||||
fn get_inner<'b, I, T>(&'b self, idx: &I) -> Option<Result<T>>
|
||||
where
|
||||
I: RowIndex,
|
||||
T: FromSql,
|
||||
T: FromSql<'b>,
|
||||
{
|
||||
let idx = match idx.__idx(&self.stmt_info.columns) {
|
||||
Some(idx) => idx,
|
||||
@ -236,21 +232,6 @@ impl<'a> Row<'a> {
|
||||
let value = FromSql::from_sql_nullable(ty, self.data.get(idx));
|
||||
Some(value.map_err(error::conversion))
|
||||
}
|
||||
|
||||
/// Retrieves the specified field as a raw buffer of Postgres data.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the index does not reference a column.
|
||||
pub fn get_bytes<I>(&self, idx: I) -> Option<&[u8]>
|
||||
where
|
||||
I: RowIndex + fmt::Debug,
|
||||
{
|
||||
match idx.__idx(&self.stmt_info.columns) {
|
||||
Some(idx) => self.data.get(idx),
|
||||
None => panic!("invalid index {:?}", idx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A lazily-loaded iterator over the resulting rows of a query.
|
||||
@ -313,18 +294,13 @@ 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`.
|
||||
@ -350,11 +326,9 @@ 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)
|
||||
|
@ -2,13 +2,11 @@
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
#[allow(unused_imports)]
|
||||
use std::ascii::AsciiExt;
|
||||
|
||||
use {bad_response, Connection, Result};
|
||||
use rows::Rows;
|
||||
use stmt::Statement;
|
||||
use types::ToSql;
|
||||
use {bad_response, Connection, Result};
|
||||
|
||||
/// An enumeration of transaction isolation levels.
|
||||
///
|
||||
|
@ -1320,20 +1320,6 @@ fn test_parameter() {
|
||||
assert_eq!(None, conn.parameter("asdf"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_bytes() {
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost:5433",
|
||||
TlsMode::None,
|
||||
));
|
||||
let stmt = or_panic!(conn.prepare("SELECT '\\x00010203'::BYTEA"));
|
||||
let result = or_panic!(stmt.query(&[]));
|
||||
assert_eq!(
|
||||
b"\x00\x01\x02\x03",
|
||||
result.iter().next().unwrap().get_bytes(0).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn url_unencoded_password() {
|
||||
assert!(
|
||||
|
@ -5,38 +5,47 @@ use std::f64;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
|
||||
use postgres::types::{FromSql, FromSqlOwned, INT4, IsNull, Kind, ToSql, Type, WrongType, NUMERIC,
|
||||
TEXT};
|
||||
use postgres::{Connection, TlsMode};
|
||||
use postgres::types::{ToSql, FromSql, WrongType, Type, IsNull, Kind, TEXT, INT4, NUMERIC};
|
||||
|
||||
#[cfg(feature = "with-bit-vec")]
|
||||
mod bit_vec;
|
||||
#[cfg(feature = "with-chrono")]
|
||||
mod chrono;
|
||||
#[cfg(feature = "with-eui48")]
|
||||
mod eui48;
|
||||
#[cfg(feature = "with-uuid")]
|
||||
mod uuid;
|
||||
#[cfg(feature = "with-time")]
|
||||
mod time;
|
||||
#[cfg(feature = "with-geo")]
|
||||
mod geo;
|
||||
#[cfg(feature = "with-rustc-serialize")]
|
||||
mod rustc_serialize;
|
||||
#[cfg(feature = "with-serde_json")]
|
||||
mod serde_json;
|
||||
#[cfg(feature = "with-chrono")]
|
||||
mod chrono;
|
||||
#[cfg(feature = "with-geo")]
|
||||
mod geo;
|
||||
#[cfg(feature = "with-time")]
|
||||
mod time;
|
||||
#[cfg(feature = "with-uuid")]
|
||||
mod uuid;
|
||||
|
||||
fn test_type<T: PartialEq + FromSql + ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
|
||||
fn test_type<T, S>(sql_type: &str, checks: &[(T, S)])
|
||||
where
|
||||
T: PartialEq + for<'a> FromSqlOwned + ToSql,
|
||||
S: fmt::Display,
|
||||
{
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost:5433",
|
||||
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);
|
||||
let rows = or_panic!(stmt.query(&[]));
|
||||
let row = rows.iter().next().unwrap();
|
||||
let result = row.get(0);
|
||||
assert_eq!(val, &result);
|
||||
|
||||
let stmt = or_panic!(conn.prepare(&*format!("SELECT $1::{}", sql_type)));
|
||||
let result = or_panic!(stmt.query(&[val])).iter().next().unwrap().get(0);
|
||||
let rows = or_panic!(stmt.query(&[val]));
|
||||
let row = rows.iter().next().unwrap();
|
||||
let result = row.get(0);
|
||||
assert_eq!(val, &result);
|
||||
}
|
||||
}
|
||||
@ -184,6 +193,19 @@ fn test_text_params() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrowed_text() {
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost:5433",
|
||||
TlsMode::None,
|
||||
));
|
||||
|
||||
let rows = or_panic!(conn.query("SELECT 'foo'", &[]));
|
||||
let row = rows.get(0);
|
||||
let s: &str = row.get(0);
|
||||
assert_eq!(s, "foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bpchar_params() {
|
||||
let conn = or_panic!(Connection::connect(
|
||||
@ -225,15 +247,9 @@ fn test_citext_params() {
|
||||
));
|
||||
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",
|
||||
&[&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!(
|
||||
@ -253,6 +269,19 @@ fn test_bytea_params() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrowed_bytea() {
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost:5433",
|
||||
TlsMode::None,
|
||||
));
|
||||
|
||||
let rows = or_panic!(conn.query("SELECT 'foo'::BYTEA", &[]));
|
||||
let row = rows.get(0);
|
||||
let s: &[u8] = row.get(0);
|
||||
assert_eq!(s, b"foo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hstore_params() {
|
||||
macro_rules! make_map {
|
||||
@ -293,7 +322,10 @@ fn test_array_params() {
|
||||
);
|
||||
}
|
||||
|
||||
fn test_nan_param<T: PartialEq + ToSql + FromSql>(sql_type: &str) {
|
||||
fn test_nan_param<T>(sql_type: &str)
|
||||
where
|
||||
T: PartialEq + ToSql + FromSqlOwned,
|
||||
{
|
||||
let conn = or_panic!(Connection::connect(
|
||||
"postgres://postgres@localhost:5433",
|
||||
TlsMode::None,
|
||||
@ -394,17 +426,16 @@ fn domain() {
|
||||
}
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
ty.name() == "session_id" &&
|
||||
match *ty.kind() {
|
||||
Kind::Domain(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
ty.name() == "session_id" && match *ty.kind() {
|
||||
Kind::Domain(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for SessionId {
|
||||
impl<'a> FromSql<'a> for SessionId {
|
||||
fn from_sql(
|
||||
ty: &Type,
|
||||
raw: &[u8],
|
||||
|
@ -9,7 +9,7 @@ use std::sync::Arc;
|
||||
#[doc(inline)]
|
||||
pub use postgres_shared::rows::RowIndex;
|
||||
|
||||
use types::{WrongType, FromSql};
|
||||
use types::{FromSql, WrongType};
|
||||
|
||||
/// A row from Postgres.
|
||||
pub struct Row {
|
||||
@ -44,9 +44,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
|
||||
pub fn get<'a, T, I>(&'a self, idx: I) -> T
|
||||
where
|
||||
T: FromSql,
|
||||
T: FromSql<'a>,
|
||||
I: RowIndex + fmt::Debug,
|
||||
{
|
||||
match self.try_get(&idx) {
|
||||
@ -64,9 +64,9 @@ impl Row {
|
||||
/// Returns `None` if the index does not reference a column, `Some(Err(..))`
|
||||
/// 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>>
|
||||
pub fn try_get<'a, T, I>(&'a self, idx: I) -> Result<Option<T>, Box<Error + Sync + Send>>
|
||||
where
|
||||
T: FromSql,
|
||||
T: FromSql<'a>,
|
||||
I: RowIndex,
|
||||
{
|
||||
let idx = match idx.__idx(&self.columns) {
|
||||
|
@ -313,7 +313,7 @@ fn domain() {
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for SessionId {
|
||||
impl<'a> FromSql<'a> for SessionId {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<StdError + Sync + Send>> {
|
||||
Vec::<u8>::from_sql(ty, raw).map(SessionId)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user