Make Type an opaque type

This commit is contained in:
Steven Fackler 2017-07-09 00:02:45 -07:00
parent 561b46a7bf
commit bec973c776
19 changed files with 1500 additions and 1197 deletions

View File

@ -14,6 +14,7 @@ const PG_RANGE_H: &'static str = include_str!("pg_range.h");
struct Type {
name: &'static str,
variant: String,
ident: String,
kind: &'static str,
element: u32,
doc: String,
@ -27,8 +28,8 @@ pub fn build(path: &Path) {
make_header(&mut file);
make_enum(&mut file, &types);
make_display_impl(&mut file);
make_impl(&mut file, &types);
make_consts(&mut file, &types);
}
fn parse_ranges() -> BTreeMap<u32, u32> {
@ -69,14 +70,10 @@ fn parse_types(ranges: &BTreeMap<u32, u32>) -> BTreeMap<u32, Type> {
let name = split[5];
let variant = match name {
"anyarray" => "AnyArray".to_owned(),
name => {
let variant = range_vector_re.replace(name, "_$1");
let variant = array_re.replace(&variant, "$1_array");
snake_to_camel(&variant)
}
};
let ident = range_vector_re.replace(name, "_$1");
let ident = array_re.replace(&ident, "$1_array");
let variant = snake_to_camel(&ident);
let ident = ident.to_ascii_uppercase();
let kind = split[11];
@ -106,11 +103,12 @@ fn parse_types(ranges: &BTreeMap<u32, u32>) -> BTreeMap<u32, Type> {
let doc = String::from_utf8(doc).unwrap();
let type_ = Type {
name: name,
variant: variant,
kind: kind,
element: element,
doc: doc,
name,
variant,
ident,
kind,
element,
doc,
};
types.insert(oid, type_);
@ -123,10 +121,17 @@ fn make_header(w: &mut BufWriter<File>) {
write!(
w,
"// Autogenerated file - DO NOT EDIT
use std::fmt;
use std::sync::Arc;
use types::{{Oid, Kind, Other}};
use types::{{Type, Oid, Kind}};
#[derive(PartialEq, Eq, Debug)]
pub struct Other {{
pub name: String,
pub oid: Oid,
pub kind: Kind,
pub schema: String,
}}
"
).unwrap();
}
@ -134,55 +139,34 @@ use types::{{Oid, Kind, Other}};
fn make_enum(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
write!(
w,
"/// A Postgres type.
"
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {{
"
pub enum Inner {{"
).unwrap();
for type_ in types.values() {
write!(
w,
" /// {}
{},
",
type_.doc,
"
{},",
type_.variant
).unwrap();
}
write!(
w,
r" /// An unknown type.
Other(Other),
r"
Other(Arc<Other>),
}}
"
).unwrap();
}
fn make_display_impl(w: &mut BufWriter<File>) {
write!(w,
r#"impl fmt::Display for Type {{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {{
match self.schema() {{
"public" | "pg_catalog" => {{}}
schema => write!(fmt, "{{}}.", schema)?,
}}
fmt.write_str(self.name())
}}
}}
"#,
).unwrap();
}
fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
write!(w,
"impl Type {{
/// Returns the `Type` corresponding to the provided `Oid` if it
/// corresponds to a built-in type.
pub fn from_oid(oid: Oid) -> Option<Type> {{
"impl Inner {{
pub fn from_oid(oid: Oid) -> Option<Inner> {{
match oid {{
",
).unwrap();
@ -190,7 +174,7 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
for (oid, type_) in types {
write!(
w,
" {} => Some(Type::{}),
" {} => Some(Inner::{}),
",
oid,
type_.variant
@ -202,7 +186,6 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
}}
}}
/// Returns the OID of the `Type`.
pub fn oid(&self) -> Oid {{
match *self {{
",
@ -212,7 +195,7 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
for (oid, type_) in types {
write!(
w,
" Type::{} => {},
" Inner::{} => {},
",
type_.variant,
oid
@ -220,11 +203,10 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
}
write!(w,
" Type::Other(ref u) => u.oid(),
" Inner::Other(ref u) => u.oid,
}}
}}
/// Returns the kind of this type.
pub fn kind(&self) -> &Kind {{
match *self {{
",
@ -233,14 +215,14 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
for type_ in types.values() {
let kind = match type_.kind {
"P" => "Pseudo".to_owned(),
"A" => format!("Array(Type::{})", types[&type_.element].variant),
"R" => format!("Range(Type::{})", types[&type_.element].variant),
"A" => format!("Array(Type(Inner::{}))", types[&type_.element].variant),
"R" => format!("Range(Type(Inner::{}))", types[&type_.element].variant),
_ => "Simple".to_owned(),
};
write!(
w,
" Type::{} => {{
" Inner::{} => {{
const V: &'static Kind = &Kind::{};
V
}}
@ -251,19 +233,10 @@ fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
}
write!(w,
r#" Type::Other(ref u) => u.kind(),
r#" Inner::Other(ref u) => &u.kind,
}}
}}
/// Returns the schema of this type.
pub fn schema(&self) -> &str {{
match *self {{
Type::Other(ref u) => u.schema(),
_ => "pg_catalog",
}}
}}
/// Returns the name of this type.
pub fn name(&self) -> &str {{
match *self {{
"#,
@ -272,7 +245,7 @@ r#" Type::Other(ref u) => u.kind(),
for type_ in types.values() {
write!(
w,
r#" Type::{} => "{}",
r#" Inner::{} => "{}",
"#,
type_.variant,
type_.name
@ -281,10 +254,34 @@ r#" Type::Other(ref u) => u.kind(),
write!(
w,
" Type::Other(ref u) => u.name(),
" Inner::Other(ref u) => &u.name,
}}
}}
}}
"
).unwrap();
}
fn make_consts(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
write!(w,
"pub mod consts {{
use types::Type;
use types::type_gen::Inner;
",
).unwrap();
for type_ in types.values() {
write!(w,
"
/// {docs}
pub const {ident}: Type = Type(Inner::{variant});
",
docs = type_.doc,
ident = type_.ident,
variant = type_.variant).unwrap();
}
write!(w,
"}}"
).unwrap();
}

View File

@ -4,7 +4,7 @@ use postgres_protocol::types;
use self::bit_vec::BitVec;
use std::error::Error;
use types::{FromSql, ToSql, IsNull, Type};
use types::{FromSql, ToSql, IsNull, Type, BIT, VARBIT};
impl FromSql for BitVec {
fn from_sql(_: &Type, raw: &[u8]) -> Result<BitVec, Box<Error + Sync + Send>> {
@ -17,7 +17,7 @@ impl FromSql for BitVec {
Ok(bitvec)
}
accepts!(Type::Bit, Type::Varbit);
accepts!(BIT, VARBIT);
}
impl ToSql for BitVec {
@ -26,6 +26,6 @@ impl ToSql for BitVec {
Ok(IsNull::No)
}
accepts!(Type::Bit, Type::Varbit);
accepts!(BIT, VARBIT);
to_sql_checked!();
}

View File

@ -5,7 +5,7 @@ use self::chrono::{Duration, NaiveDate, NaiveTime, NaiveDateTime, DateTime, Utc,
FixedOffset};
use std::error::Error;
use types::{FromSql, ToSql, IsNull, Type};
use types::{FromSql, ToSql, IsNull, Type, TIMESTAMP, TIMESTAMPTZ, DATE, TIME};
fn base() -> NaiveDateTime {
NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0)
@ -17,7 +17,7 @@ impl FromSql for NaiveDateTime {
Ok(base() + Duration::microseconds(t))
}
accepts!(Type::Timestamp);
accepts!(TIMESTAMP);
}
impl ToSql for NaiveDateTime {
@ -30,7 +30,7 @@ impl ToSql for NaiveDateTime {
Ok(IsNull::No)
}
accepts!(Type::Timestamp);
accepts!(TIMESTAMP);
to_sql_checked!();
}
@ -40,7 +40,7 @@ impl FromSql for DateTime<Utc> {
Ok(DateTime::from_utc(naive, Utc))
}
accepts!(Type::Timestamptz);
accepts!(TIMESTAMPTZ);
}
impl ToSql for DateTime<Utc> {
@ -48,7 +48,7 @@ impl ToSql for DateTime<Utc> {
self.naive_utc().to_sql(type_, w)
}
accepts!(Type::Timestamptz);
accepts!(TIMESTAMPTZ);
to_sql_checked!();
}
@ -58,7 +58,7 @@ impl FromSql for DateTime<Local> {
Ok(utc.with_timezone(&Local))
}
accepts!(Type::Timestamptz);
accepts!(TIMESTAMPTZ);
}
impl ToSql for DateTime<Local> {
@ -70,7 +70,7 @@ impl ToSql for DateTime<Local> {
self.with_timezone(&Utc).to_sql(type_, w)
}
accepts!(Type::Timestamptz);
accepts!(TIMESTAMPTZ);
to_sql_checked!();
}
@ -83,7 +83,7 @@ impl FromSql for DateTime<FixedOffset> {
Ok(utc.with_timezone(&FixedOffset::east(0)))
}
accepts!(Type::Timestamptz);
accepts!(TIMESTAMPTZ);
}
impl ToSql for DateTime<FixedOffset> {
@ -91,7 +91,7 @@ impl ToSql for DateTime<FixedOffset> {
self.with_timezone(&Utc).to_sql(type_, w)
}
accepts!(Type::Timestamptz);
accepts!(TIMESTAMPTZ);
to_sql_checked!();
}
@ -101,7 +101,7 @@ impl FromSql for NaiveDate {
Ok(base().date() + Duration::days(jd as i64))
}
accepts!(Type::Date);
accepts!(DATE);
}
impl ToSql for NaiveDate {
@ -115,7 +115,7 @@ impl ToSql for NaiveDate {
Ok(IsNull::No)
}
accepts!(Type::Date);
accepts!(DATE);
to_sql_checked!();
}
@ -125,7 +125,7 @@ impl FromSql for NaiveTime {
Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec))
}
accepts!(Type::Time);
accepts!(TIME);
}
impl ToSql for NaiveTime {
@ -139,6 +139,6 @@ impl ToSql for NaiveTime {
Ok(IsNull::No)
}
accepts!(Type::Time);
accepts!(TIME);
to_sql_checked!();
}

View File

@ -4,7 +4,7 @@ use self::eui48::MacAddress;
use std::error::Error;
use postgres_protocol::types;
use types::{FromSql, ToSql, Type, IsNull};
use types::{FromSql, ToSql, Type, IsNull, MACADDR};
impl FromSql for MacAddress {
fn from_sql(_: &Type, raw: &[u8]) -> Result<MacAddress, Box<Error + Sync + Send>> {
@ -12,7 +12,7 @@ impl FromSql for MacAddress {
Ok(MacAddress::new(bytes))
}
accepts!(Type::Macaddr);
accepts!(MACADDR);
}
impl ToSql for MacAddress {
@ -23,6 +23,6 @@ impl ToSql for MacAddress {
Ok(IsNull::No)
}
accepts!(Type::Macaddr);
accepts!(MACADDR);
to_sql_checked!();
}

View File

@ -5,7 +5,7 @@ use self::geo::{Bbox, LineString, Point};
use std::error::Error;
use fallible_iterator::FallibleIterator;
use types::{FromSql, ToSql, IsNull, Type};
use types::{FromSql, ToSql, IsNull, Type, POINT, BOX, PATH};
impl FromSql for Point<f64> {
fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>> {
@ -13,7 +13,7 @@ impl FromSql for Point<f64> {
Ok(Point::new(point.x(), point.y()))
}
accepts!(Type::Point);
accepts!(POINT);
}
impl ToSql for Point<f64> {
@ -22,7 +22,7 @@ impl ToSql for Point<f64> {
Ok(IsNull::No)
}
accepts!(Type::Point);
accepts!(POINT);
to_sql_checked!();
}
@ -37,7 +37,7 @@ impl FromSql for Bbox<f64> {
})
}
accepts!(Type::Box);
accepts!(BOX);
}
impl ToSql for Bbox<f64> {
@ -46,7 +46,7 @@ impl ToSql for Bbox<f64> {
Ok(IsNull::No)
}
accepts!(Type::Box);
accepts!(BOX);
to_sql_checked!();
}
@ -57,7 +57,7 @@ impl FromSql for LineString<f64> {
Ok(LineString(points))
}
accepts!(Type::Path);
accepts!(PATH);
}
impl ToSql for LineString<f64> {
@ -67,6 +67,6 @@ impl ToSql for LineString<f64> {
Ok(IsNull::No)
}
accepts!(Type::Path);
accepts!(PATH);
to_sql_checked!();
}

View File

@ -6,11 +6,13 @@ use std::error::Error;
use std::fmt;
use std::sync::Arc;
use types::type_gen::{Inner, Other};
#[doc(inline)]
pub use postgres_protocol::Oid;
pub use self::type_gen::Type;
pub use self::special::{Date, Timestamp};
pub use types::type_gen::consts::*;
pub use types::special::{Date, Timestamp};
/// Generates a simple implementation of `ToSql::accepts` which accepts the
/// types passed to it.
@ -81,6 +83,62 @@ mod geo;
mod special;
mod type_gen;
/// A Postgres type.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Type(Inner);
impl fmt::Display for Type {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.schema() {
"public" | "pg_catalog" => {}
schema => write!(fmt, "{}.", schema)?,
}
fmt.write_str(self.name())
}
}
impl Type {
// WARNING: this is not considered public API
#[doc(hidden)]
pub fn _new(name: String, oid: Oid, kind: Kind, schema: String) -> Type {
Type(Inner::Other(Arc::new(Other {
name: name,
oid: oid,
kind: kind,
schema: schema,
})))
}
/// Returns the `Type` corresponding to the provided `Oid` if it
/// corresponds to a built-in type.
pub fn from_oid(oid: Oid) -> Option<Type> {
Inner::from_oid(oid).map(Type)
}
/// Returns the OID of the `Type`.
pub fn oid(&self) -> Oid {
self.0.oid()
}
/// Returns the kind of this type.
pub fn kind(&self) -> &Kind {
self.0.kind()
}
/// Returns the schema of this type.
pub fn schema(&self) -> &str {
match self.0 {
Inner::Other(ref u) => &u.schema,
_ => "pg_catalog",
}
}
/// Returns the name of this type.
pub fn name(&self) -> &str {
self.0.name()
}
}
/// Represents the kind of a Postgres type.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Kind {
@ -131,63 +189,6 @@ impl Field {
}
}
/// Information about an unknown type.
#[derive(PartialEq, Eq, Clone)]
pub struct Other(Arc<OtherInner>);
impl fmt::Debug for Other {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Other")
.field("name", &self.0.name)
.field("oid", &self.0.oid)
.field("kind", &self.0.kind)
.field("schema", &self.0.schema)
.finish()
}
}
#[derive(PartialEq, Eq)]
struct OtherInner {
name: String,
oid: Oid,
kind: Kind,
schema: String,
}
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,
}))
}
}
impl Other {
/// The name of the type.
pub fn name(&self) -> &str {
&self.0.name
}
/// The OID of this type.
pub fn oid(&self) -> Oid {
self.0.oid
}
/// The kind of this type.
pub fn kind(&self) -> &Kind {
&self.0.kind
}
/// The schema of this type.
pub fn schema(&self) -> &str {
&self.0.schema
}
}
/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
/// implementation that does not support `NULL` values.
#[derive(Debug, Clone, Copy)]
@ -365,7 +366,7 @@ impl FromSql for Vec<u8> {
Ok(types::bytea_from_sql(raw).to_owned())
}
accepts!(Type::Bytea);
accepts!(BYTEA);
}
impl FromSql for String {
@ -375,8 +376,8 @@ impl FromSql for String {
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Varchar | Type::Text | Type::Bpchar | Type::Name | Type::Unknown => true,
Type::Other(ref u) if u.name() == "citext" => true,
VARCHAR | TEXT | BPCHAR | NAME | UNKNOWN => true,
ref ty if ty.name() == "citext" => true,
_ => false,
}
}
@ -396,14 +397,14 @@ macro_rules! simple_from {
}
}
simple_from!(bool, bool_from_sql, Type::Bool);
simple_from!(i8, char_from_sql, Type::Char);
simple_from!(i16, int2_from_sql, Type::Int2);
simple_from!(i32, int4_from_sql, Type::Int4);
simple_from!(u32, oid_from_sql, Type::Oid);
simple_from!(i64, int8_from_sql, Type::Int8);
simple_from!(f32, float4_from_sql, Type::Float4);
simple_from!(f64, float8_from_sql, Type::Float8);
simple_from!(bool, bool_from_sql, BOOL);
simple_from!(i8, char_from_sql, CHAR);
simple_from!(i16, int2_from_sql, INT2);
simple_from!(i32, int4_from_sql, INT4);
simple_from!(u32, oid_from_sql, OID);
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>> {
fn from_sql(
@ -416,10 +417,7 @@ impl FromSql for HashMap<String, Option<String>> {
}
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Other(ref u) if u.name() == "hstore" => true,
_ => false,
}
ty.name() == "hstore"
}
}
@ -589,7 +587,7 @@ impl<'a> ToSql for &'a [u8] {
Ok(IsNull::No)
}
accepts!(Type::Bytea);
accepts!(BYTEA);
to_sql_checked!();
}
@ -626,8 +624,8 @@ impl<'a> ToSql for &'a str {
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Varchar | Type::Text | Type::Bpchar | Type::Name => true,
Type::Other(ref u) if u.name() == "citext" => true,
VARCHAR | TEXT | BPCHAR | NAME | UNKNOWN => true,
ref ty if ty.name() == "citext" => true,
_ => false,
}
}
@ -665,14 +663,14 @@ macro_rules! simple_to {
}
}
simple_to!(bool, bool_to_sql, Type::Bool);
simple_to!(i8, char_to_sql, Type::Char);
simple_to!(i16, int2_to_sql, Type::Int2);
simple_to!(i32, int4_to_sql, Type::Int4);
simple_to!(u32, oid_to_sql, Type::Oid);
simple_to!(i64, int8_to_sql, Type::Int8);
simple_to!(f32, float4_to_sql, Type::Float4);
simple_to!(f64, float8_to_sql, Type::Float8);
simple_to!(bool, bool_to_sql, BOOL);
simple_to!(i8, char_to_sql, CHAR);
simple_to!(i16, int2_to_sql, INT2);
simple_to!(i32, int4_to_sql, INT4);
simple_to!(u32, oid_to_sql, OID);
simple_to!(i64, int8_to_sql, INT8);
simple_to!(f32, float4_to_sql, FLOAT4);
simple_to!(f64, float8_to_sql, FLOAT8);
impl ToSql for HashMap<String, Option<String>> {
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
@ -684,10 +682,7 @@ impl ToSql for HashMap<String, Option<String>> {
}
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Other(ref u) if u.name() == "hstore" => true,
_ => false,
}
ty.name() == "hstore"
}
to_sql_checked!();

View File

@ -4,11 +4,11 @@ use self::rustc_serialize::json;
use std::io::{Read, Write};
use std::error::Error;
use types::{FromSql, ToSql, IsNull, Type};
use types::{FromSql, ToSql, IsNull, Type, JSON, JSONB};
impl FromSql for json::Json {
fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<json::Json, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
if *ty == JSONB {
let mut b = [0; 1];
raw.read_exact(&mut b)?;
// We only support version 1 of the jsonb binary format
@ -19,18 +19,18 @@ impl FromSql for json::Json {
json::Json::from_reader(&mut raw).map_err(Into::into)
}
accepts!(Type::Json, Type::Jsonb);
accepts!(JSON, JSONB);
}
impl ToSql for json::Json {
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
if *ty == JSONB {
out.push(1);
}
write!(out, "{}", self)?;
Ok(IsNull::No)
}
accepts!(Type::Json, Type::Jsonb);
accepts!(JSON, JSONB);
to_sql_checked!();
}

View File

@ -4,11 +4,11 @@ use self::serde_json::Value;
use std::error::Error;
use std::io::{Read, Write};
use types::{FromSql, ToSql, IsNull, Type};
use types::{FromSql, ToSql, IsNull, Type, JSON, JSONB};
impl FromSql for Value {
fn from_sql(ty: &Type, mut raw: &[u8]) -> Result<Value, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
if *ty == JSONB {
let mut b = [0; 1];
raw.read_exact(&mut b)?;
// We only support version 1 of the jsonb binary format
@ -19,18 +19,18 @@ impl FromSql for Value {
serde_json::de::from_reader(raw).map_err(Into::into)
}
accepts!(Type::Json, Type::Jsonb);
accepts!(JSON, JSONB);
}
impl ToSql for Value {
fn to_sql(&self, ty: &Type, mut out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
if let Type::Jsonb = *ty {
if *ty == JSONB {
out.push(1);
}
write!(out, "{}", self)?;
Ok(IsNull::No)
}
accepts!(Type::Json, Type::Jsonb);
accepts!(JSON, JSONB);
to_sql_checked!();
}

View File

@ -2,7 +2,7 @@ use postgres_protocol::types;
use std::{i32, i64};
use std::error::Error;
use types::{Type, FromSql, ToSql, IsNull};
use types::{Type, FromSql, ToSql, IsNull, DATE, TIMESTAMP, TIMESTAMPTZ};
/// A wrapper that can be used to represent infinity with `Type::Date` types.
#[derive(Debug, Clone, Copy, PartialEq)]
@ -25,7 +25,7 @@ impl<T: FromSql> FromSql for Date<T> {
}
fn accepts(ty: &Type) -> bool {
*ty == Type::Date && T::accepts(ty)
*ty == DATE && T::accepts(ty)
}
}
impl<T: ToSql> ToSql for Date<T> {
@ -41,7 +41,7 @@ impl<T: ToSql> ToSql for Date<T> {
}
fn accepts(ty: &Type) -> bool {
*ty == Type::Date && T::accepts(ty)
*ty == DATE && T::accepts(ty)
}
to_sql_checked!();
@ -69,7 +69,10 @@ impl<T: FromSql> FromSql for Timestamp<T> {
}
fn accepts(ty: &Type) -> bool {
(*ty == Type::Timestamp || *ty == Type::Timestamptz) && T::accepts(ty)
match *ty {
TIMESTAMP | TIMESTAMPTZ if T::accepts(ty) => true,
_ => false
}
}
}
@ -86,7 +89,10 @@ impl<T: ToSql> ToSql for Timestamp<T> {
}
fn accepts(ty: &Type) -> bool {
(*ty == Type::Timestamp || *ty == Type::Timestamptz) && T::accepts(ty)
match *ty {
TIMESTAMP | TIMESTAMPTZ if T::accepts(ty) => true,
_ => false
}
}
to_sql_checked!();

View File

@ -4,7 +4,7 @@ use self::time::Timespec;
use std::error::Error;
use postgres_protocol::types;
use types::{Type, FromSql, ToSql, IsNull};
use types::{Type, FromSql, ToSql, IsNull, TIMESTAMP, TIMESTAMPTZ};
const USEC_PER_SEC: i64 = 1_000_000;
const NSEC_PER_USEC: i64 = 1_000;
@ -26,7 +26,7 @@ impl FromSql for Timespec {
Ok(Timespec::new(sec, (usec * NSEC_PER_USEC) as i32))
}
accepts!(Type::Timestamp, Type::Timestamptz);
accepts!(TIMESTAMP, TIMESTAMPTZ);
}
impl ToSql for Timespec {
@ -36,6 +36,6 @@ impl ToSql for Timespec {
Ok(IsNull::No)
}
accepts!(Type::Timestamp, Type::Timestamptz);
accepts!(TIMESTAMP, TIMESTAMPTZ);
to_sql_checked!();
}

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ use postgres_protocol::types;
use self::uuid::Uuid;
use std::error::Error;
use types::{FromSql, ToSql, Type, IsNull};
use types::{FromSql, ToSql, Type, IsNull, UUID};
impl FromSql for Uuid {
fn from_sql(_: &Type, raw: &[u8]) -> Result<Uuid, Box<Error + Sync + Send>> {
@ -12,7 +12,7 @@ impl FromSql for Uuid {
Ok(Uuid::from_bytes(&bytes).unwrap())
}
accepts!(Type::Uuid);
accepts!(UUID);
}
impl ToSql for Uuid {
@ -21,6 +21,6 @@ impl ToSql for Uuid {
Ok(IsNull::No)
}
accepts!(Type::Uuid);
accepts!(UUID);
to_sql_checked!();
}

View File

@ -101,7 +101,7 @@ use priv_io::MessageStream;
use rows::{Rows, LazyRows};
use stmt::{Statement, Column};
use transaction::{Transaction, IsolationLevel};
use types::{IsNull, Kind, Type, Oid, Other, ToSql, FromSql, Field};
use types::{IsNull, Kind, Type, Oid, ToSql, FromSql, Field, OID, NAME, CHAR};
#[doc(inline)]
pub use postgres_shared::CancelData;
@ -236,7 +236,7 @@ struct InnerConnection {
notice_handler: Box<HandleNotice>,
notifications: VecDeque<Notification>,
cancel_data: CancelData,
unknown_types: HashMap<Oid, Other>,
unknown_types: HashMap<Oid, Type>,
cached_statements: HashMap<String, Arc<StatementInfo>>,
parameters: HashMap<String, String>,
next_stmt_id: u32,
@ -745,12 +745,12 @@ impl InnerConnection {
}
if let Some(ty) = self.unknown_types.get(&oid) {
return Ok(Type::Other(ty.clone()));
return Ok(ty.clone());
}
let ty = self.read_type(oid)?;
self.unknown_types.insert(oid, ty.clone());
Ok(Type::Other(ty))
Ok(ty)
}
fn setup_typeinfo_query(&mut self) -> Result<()> {
@ -790,13 +790,13 @@ impl InnerConnection {
}
#[allow(if_not_else)]
fn read_type(&mut self, oid: Oid) -> Result<Other> {
fn read_type(&mut self, oid: Oid) -> Result<Type> {
self.setup_typeinfo_query()?;
self.raw_execute(
TYPEINFO_QUERY,
"",
0,
&[Type::Oid],
&[OID],
&[&oid],
)?;
let mut row = None;
@ -805,24 +805,24 @@ impl InnerConnection {
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(
let name = String::from_sql_nullable(&NAME, get_raw(0)).map_err(
Error::Conversion,
)?;
let type_ = i8::from_sql_nullable(&Type::Char, get_raw(1)).map_err(
let type_ = i8::from_sql_nullable(&CHAR, get_raw(1)).map_err(
Error::Conversion,
)?;
let elem_oid = Oid::from_sql_nullable(&Type::Oid, get_raw(2)).map_err(
let elem_oid = Oid::from_sql_nullable(&OID, get_raw(2)).map_err(
Error::Conversion,
)?;
let rngsubtype = Option::<Oid>::from_sql_nullable(&Type::Oid, get_raw(3))
let rngsubtype = Option::<Oid>::from_sql_nullable(&OID, get_raw(3))
.map_err(Error::Conversion)?;
let basetype = Oid::from_sql_nullable(&Type::Oid, get_raw(4)).map_err(
let basetype = Oid::from_sql_nullable(&OID, get_raw(4)).map_err(
Error::Conversion,
)?;
let schema = String::from_sql_nullable(&Type::Name, get_raw(5)).map_err(
let schema = String::from_sql_nullable(&NAME, get_raw(5)).map_err(
Error::Conversion,
)?;
let relid = Oid::from_sql_nullable(&Type::Oid, get_raw(6)).map_err(
let relid = Oid::from_sql_nullable(&OID, get_raw(6)).map_err(
Error::Conversion,
)?;
(name, type_, elem_oid, rngsubtype, basetype, schema, relid)
@ -845,7 +845,7 @@ impl InnerConnection {
}
};
Ok(Other::new(name, oid, kind, schema))
Ok(Type::_new(name, oid, kind, schema))
}
fn setup_typeinfo_enum_query(&mut self) -> Result<()> {
@ -884,7 +884,7 @@ impl InnerConnection {
TYPEINFO_ENUM_QUERY,
"",
0,
&[Type::Oid],
&[OID],
&[&oid],
)?;
let mut rows = vec![];
@ -892,7 +892,7 @@ impl InnerConnection {
let mut variants = vec![];
for row in rows {
variants.push(String::from_sql_nullable(&Type::Name, row.get(0)).map_err(
variants.push(String::from_sql_nullable(&NAME, row.get(0)).map_err(
Error::Conversion,
)?);
}
@ -925,7 +925,7 @@ impl InnerConnection {
TYPEINFO_COMPOSITE_QUERY,
"",
0,
&[Type::Oid],
&[OID],
&[&relid],
)?;
let mut rows = vec![];
@ -934,10 +934,10 @@ impl InnerConnection {
let mut fields = vec![];
for row in rows {
let (name, type_) = {
let name = String::from_sql_nullable(&Type::Name, row.get(0)).map_err(
let name = String::from_sql_nullable(&NAME, row.get(0)).map_err(
Error::Conversion,
)?;
let type_ = Oid::from_sql_nullable(&Type::Oid, row.get(1)).map_err(
let type_ = Oid::from_sql_nullable(&OID, row.get(1)).map_err(
Error::Conversion,
)?;
(name, type_)
@ -1468,10 +1468,6 @@ fn err(fields: &mut ErrorFields) -> Error {
}
}
trait OtherNew {
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other;
}
trait RowsNew {
fn new(stmt: &Statement, data: Vec<RowData>) -> Rows<'static>;
}

View File

@ -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};
// FIXME
pub use postgres_shared::types::*;
#[doc(hidden)]
pub use postgres_shared::types::__to_sql_checked;

View File

@ -14,7 +14,7 @@ use postgres::{HandleNotice, Connection, GenericConnection, TlsMode};
use postgres::transaction::{self, IsolationLevel};
use postgres::error::{Error, ConnectError, DbError, SYNTAX_ERROR, QUERY_CANCELED, UNDEFINED_TABLE,
INVALID_CATALOG_NAME, INVALID_PASSWORD, CARDINALITY_VIOLATION};
use postgres::types::{Oid, Type, Kind, WrongType};
use postgres::types::{Oid, Type, Kind, WrongType, INT4, VARCHAR, FLOAT8};
use postgres::error::ErrorPosition::Normal;
use postgres::rows::RowIndex;
use postgres::notification::Notification;
@ -574,7 +574,7 @@ fn test_param_types() {
TlsMode::None,
));
let stmt = or_panic!(conn.prepare("SELECT $1::INT, $2::VARCHAR"));
assert_eq!(stmt.param_types(), &[Type::Int4, Type::Varchar][..]);
assert_eq!(stmt.param_types(), &[INT4, VARCHAR][..]);
}
#[test]
@ -587,9 +587,9 @@ fn test_columns() {
let cols = stmt.columns();
assert_eq!(2, cols.len());
assert_eq!(cols[0].name(), "a");
assert_eq!(cols[0].type_(), &Type::Int4);
assert_eq!(cols[0].type_(), &INT4);
assert_eq!(cols[1].name(), "b");
assert_eq!(cols[1].type_(), &Type::Varchar);
assert_eq!(cols[1].type_(), &VARCHAR);
}
#[test]
@ -1277,13 +1277,9 @@ fn test_custom_range_element_type() {
&[],
));
let stmt = or_panic!(conn.prepare("SELECT $1::floatrange"));
match &stmt.param_types()[0] {
&Type::Other(ref u) => {
assert_eq!("floatrange", u.name());
assert_eq!(&Kind::Range(Type::Float8), u.kind());
}
t => panic!("Unexpected type {:?}", t),
}
let ty = &stmt.param_types()[0];
assert_eq!("floatrange", ty.name());
assert_eq!(&Kind::Range(FLOAT8), ty.kind());
}
#[test]

View File

@ -7,7 +7,7 @@ use std::result;
use postgres::{Connection, TlsMode};
use postgres::error::Error;
use postgres::types::{ToSql, FromSql, WrongType, Type, IsNull, Kind};
use postgres::types::{ToSql, FromSql, WrongType, Type, IsNull, Kind, TEXT, INT4, NUMERIC};
#[cfg(feature = "with-bit-vec")]
mod bit_vec;
@ -449,11 +449,11 @@ fn composite() {
match *type_.kind() {
Kind::Composite(ref fields) => {
assert_eq!(fields[0].name(), "name");
assert_eq!(fields[0].type_(), &Type::Text);
assert_eq!(fields[0].type_(), &TEXT);
assert_eq!(fields[1].name(), "supplier");
assert_eq!(fields[1].type_(), &Type::Int4);
assert_eq!(fields[1].type_(), &INT4);
assert_eq!(fields[2].name(), "price");
assert_eq!(fields[2].type_(), &Type::Numeric);
assert_eq!(fields[2].type_(), &NUMERIC);
}
ref t => panic!("bad type {:?}", t),
}

View File

@ -95,7 +95,7 @@ use stmt::{Statement, Column};
use stream::PostgresStream;
use tls::Handshake;
use transaction::Transaction;
use types::{Oid, Type, ToSql, IsNull, FromSql, Other, Kind, Field};
use types::{Oid, Type, ToSql, IsNull, FromSql, Kind, Field, NAME, CHAR, OID};
use rows::Row;
pub mod error;
@ -173,7 +173,7 @@ struct InnerConnection {
close_receiver: Receiver<(u8, String)>,
close_sender: Sender<(u8, String)>,
parameters: HashMap<String, String>,
types: HashMap<Oid, Other>,
types: HashMap<Oid, Type>,
notifications: VecDeque<Notification>,
cancel_data: CancelData,
has_typeinfo_query: bool,
@ -661,53 +661,53 @@ impl Connection {
return Ok((type_, self)).into_future().boxed();
};
let other = self.0.types.get(&oid).map(Clone::clone);
if let Some(other) = other {
return Ok((Type::Other(other), self)).into_future().boxed();
let ty = self.0.types.get(&oid).map(Clone::clone);
if let Some(ty) = ty {
return Ok((ty, self)).into_future().boxed();
}
self.get_unknown_type(oid)
.map(move |(ty, mut c)| {
c.0.types.insert(oid, ty.clone());
(Type::Other(ty), c)
(ty, c)
})
.boxed()
}
fn get_unknown_type(self, oid: Oid) -> BoxFuture<(Other, Connection), Error> {
fn get_unknown_type(self, oid: Oid) -> BoxFuture<(Type, Connection), Error> {
self.setup_typeinfo_query()
.and_then(move |c| {
c.raw_execute(TYPEINFO_QUERY, "", &[Type::Oid], &[&oid])
c.raw_execute(TYPEINFO_QUERY, "", &[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));
let name = match String::from_sql_nullable(&Type::Name, get(0)) {
let name = match String::from_sql_nullable(&NAME, get(0)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let type_ = match i8::from_sql_nullable(&Type::Char, get(1)) {
let type_ = match i8::from_sql_nullable(&CHAR, get(1)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let elem_oid = match Oid::from_sql_nullable(&Type::Oid, get(2)) {
let elem_oid = match Oid::from_sql_nullable(&OID, get(2)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let rngsubtype = match Option::<Oid>::from_sql_nullable(&Type::Oid, get(3)) {
let rngsubtype = match Option::<Oid>::from_sql_nullable(&OID, get(3)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let basetype = match Oid::from_sql_nullable(&Type::Oid, get(4)) {
let basetype = match Oid::from_sql_nullable(&OID, get(4)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let schema = match String::from_sql_nullable(&Type::Name, get(5)) {
let schema = match String::from_sql_nullable(&NAME, get(5)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let relid = match Oid::from_sql_nullable(&Type::Oid, get(6)) {
let relid = match Oid::from_sql_nullable(&OID, get(6)) {
Ok(v) => v,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
@ -749,7 +749,7 @@ impl Connection {
};
Either::B(kind.map(
move |(k, c)| (Other::new(name, oid, k, schema), c),
move |(k, c)| (Type::_new(name, oid, k, schema), c),
))
})
.boxed()
@ -802,13 +802,13 @@ 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])
c.raw_execute(TYPEINFO_ENUM_QUERY, "", &[OID], &[&oid])
})
.and_then(|c| c.read_rows().collect())
.and_then(|(r, c)| {
let mut variants = vec![];
for row in r {
let variant = match String::from_sql_nullable(&Type::Name, row.get(0)) {
let variant = match String::from_sql_nullable(&NAME, row.get(0)) {
Ok(v) => v,
Err(e) => return Err(Error::Conversion(e, c)),
};
@ -854,18 +854,18 @@ impl Connection {
fn get_composite_fields(self, oid: Oid) -> BoxFuture<(Vec<Field>, Connection), Error> {
self.setup_typeinfo_composite_query()
.and_then(move |c| {
c.raw_execute(TYPEINFO_COMPOSITE_QUERY, "", &[Type::Oid], &[&oid])
c.raw_execute(TYPEINFO_COMPOSITE_QUERY, "", &[OID], &[&oid])
})
.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| {
let name = match String::from_sql_nullable(&Type::Name, row.get(0)) {
let name = match String::from_sql_nullable(&NAME, row.get(0)) {
Ok(name) => name,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};
let oid = match Oid::from_sql_nullable(&Type::Oid, row.get(1)) {
let oid = match Oid::from_sql_nullable(&OID, row.get(1)) {
Ok(oid) => oid,
Err(e) => return Either::A(Err(Error::Conversion(e, c)).into_future()),
};

View File

@ -9,7 +9,7 @@ use super::*;
use error::{Error, ConnectError, INVALID_PASSWORD, INVALID_AUTHORIZATION_SPECIFICATION,
QUERY_CANCELED};
use params::{ConnectParams, Host};
use types::{ToSql, FromSql, Type, IsNull, Kind};
use types::{ToSql, FromSql, Type, IsNull, Kind, BYTEA, TEXT, INT4, NUMERIC};
#[test]
fn md5_user() {
@ -318,7 +318,7 @@ fn domain() {
fn accepts(ty: &Type) -> bool {
match *ty.kind() {
Kind::Domain(Type::Bytea) => ty.name() == "session_id",
Kind::Domain(BYTEA) => ty.name() == "session_id",
_ => false,
}
}
@ -385,11 +385,11 @@ fn composite() {
match *type_.kind() {
Kind::Composite(ref fields) => {
assert_eq!(fields[0].name(), "name");
assert_eq!(fields[0].type_(), &Type::Text);
assert_eq!(fields[0].type_(), &TEXT);
assert_eq!(fields[1].name(), "supplier");
assert_eq!(fields[1].type_(), &Type::Int4);
assert_eq!(fields[1].type_(), &INT4);
assert_eq!(fields[2].name(), "price");
assert_eq!(fields[2].type_(), &Type::Numeric);
assert_eq!(fields[2].type_(), &NUMERIC);
}
ref t => panic!("bad type {:?}", t),
}

View File

@ -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};
// FIXME
pub use postgres_shared::types::*;
#[doc(hidden)]
pub use postgres_shared::types::__to_sql_checked;