From 1b20a38bd9a9225f1f9657810de3886f0b990861 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 20 Jul 2015 23:11:40 -0700 Subject: [PATCH 1/6] Implement ToSql and FromSql for DateTime<{Local,FixedOffset}> --- src/types/chrono.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/types/chrono.rs b/src/types/chrono.rs index 159bbdec..1e724987 100644 --- a/src/types/chrono.rs +++ b/src/types/chrono.rs @@ -3,7 +3,7 @@ extern crate chrono; use std::error; use std::io::prelude::*; use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; -use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC}; +use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, UTC, Local, FixedOffset}; use Result; use error::Error; @@ -52,6 +52,45 @@ impl ToSql for DateTime { to_sql_checked!(); } +impl FromSql for DateTime { + fn from_sql(type_: &Type, raw: &mut R, info: &SessionInfo) -> Result> { + let utc = try!(DateTime::::from_sql(type_, raw, info)); + Ok(utc.with_timezone(&Local)) + } + + accepts!(Type::TimestampTZ); +} + +impl ToSql for DateTime { + fn to_sql(&self, type_: &Type, mut w: &mut W, info: &SessionInfo) + -> Result { + self.with_timezone(&UTC).to_sql(type_, w, info) + } + + accepts!(Type::TimestampTZ); + to_sql_checked!(); +} + +impl FromSql for DateTime { + fn from_sql(type_: &Type, raw: &mut R, info: &SessionInfo) + -> Result> { + let utc = try!(DateTime::::from_sql(type_, raw, info)); + Ok(utc.with_timezone(&FixedOffset::east(0))) + } + + accepts!(Type::TimestampTZ); +} + +impl ToSql for DateTime { + fn to_sql(&self, type_: &Type, mut w: &mut W, info: &SessionInfo) + -> Result { + self.with_timezone(&UTC).to_sql(type_, w, info) + } + + accepts!(Type::TimestampTZ); + to_sql_checked!(); +} + impl FromSql for NaiveDate { fn from_sql(_: &Type, raw: &mut R, _: &SessionInfo) -> Result { let jd = try!(raw.read_i32::()); From edc6f721a57edc25894cadac1f3f3c2715f69189 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 20 Jul 2015 23:16:50 -0700 Subject: [PATCH 2/6] Add docs for new impls --- README.md | 6 ++++-- src/types/mod.rs | 44 ++++++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8fc28b56..43df485a 100644 --- a/README.md +++ b/README.md @@ -216,9 +216,11 @@ types. The driver currently supports the following conversions: - time::Timespec + time::Timespec, + chrono::DateTime<UTC>, + chrono::DateTime<Local>, and - chrono::DateTime<UTC> + chrono::DateTime<FixedOffset> (optional) TIMESTAMP WITH TIME ZONE diff --git a/src/types/mod.rs b/src/types/mod.rs index 2eab704a..6b398406 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -565,16 +565,18 @@ impl error::Error for WasNull { /// name. For example, the `serde` feature enables the implementation for the /// `serde::json::Value` type. /// -/// | Rust type | Postgres type(s) | -/// |-----------------------------|-------------------------------------| -/// | serialize::json::Json | JSON, JSONB | -/// | serde::json::Value | JSON, JSONB | -/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE | -/// | chrono::NaiveDateTime | TIMESTAMP | -/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE | -/// | chrono::NaiveDate | DATE | -/// | chrono::NaiveTime | TIME | -/// | uuid::Uuid | UUID | +/// | Rust type | Postgres type(s) | +/// |-------------------------------------|-------------------------------------| +/// | serialize::json::Json | JSON, JSONB | +/// | serde::json::Value | JSON, JSONB | +/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE | +/// | chrono::NaiveDateTime | TIMESTAMP | +/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE | +/// | chrono::DateTime<Local> | TIMESTAMP WITH TIME ZONE | +/// | chrono::DateTime<FixedOffset> | TIMESTAMP WITH TIME ZONE | +/// | chrono::NaiveDate | DATE | +/// | chrono::NaiveTime | TIME | +/// | uuid::Uuid | UUID | /// /// # Nullability /// @@ -770,16 +772,18 @@ pub enum IsNull { /// name. For example, the `serde` feature enables the implementation for the /// `serde::json::Value` type. /// -/// | Rust type | Postgres type(s) | -/// |-----------------------------|-------------------------------------| -/// | serialize::json::Json | JSON, JSONB | -/// | serde::json::Value | JSON, JSONB | -/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE | -/// | chrono::NaiveDateTime | TIMESTAMP | -/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE | -/// | chrono::NaiveDate | DATE | -/// | chrono::NaiveTime | TIME | -/// | uuid::Uuid | UUID | +/// | Rust type | Postgres type(s) | +/// |-------------------------------------|-------------------------------------| +/// | serialize::json::Json | JSON, JSONB | +/// | serde::json::Value | JSON, JSONB | +/// | time::Timespec | TIMESTAMP, TIMESTAMP WITH TIME ZONE | +/// | chrono::NaiveDateTime | TIMESTAMP | +/// | chrono::DateTime<UTC> | TIMESTAMP WITH TIME ZONE | +/// | chrono::DateTime<Local> | TIMESTAMP WITH TIME ZONE | +/// | chrono::DateTime<FixedOffset> | TIMESTAMP WITH TIME ZONE | +/// | chrono::NaiveDate | DATE | +/// | chrono::NaiveTime | TIME | +/// | uuid::Uuid | UUID | /// /// # Nullability /// From a60dc808ba2c764cf97b417a649950d59750b98a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 22 Jul 2015 07:41:40 -0700 Subject: [PATCH 3/6] Ensure Connection is always Send --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 65340e2e..e9dee9ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -864,6 +864,11 @@ impl InnerConnection { } } +fn _ensure_send() { + fn _is_send() {} + _is_send::(); +} + /// A connection to a Postgres database. pub struct Connection { conn: RefCell From cb6a408c139d3e4a061e777f4e5f0569f78600d2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 30 Jul 2015 21:24:59 -0700 Subject: [PATCH 4/6] Specify sudo is required for travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 027019a7..0e2e52d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: rust +sudo: required rust: - nightly - beta From 64de6abb1e17eae31c9972b649e01145b9f98c18 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 30 Jul 2015 22:04:22 -0700 Subject: [PATCH 5/6] Look up column names case insensitively It tries a case sensitive comparison first so all existing uses should continue to be OK. It should really have some form of unicode awarenes but it's unclear exactly what. The JDBC driver uses the US locale when lowercasing and libpq uses tolower with the system locale. Closes #136 --- src/rows.rs | 10 +++++++++- tests/test.rs | 13 +++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/rows.rs b/src/rows.rs index 1728ff4c..1d695d68 100644 --- a/src/rows.rs +++ b/src/rows.rs @@ -1,5 +1,6 @@ //! Query result rows. +use std::ascii::AsciiExt; use std::fmt; use std::collections::VecDeque; use debug_builders::DebugStruct; @@ -274,7 +275,14 @@ impl RowIndex for usize { impl<'a> RowIndex for &'a str { #[inline] fn idx(&self, stmt: &Statement) -> Option { - stmt.columns().iter().position(|d| d.name == *self) + if let Some(idx) = stmt.columns().iter().position(|d| d.name == *self) { + return Some(idx); + }; + + // 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.columns().iter().position(|d| d.name.eq_ignore_ascii_case(*self)) } } diff --git a/tests/test.rs b/tests/test.rs index f14ae4b8..809bcbaa 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -25,6 +25,7 @@ use postgres::error::SqlState::{SyntaxError, InvalidPassword, CardinalityViolation}; use postgres::error::ErrorPosition::Normal; +use postgres::rows::RowIndex; macro_rules! or_panic { ($e:expr) => ( @@ -886,3 +887,15 @@ fn test_rows_index() { assert_eq!(3, rows.len()); assert_eq!(2i32, rows.get(1).get(0)); } + +#[test] +fn test_row_case_insensitive() { + let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap(); + conn.batch_execute("CREATE TEMPORARY TABLE foo (foo INT, \"bAr\" INT, \"Bar\" INT);").unwrap(); + let stmt = conn.prepare("SELECT * FROM foo").unwrap(); + assert_eq!(Some(0), "foo".idx(&stmt)); + assert_eq!(Some(0), "FOO".idx(&stmt)); + assert_eq!(Some(1), "bar".idx(&stmt)); + assert_eq!(Some(1), "bAr".idx(&stmt)); + assert_eq!(Some(2), "Bar".idx(&stmt)); +} From b3e596b3c8dc0e4a7c7fdd37c4547b712fa7dcf8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 30 Jul 2015 22:44:52 -0700 Subject: [PATCH 6/6] Release v0.9.4 --- Cargo.toml | 4 ++-- README.md | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index baf3ffbe..14f471a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "postgres" -version = "0.9.3" +version = "0.9.4" authors = ["Steven Fackler "] license = "MIT" description = "A native PostgreSQL driver" repository = "https://github.com/sfackler/rust-postgres" -documentation = "https://sfackler.github.io/rust-postgres/doc/v0.9.3/postgres" +documentation = "https://sfackler.github.io/rust-postgres/doc/v0.9.4/postgres" readme = "README.md" keywords = ["database", "sql"] build = "build.rs" diff --git a/README.md b/README.md index 43df485a..c9d0f956 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Rust-Postgres A native PostgreSQL driver for Rust. -[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.9.3/postgres) +[Documentation](https://sfackler.github.io/rust-postgres/doc/v0.9.4/postgres) [![Build Status](https://travis-ci.org/sfackler/rust-postgres.png?branch=master)](https://travis-ci.org/sfackler/rust-postgres) [![Latest Version](https://img.shields.io/crates/v/postgres.svg)](https://crates.io/crates/postgres) diff --git a/src/lib.rs b/src/lib.rs index e9dee9ed..437cad8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ //! } //! } //! ``` -#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.9.3")] +#![doc(html_root_url="https://sfackler.github.io/rust-postgres/doc/v0.9.4")] #![warn(missing_docs)] extern crate bufstream;