diff --git a/.circleci/config.yml b/.circleci/config.yml index 26b5cf27..dab9ec28 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/codegen/src/main.rs b/codegen/src/main.rs index bd1cdd73..9aa9a974 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -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; diff --git a/codegen/src/type_gen.rs b/codegen/src/type_gen.rs index 81b356b3..645dc493 100644 --- a/codegen/src/type_gen.rs +++ b/codegen/src/type_gen.rs @@ -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, types: &BTreeMap) { w, " {} => Some(Inner::{}), ", - oid, - type_.variant + oid, type_.variant ).unwrap(); } @@ -194,14 +191,12 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { ", ).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, types: &BTreeMap) { V }} ", - type_.variant, - kind + type_.variant, kind ).unwrap(); } @@ -252,8 +246,7 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { w, r#" Inner::{} => "{}", "#, - type_.variant, - type_.name + type_.variant, type_.name ).unwrap(); } diff --git a/postgres-shared/src/rows.rs b/postgres-shared/src/rows.rs index f6b1e47f..48de5360 100644 --- a/postgres-shared/src/rows.rs +++ b/postgres-shared/src/rows.rs @@ -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; diff --git a/postgres-shared/src/types/bit_vec.rs b/postgres-shared/src/types/bit_vec.rs index 6bbbe836..2b067496 100644 --- a/postgres-shared/src/types/bit_vec.rs +++ b/postgres-shared/src/types/bit_vec.rs @@ -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> { let varbit = types::varbit_from_sql(raw)?; let mut bitvec = BitVec::from_bytes(varbit.bytes()); diff --git a/postgres-shared/src/types/chrono.rs b/postgres-shared/src/types/chrono.rs index fd55eb89..a0fc4d63 100644 --- a/postgres-shared/src/types/chrono.rs +++ b/postgres-shared/src/types/chrono.rs @@ -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> { 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 { +impl<'a> FromSql<'a> for DateTime { fn from_sql(type_: &Type, raw: &[u8]) -> Result, Box> { let naive = NaiveDateTime::from_sql(type_, raw)?; Ok(DateTime::from_utc(naive, Utc)) @@ -52,7 +52,7 @@ impl ToSql for DateTime { to_sql_checked!(); } -impl FromSql for DateTime { +impl<'a> FromSql<'a> for DateTime { fn from_sql(type_: &Type, raw: &[u8]) -> Result, Box> { let utc = DateTime::::from_sql(type_, raw)?; Ok(utc.with_timezone(&Local)) @@ -70,7 +70,7 @@ impl ToSql for DateTime { to_sql_checked!(); } -impl FromSql for DateTime { +impl<'a> FromSql<'a> for DateTime { fn from_sql( type_: &Type, raw: &[u8], @@ -91,7 +91,7 @@ impl ToSql for DateTime { to_sql_checked!(); } -impl FromSql for NaiveDate { +impl<'a> FromSql<'a> for NaiveDate { fn from_sql(_: &Type, raw: &[u8]) -> Result> { 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> { let usec = types::time_from_sql(raw)?; Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec)) diff --git a/postgres-shared/src/types/eui48.rs b/postgres-shared/src/types/eui48.rs index 1ccbe689..59944db2 100644 --- a/postgres-shared/src/types/eui48.rs +++ b/postgres-shared/src/types/eui48.rs @@ -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> { let bytes = types::macaddr_from_sql(raw)?; Ok(MacAddress::new(bytes)) diff --git a/postgres-shared/src/types/geo.rs b/postgres-shared/src/types/geo.rs index de5353cc..396bb791 100644 --- a/postgres-shared/src/types/geo.rs +++ b/postgres-shared/src/types/geo.rs @@ -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 { +impl<'a> FromSql<'a> for Point { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let point = types::point_from_sql(raw)?; Ok(Point::new(point.x(), point.y())) @@ -26,7 +26,7 @@ impl ToSql for Point { to_sql_checked!(); } -impl FromSql for Bbox { +impl<'a> FromSql<'a> for Bbox { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let bbox = types::box_from_sql(raw)?; Ok(Bbox { @@ -50,7 +50,7 @@ impl ToSql for Bbox { to_sql_checked!(); } -impl FromSql for LineString { +impl<'a> FromSql<'a> for LineString { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let path = types::path_from_sql(raw)?; let points = path.points().map(|p| Point::new(p.x(), p.y())).collect()?; diff --git a/postgres-shared/src/types/mod.rs b/postgres-shared/src/types/mod.rs index 6917dd1c..94651813 100644 --- a/postgres-shared/src/types/mod.rs +++ b/postgres-shared/src/types/mod.rs @@ -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` | BYTEA | +/// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN | +/// | `&[u8]`/`Vec` | BYTEA | /// | `HashMap>` | HSTORE | /// /// In addition, some implementations are provided for types in third party @@ -290,13 +290,13 @@ impl WrongType { /// /// `FromSql` is implemented for `Vec` 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>; + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result>; /// 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> { + fn from_sql_nullable( + ty: &Type, + raw: Option<&'a [u8]>, + ) -> Result> { 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 FromSql for Option { - fn from_sql(ty: &Type, raw: &[u8]) -> Result, Box> { +/// 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 FromSqlOwned for T +where + T: for<'a> FromSql<'a>, +{ +} + +impl<'a, T: FromSql<'a>> FromSql<'a> for Option { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result, Box> { ::from_sql(ty, raw).map(Some) } @@ -338,8 +352,8 @@ impl FromSql for Option { } } -impl FromSql for Vec { - fn from_sql(ty: &Type, raw: &[u8]) -> Result, Box> { +impl<'a, T: FromSql<'a>> FromSql<'a> for Vec { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result, Box> { let member_type = match *ty.kind() { Kind::Array(ref member) => member, _ => panic!("expected array type"), @@ -364,19 +378,37 @@ impl FromSql for Vec { } } -impl FromSql for Vec { - fn from_sql(_: &Type, raw: &[u8]) -> Result, Box> { +impl<'a> FromSql<'a> for Vec { + fn from_sql(_: &Type, raw: &'a [u8]) -> Result, Box> { Ok(types::bytea_from_sql(raw).to_owned()) } accepts!(BYTEA); } -impl FromSql for String { - fn from_sql(_: &Type, raw: &[u8]) -> Result> { +impl<'a> FromSql<'a> for &'a [u8] { + fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a [u8], Box> { + Ok(types::bytea_from_sql(raw)) + } + + accepts!(BYTEA); +} + +impl<'a> FromSql<'a> for String { + fn from_sql(_: &Type, raw: &'a [u8]) -> Result> { 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> { + 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> { + impl<'a> FromSql<'a> for $t { + fn from_sql(_: &Type, raw: &'a [u8]) -> Result<$t, Box> { 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> { +impl<'a> FromSql<'a> for HashMap> { fn from_sql( _: &Type, - raw: &[u8], + raw: &'a [u8], ) -> Result>, Box> { 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` | BYTEA | -/// | `&[u8]` | BYTEA | +/// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME | +/// | `&[u8]`/Vec` | BYTEA | /// | `HashMap>` | HSTORE | /// /// In addition, some implementations are provided for types in third party diff --git a/postgres-shared/src/types/rustc_serialize.rs b/postgres-shared/src/types/rustc_serialize.rs index f8dedc91..c47ecfb0 100644 --- a/postgres-shared/src/types/rustc_serialize.rs +++ b/postgres-shared/src/types/rustc_serialize.rs @@ -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> { if *ty == JSONB { let mut b = [0; 1]; diff --git a/postgres-shared/src/types/serde_json.rs b/postgres-shared/src/types/serde_json.rs index 842dd305..8e0bd770 100644 --- a/postgres-shared/src/types/serde_json.rs +++ b/postgres-shared/src/types/serde_json.rs @@ -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> { if *ty == JSONB { let mut b = [0; 1]; diff --git a/postgres-shared/src/types/special.rs b/postgres-shared/src/types/special.rs index a7e14de9..5658a551 100644 --- a/postgres-shared/src/types/special.rs +++ b/postgres-shared/src/types/special.rs @@ -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 { Value(T), } -impl FromSql for Date { - fn from_sql(ty: &Type, raw: &[u8]) -> Result> { +impl<'a, T: FromSql<'a>> FromSql<'a> for Date { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { match types::date_from_sql(raw)? { i32::MAX => Ok(Date::PosInfinity), i32::MIN => Ok(Date::NegInfinity), @@ -28,6 +28,7 @@ impl FromSql for Date { *ty == DATE && T::accepts(ty) } } + impl ToSql for Date { fn to_sql(&self, ty: &Type, out: &mut Vec) -> Result> { let value = match *self { @@ -59,8 +60,8 @@ pub enum Timestamp { Value(T), } -impl FromSql for Timestamp { - fn from_sql(ty: &Type, raw: &[u8]) -> Result> { +impl<'a, T: FromSql<'a>> FromSql<'a> for Timestamp { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { match types::timestamp_from_sql(raw)? { i64::MAX => Ok(Timestamp::PosInfinity), i64::MIN => Ok(Timestamp::NegInfinity), @@ -71,7 +72,7 @@ impl FromSql for Timestamp { fn accepts(ty: &Type) -> bool { match *ty { TIMESTAMP | TIMESTAMPTZ if T::accepts(ty) => true, - _ => false + _ => false, } } } @@ -91,7 +92,7 @@ impl ToSql for Timestamp { fn accepts(ty: &Type) -> bool { match *ty { TIMESTAMP | TIMESTAMPTZ if T::accepts(ty) => true, - _ => false + _ => false, } } diff --git a/postgres-shared/src/types/time.rs b/postgres-shared/src/types/time.rs index e6b43043..e827953d 100644 --- a/postgres-shared/src/types/time.rs +++ b/postgres-shared/src/types/time.rs @@ -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> { let t = types::timestamp_from_sql(raw)?; let mut sec = t / USEC_PER_SEC + TIME_SEC_CONVERSION; diff --git a/postgres-shared/src/types/uuid.rs b/postgres-shared/src/types/uuid.rs index 822f85b0..7cba9161 100644 --- a/postgres-shared/src/types/uuid.rs +++ b/postgres-shared/src/types/uuid.rs @@ -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> { let bytes = types::uuid_from_sql(raw)?; Ok(Uuid::from_bytes(&bytes).unwrap()) diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index 6ef2a687..4a001262 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -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"; diff --git a/postgres/src/rows.rs b/postgres/src/rows.rs index 1b0fc27c..25b006fd 100644 --- a/postgres/src/rows.rs +++ b/postgres/src/rows.rs @@ -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> { - 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> { - 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(&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(&self, idx: I) -> Option> + pub fn get_opt<'b, I, T>(&'b self, idx: I) -> Option> where I: RowIndex, - T: FromSql, + T: FromSql<'b>, { self.get_inner(&idx) } - fn get_inner(&self, idx: &I) -> Option> + fn get_inner<'b, I, T>(&'b self, idx: &I) -> Option> 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(&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) diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index e1c8ab17..e1611b9b 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -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. /// diff --git a/postgres/tests/test.rs b/postgres/tests/test.rs index 9cfd5802..ba12c495 100644 --- a/postgres/tests/test.rs +++ b/postgres/tests/test.rs @@ -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!( diff --git a/postgres/tests/types/mod.rs b/postgres/tests/types/mod.rs index 495dc3f5..1aad85cd 100644 --- a/postgres/tests/types/mod.rs +++ b/postgres/tests/types/mod.rs @@ -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(sql_type: &str, checks: &[(T, S)]) { +fn test_type(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(sql_type: &str) { +fn test_nan_param(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], diff --git a/tokio-postgres/src/rows.rs b/tokio-postgres/src/rows.rs index 482f7cc1..6b996fbf 100644 --- a/tokio-postgres/src/rows.rs +++ b/tokio-postgres/src/rows.rs @@ -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(&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(&self, idx: I) -> Result, Box> + pub fn try_get<'a, T, I>(&'a self, idx: I) -> Result, Box> where - T: FromSql, + T: FromSql<'a>, I: RowIndex, { let idx = match idx.__idx(&self.columns) { diff --git a/tokio-postgres/src/test.rs b/tokio-postgres/src/test.rs index 69c57c1d..6130a90c 100644 --- a/tokio-postgres/src/test.rs +++ b/tokio-postgres/src/test.rs @@ -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> { Vec::::from_sql(ty, raw).map(SessionId) }