Skip to content

Commit b30bd46

Browse files
committed
Set element_type for range types
Closes rust-postgres#95
1 parent 537120d commit b30bd46

3 files changed

Lines changed: 59 additions & 16 deletions

File tree

src/lib.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ mod util;
9999
pub mod types;
100100

101101
const CANARY: u32 = 0xdeadbeef;
102-
const TYPENAME_QUERY: &'static str = "t";
102+
const TYPEINFO_QUERY: &'static str = "t";
103103

104104
/// A type alias of the result returned by many methods.
105105
pub type Result<T> = result::Result<T, Error>;
@@ -456,15 +456,34 @@ impl InnerConnection {
456456
}
457457
}
458458

459-
match conn.raw_prepare(TYPENAME_QUERY,
460-
"SELECT typname, typelem FROM pg_catalog.pg_type WHERE oid = $1") {
461-
Ok(..) => {}
459+
try!(conn.setup_typeinfo_query());
460+
461+
Ok(conn)
462+
}
463+
464+
fn setup_typeinfo_query(&mut self) -> result::Result<(), ConnectError> {
465+
match self.raw_prepare(TYPEINFO_QUERY,
466+
"SELECT t.typname, t.typelem, r.rngsubtype \
467+
FROM pg_catalog.pg_type t \
468+
LEFT OUTER JOIN pg_catalog.pg_range r \
469+
ON r.rngtypid = t.oid \
470+
WHERE t.oid = $1") {
471+
Ok(..) => return Ok(()),
462472
Err(Error::IoError(e)) => return Err(ConnectError::IoError(e)),
473+
// Range types weren't added until Postgres 9.2, so pg_range may not exist
474+
Err(Error::DbError(DbError { code: SqlState::UndefinedTable, .. })) => {}
463475
Err(Error::DbError(e)) => return Err(ConnectError::DbError(e)),
464476
_ => unreachable!()
465477
}
466478

467-
Ok(conn)
479+
match self.raw_prepare(TYPEINFO_QUERY,
480+
"SELECT typname, typelem, NULL::OID FROM pg_catalog.pg_type \
481+
WHERE oid = $1") {
482+
Ok(..) => Ok(()),
483+
Err(Error::IoError(e)) => Err(ConnectError::IoError(e)),
484+
Err(Error::DbError(e)) => Err(ConnectError::DbError(e)),
485+
_ => unreachable!()
486+
}
468487
}
469488

470489
fn write_messages(&mut self, messages: &[FrontendMessage]) -> IoResult<()> {
@@ -683,7 +702,7 @@ impl InnerConnection {
683702
try!(self.write_messages(&[
684703
Bind {
685704
portal: "",
686-
statement: TYPENAME_QUERY,
705+
statement: TYPEINFO_QUERY,
687706
formats: &[1],
688707
values: &[try!(oid.to_sql(&Type::Oid))],
689708
result_formats: &[1]
@@ -701,10 +720,12 @@ impl InnerConnection {
701720
}
702721
_ => bad_response!(self)
703722
}
704-
let (name, elem_oid): (String, Oid) = match try!(self.read_message()) {
723+
let (name, elem_oid, rngsubtype): (String, Oid, Option<Oid>) =
724+
match try!(self.read_message()) {
705725
DataRow { row } => {
706726
(try!(FromSql::from_sql(&Type::Name, row[0].as_ref().map(|r| &**r))),
707-
try!(FromSql::from_sql(&Type::Oid, row[1].as_ref().map(|r| &**r))))
727+
try!(FromSql::from_sql(&Type::Oid, row[1].as_ref().map(|r| &**r))),
728+
try!(FromSql::from_sql(&Type::Oid, row[2].as_ref().map(|r| &**r))))
708729
}
709730
ErrorResponse { fields } => {
710731
try!(self.wait_for_ready());
@@ -722,10 +743,14 @@ impl InnerConnection {
722743
}
723744
try!(self.wait_for_ready());
724745

725-
let element_type = if elem_oid != 0 {
726-
Some(Box::new(try!(self.get_type(oid))))
746+
let elem_oid = if elem_oid != 0 {
747+
Some(elem_oid)
727748
} else {
728-
None
749+
rngsubtype
750+
};
751+
let element_type = match elem_oid {
752+
Some(oid) => Some(Box::new(try!(self.get_type(oid)))),
753+
None => None,
729754
};
730755
let type_ = Type::Unknown {
731756
oid: oid,

src/types/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ macro_rules! make_postgres_type {
234234
}
235235
}
236236

237-
/// If this `Type` is an array, returns the type of its elements
237+
/// If this `Type` is an array or range, returns the type of its elements
238238
pub fn element_type(&self) -> Option<Type> {
239239
match *self {
240240
$(
@@ -324,19 +324,19 @@ make_postgres_type! {
324324
#[doc="VARCHAR/CHARACTER VARYING"]
325325
VARCHAROID => Varchar:,
326326
#[doc="INT4RANGE"]
327-
INT4RANGEOID => Int4Range:,
327+
INT4RANGEOID => Int4Range: member Int4,
328328
#[doc="INT4RANGE[]"]
329329
INT4RANGEARRAYOID => Int4RangeArray: member Int4Range,
330330
#[doc="TSRANGE"]
331-
TSRANGEOID => TsRange:,
331+
TSRANGEOID => TsRange: member Timestamp,
332332
#[doc="TSRANGE[]"]
333333
TSRANGEARRAYOID => TsRangeArray: member TsRange,
334334
#[doc="TSTZRANGE"]
335-
TSTZRANGEOID => TstzRange:,
335+
TSTZRANGEOID => TstzRange: member TimestampTZ,
336336
#[doc="TSTZRANGE[]"]
337337
TSTZRANGEARRAYOID => TstzRangeArray: member TstzRange,
338338
#[doc="INT8RANGE"]
339-
INT8RANGEOID => Int8Range:,
339+
INT8RANGEOID => Int8Range: member Int8,
340340
#[doc="INT8RANGE[]"]
341341
INT8RANGEARRAYOID => Int8RangeArray: member Int8Range
342342
}

tests/test.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,3 +884,21 @@ fn test_generic_connection() {
884884
let trans = or_panic!(conn.transaction());
885885
f(&trans);
886886
}
887+
888+
#[test]
889+
fn test_custom_range_element_type() {
890+
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", &SslMode::None));
891+
let trans = or_panic!(conn.transaction());
892+
or_panic!(trans.execute("CREATE TYPE floatrange AS RANGE (
893+
subtype = float8,
894+
subtype_diff = float8mi
895+
)", &[]));
896+
let stmt = or_panic!(trans.prepare("SELECT $1::floatrange"));
897+
match &stmt.param_types()[0] {
898+
&Type::Unknown { ref name, ref element_type, .. } => {
899+
assert_eq!("floatrange", &**name);
900+
assert_eq!(&Some(Box::new(Type::Float8)), element_type);
901+
}
902+
t => panic!("Unexpected type {:?}", t)
903+
}
904+
}

0 commit comments

Comments
 (0)