1- use std:: io:: prelude:: * ;
2- use std:: error;
3- use postgres;
1+ use std:: error:: Error ;
42use postgres:: types:: { Type , Kind , ToSql , FromSql , IsNull , SessionInfo } ;
5- use postgres:: error:: Error ;
6- use byteorder:: { ReadBytesExt , WriteBytesExt , BigEndian } ;
3+ use postgres_protocol:: types;
74
85use { Range , RangeBound , BoundType , BoundSided , Normalizable } ;
96
10- const RANGE_UPPER_UNBOUNDED : i8 = 0b0001_0000 ;
11- const RANGE_LOWER_UNBOUNDED : i8 = 0b0000_1000 ;
12- const RANGE_UPPER_INCLUSIVE : i8 = 0b0000_0100 ;
13- const RANGE_LOWER_INCLUSIVE : i8 = 0b0000_0010 ;
14- const RANGE_EMPTY : i8 = 0b0000_0001 ;
15-
167impl < T > FromSql for Range < T > where T : PartialOrd +Normalizable +FromSql {
17- fn from_sql < R : Read > ( ty : & Type , rdr : & mut R , info : & SessionInfo )
18- -> postgres:: Result < Range < T > > {
8+ fn from_sql ( ty : & Type , raw : & [ u8 ] , info : & SessionInfo ) -> Result < Range < T > , Box < Error + Sync + Send > > {
199 let element_type = match ty. kind ( ) {
2010 & Kind :: Range ( ref ty) => ty,
2111 _ => panic ! ( "unexpected type {:?}" , ty)
2212 } ;
2313
24- let t = try!( rdr. read_i8 ( ) ) ;
25-
26- if t & RANGE_EMPTY != 0 {
27- return Ok ( Range :: empty ( ) ) ;
28- }
29-
30- fn make_bound < S , T , R > ( ty : & Type , rdr : & mut R , info : & SessionInfo ,
31- tag : i8 , bound_flag : i8 , inclusive_flag : i8 )
32- -> postgres:: Result < Option < RangeBound < S , T > > >
33- where S : BoundSided , T : PartialOrd +Normalizable +FromSql , R : Read {
34- match tag & bound_flag {
35- 0 => {
36- let type_ = match tag & inclusive_flag {
37- 0 => BoundType :: Exclusive ,
38- _ => BoundType :: Inclusive ,
39- } ;
40- let len = try!( rdr. read_i32 :: < BigEndian > ( ) ) as u64 ;
41- let mut limit = rdr. take ( len) ;
42- let bound = try!( FromSql :: from_sql ( ty, & mut limit, info) ) ;
43- if limit. limit ( ) != 0 {
44- let err: Box < error:: Error +Sync +Send > =
45- "from_sql call did not consume all data" . into ( ) ;
46- return Err ( Error :: Conversion ( err) ) ;
47- }
48- Ok ( Some ( RangeBound :: new ( bound, type_) ) )
49- }
50- _ => Ok ( None )
14+ match try!( types:: range_from_sql ( raw) ) {
15+ types:: Range :: Empty => Ok ( Range :: empty ( ) ) ,
16+ types:: Range :: Nonempty ( lower, upper) => {
17+ let lower = try!( bound_from_sql ( lower, element_type, info) ) ;
18+ let upper = try!( bound_from_sql ( upper, element_type, info) ) ;
19+ Ok ( Range :: new ( lower, upper) )
5120 }
5221 }
53-
54- let lower = try!( make_bound ( element_type, rdr, info, t,
55- RANGE_LOWER_UNBOUNDED , RANGE_LOWER_INCLUSIVE ) ) ;
56- let upper = try!( make_bound ( element_type, rdr, info, t,
57- RANGE_UPPER_UNBOUNDED , RANGE_UPPER_INCLUSIVE ) ) ;
58- Ok ( Range :: new ( lower, upper) )
5922 }
6023
6124 fn accepts ( ty : & Type ) -> bool {
@@ -66,47 +29,44 @@ impl<T> FromSql for Range<T> where T: PartialOrd+Normalizable+FromSql {
6629 }
6730}
6831
32+ fn bound_from_sql < T , S > ( bound : types:: RangeBound < Option < & [ u8 ] > > , ty : & Type , info : & SessionInfo ) -> Result < Option < RangeBound < S , T > > , Box < Error + Sync + Send > >
33+ where T : PartialOrd + Normalizable + FromSql ,
34+ S : BoundSided
35+ {
36+ match bound {
37+ types:: RangeBound :: Exclusive ( value) => {
38+ let value = match value {
39+ Some ( value) => try!( T :: from_sql ( ty, value, info) ) ,
40+ None => try!( T :: from_sql_null ( ty, info) ) ,
41+ } ;
42+ Ok ( Some ( RangeBound :: new ( value, BoundType :: Exclusive ) ) )
43+ } ,
44+ types:: RangeBound :: Inclusive ( value) => {
45+ let value = match value {
46+ Some ( value) => try!( T :: from_sql ( ty, value, info) ) ,
47+ None => try!( T :: from_sql_null ( ty, info) ) ,
48+ } ;
49+ Ok ( Some ( RangeBound :: new ( value, BoundType :: Inclusive ) ) )
50+ } ,
51+ types:: RangeBound :: Unbounded => Ok ( None ) ,
52+ }
53+ }
54+
6955impl < T > ToSql for Range < T > where T : PartialOrd +Normalizable +ToSql {
70- fn to_sql < W : ?Sized +Write > ( & self , ty : & Type , mut buf : & mut W , info : & SessionInfo )
71- -> postgres:: Result < IsNull > {
56+ fn to_sql ( & self , ty : & Type , mut buf : & mut Vec < u8 > , info : & SessionInfo ) -> Result < IsNull , Box < Error + Sync + Send > > {
7257 let element_type = match ty. kind ( ) {
7358 & Kind :: Range ( ref ty) => ty,
7459 _ => panic ! ( "unexpected type {:?}" , ty)
7560 } ;
7661
77- let mut tag = 0 ;
7862 if self . is_empty ( ) {
79- tag |= RANGE_EMPTY ;
63+ types :: empty_range_to_sql ( buf ) ;
8064 } else {
81- fn make_tag < S , T > ( bound : Option < & RangeBound < S , T > > , unbounded_tag : i8 ,
82- inclusive_tag : i8 ) -> i8 where S : BoundSided {
83- match bound {
84- None => unbounded_tag,
85- Some ( & RangeBound { type_ : BoundType :: Inclusive , .. } ) => inclusive_tag,
86- _ => 0
87- }
88- }
89- tag |= make_tag ( self . lower ( ) , RANGE_LOWER_UNBOUNDED , RANGE_LOWER_INCLUSIVE ) ;
90- tag |= make_tag ( self . upper ( ) , RANGE_UPPER_UNBOUNDED , RANGE_UPPER_INCLUSIVE ) ;
91- }
92-
93- try!( buf. write_i8 ( tag) ) ;
94-
95- fn write_value < S , T , W : ?Sized > ( ty : & Type , mut buf : & mut W , info : & SessionInfo ,
96- v : Option < & RangeBound < S , T > > ) -> postgres:: Result < ( ) >
97- where S : BoundSided , T : ToSql , W : Write {
98- if let Some ( bound) = v {
99- let mut inner_buf = vec ! [ ] ;
100- try!( bound. value . to_sql ( ty, & mut inner_buf, info) ) ;
101- try!( buf. write_u32 :: < BigEndian > ( inner_buf. len ( ) as u32 ) ) ;
102- try!( buf. write_all ( & * inner_buf) ) ;
103- }
104- Ok ( ( ) )
65+ try!( types:: range_to_sql ( |buf| bound_to_sql ( self . lower ( ) , element_type, info, buf) ,
66+ |buf| bound_to_sql ( self . upper ( ) , element_type, info, buf) ,
67+ buf) ) ;
10568 }
10669
107- try!( write_value ( & element_type, buf, info, self . lower ( ) ) ) ;
108- try!( write_value ( & element_type, buf, info, self . upper ( ) ) ) ;
109-
11070 Ok ( IsNull :: No )
11171 }
11272
@@ -120,11 +80,32 @@ impl<T> ToSql for Range<T> where T: PartialOrd+Normalizable+ToSql {
12080 to_sql_checked ! ( ) ;
12181}
12282
83+ fn bound_to_sql < S , T > ( bound : Option < & RangeBound < S , T > > , ty : & Type , info : & SessionInfo , buf : & mut Vec < u8 > ) -> Result < types:: RangeBound < types:: IsNull > , Box < Error + Sync + Send > >
84+ where S : BoundSided ,
85+ T : ToSql
86+ {
87+ match bound {
88+ Some ( bound) => {
89+ let null = match try!( bound. value . to_sql ( ty, buf, info) ) {
90+ IsNull :: Yes => types:: IsNull :: Yes ,
91+ IsNull :: No => types:: IsNull :: No ,
92+ } ;
93+
94+ match bound. type_ {
95+ BoundType :: Exclusive => Ok ( types:: RangeBound :: Exclusive ( null) ) ,
96+ BoundType :: Inclusive => Ok ( types:: RangeBound :: Inclusive ( null) ) ,
97+ }
98+ }
99+ None => Ok ( types:: RangeBound :: Unbounded ) ,
100+ }
101+
102+ }
103+
123104#[ cfg( test) ]
124105mod test {
125106 use std:: fmt;
126107
127- use postgres:: { Connection , SslMode } ;
108+ use postgres:: { Connection , TlsMode } ;
128109 use postgres:: types:: { FromSql , ToSql } ;
129110 use time:: { self , Timespec } ;
130111
@@ -150,7 +131,7 @@ mod test {
150131 }
151132
152133 fn test_type < T : PartialEq +FromSql +ToSql , S : fmt:: Display > ( sql_type : & str , checks : & [ ( T , S ) ] ) {
153- let conn = Connection :: connect ( "postgres://postgres@localhost" , SslMode :: None ) . unwrap ( ) ;
134+ let conn = Connection :: connect ( "postgres://postgres@localhost" , TlsMode :: None ) . unwrap ( ) ;
154135 for & ( ref val, ref repr) in checks {
155136 let stmt = conn. prepare ( & * format ! ( "SELECT {}::{}" , * repr, sql_type) ) . unwrap ( ) ;
156137 let result = stmt. query ( & [ ] ) . unwrap ( ) . iter ( ) . next ( ) . unwrap ( ) . get ( 0 ) ;
0 commit comments