1- use std:: old_io:: ByRefReader ;
2- use std:: old_io:: util:: LimitReader ;
31use std:: iter:: MultiplicativeIterator ;
2+ use std:: io:: prelude:: * ;
3+ use byteorder:: { ReadBytesExt , WriteBytesExt , BigEndian } ;
44
5- use time:: Timespec ;
6- use serialize:: json:: Json ;
7- use postgres:: { self , Error } ;
8- use postgres:: types:: { RawFromSql , ToSql , RawToSql , Type , Oid } ;
5+ use postgres:: { self , Error , Type , Kind , ToSql , FromSql , Oid } ;
6+ use postgres:: types:: { IsNull } ;
97
108use { Array , ArrayBase , DimensionInfo } ;
119
12- macro_rules! check_types {
13- ( $actual: ident, $( $expected: pat) ,+) => (
14- match $actual {
15- $( & $expected) |+ => { }
16- actual => return Err ( :: postgres:: Error :: WrongType ( actual. clone( ) ) )
17- }
18- )
19- }
20-
21- macro_rules! from_sql_impl {
22- ( $t: ty, $( $oid: pat) ,+) => {
23- impl :: postgres:: FromSql for Option <:: ArrayBase <Option <$t>>> {
24- fn from_sql( ty: & :: postgres:: Type , raw: Option <& [ u8 ] >) -> :: postgres:: Result <Self > {
25- check_types!( ty, $( $oid) ,+) ;
26-
27- match raw {
28- Some ( mut raw) => :: postgres:: types:: RawFromSql :: raw_from_sql( ty, & mut raw) . map( Some ) ,
29- None => Ok ( None ) ,
30- }
31- }
32- }
33-
34- impl :: postgres:: FromSql for :: ArrayBase <Option <$t>> {
35- fn from_sql( ty: & :: postgres:: Type , raw: Option <& [ u8 ] >) -> :: postgres:: Result <Self > {
36- let v: :: postgres:: Result <Option <Self >> = :: postgres:: FromSql :: from_sql( ty, raw) ;
37- match v {
38- Ok ( None ) => Err ( :: postgres:: Error :: WasNull ) ,
39- Ok ( Some ( v) ) => Ok ( v) ,
40- Err ( err) => Err ( err) ,
41- }
42- }
43- }
44- }
45- }
46-
47- macro_rules! to_sql_impl {
48- ( $t: ty, $( $oid: pat) ,+) => {
49- impl :: postgres:: ToSql for :: ArrayBase <Option <$t>> {
50- fn to_sql( & self , ty: & :: postgres:: Type ) -> :: postgres:: Result <Option <Vec <u8 >>> {
51- check_types!( ty, $( $oid) ,+) ;
52- Ok ( Some ( :: impls:: raw_to_array( self , ty) ) )
53- }
54- }
55-
56- impl :: postgres:: ToSql for Option <:: ArrayBase <Option <$t>>> {
57- fn to_sql( & self , ty: & :: postgres:: Type ) -> :: postgres:: Result <Option <Vec <u8 >>> {
58- check_types!( ty, $( $oid) ,+) ;
59- match * self {
60- Some ( ref arr) => arr. to_sql( ty) ,
61- None => Ok ( None )
62- }
63- }
64- }
65- }
66- }
67-
68-
69- #[ cfg( feature = "uuid" ) ]
70- mod uuid;
10+ impl < T > FromSql for ArrayBase < Option < T > > where T : FromSql {
11+ fn from_sql < R : Read > ( ty : & Type , raw : & mut R ) -> postgres:: Result < ArrayBase < Option < T > > > {
12+ let element_type = match ty. kind ( ) {
13+ & Kind :: Array ( ref ty) => ty,
14+ _ => panic ! ( "unexpected type {:?}" , ty) ,
15+ } ;
7116
72- impl < T > RawFromSql for ArrayBase < Option < T > > where T : RawFromSql {
73- fn raw_from_sql < R : Reader > ( ty : & Type , raw : & mut R ) -> postgres:: Result < ArrayBase < Option < T > > > {
74- let ndim = try!( raw. read_be_u32 ( ) ) as usize ;
75- let _has_null = try!( raw. read_be_i32 ( ) ) == 1 ;
76- let _element_type: Oid = try!( raw. read_be_u32 ( ) ) ;
17+ let ndim = try!( raw. read_u32 :: < BigEndian > ( ) ) as usize ;
18+ let _has_null = try!( raw. read_i32 :: < BigEndian > ( ) ) == 1 ;
19+ let _element_type: Oid = try!( raw. read_u32 :: < BigEndian > ( ) ) ;
7720
7821 let mut dim_info = Vec :: with_capacity ( ndim) ;
7922 for _ in range ( 0 , ndim) {
8023 dim_info. push ( DimensionInfo {
81- len : try!( raw. read_be_u32 ( ) ) as usize ,
82- lower_bound : try!( raw. read_be_i32 ( ) ) as isize ,
24+ len : try!( raw. read_u32 :: < BigEndian > ( ) ) as usize ,
25+ lower_bound : try!( raw. read_i32 :: < BigEndian > ( ) ) as isize ,
8326 } ) ;
8427 }
8528 let nele = if dim_info. len ( ) == 0 {
@@ -90,75 +33,71 @@ impl<T> RawFromSql for ArrayBase<Option<T>> where T: RawFromSql {
9033
9134 let mut elements = Vec :: with_capacity ( nele) ;
9235 for _ in range ( 0 , nele) {
93- let len = try!( raw. read_be_i32 ( ) ) ;
36+ let len = try!( raw. read_i32 :: < BigEndian > ( ) ) ;
9437 if len < 0 {
9538 elements. push ( None ) ;
9639 } else {
97- let mut limit = LimitReader :: new ( raw. by_ref ( ) , len as usize ) ;
98- elements. push ( Some ( try!( RawFromSql :: raw_from_sql ( & ty. element_type ( ) . unwrap ( ) ,
99- & mut limit) ) ) ) ;
40+ let mut limit = raw. take ( len as u64 ) ;
41+ elements. push ( Some ( try!( FromSql :: from_sql ( & element_type, & mut limit) ) ) ) ;
10042 if limit. limit ( ) != 0 {
101- return Err ( Error :: BadData ) ;
43+ return Err ( Error :: BadResponse ) ;
10244 }
10345 }
10446 }
10547
10648 Ok ( ArrayBase :: from_raw ( elements, dim_info) )
10749 }
108- }
10950
110- from_sql_impl ! ( bool , Type :: BoolArray ) ;
111- from_sql_impl ! ( Vec <u8 >, Type :: ByteAArray ) ;
112- from_sql_impl ! ( i8 , Type :: CharArray ) ;
113- from_sql_impl ! ( i16 , Type :: Int2Array ) ;
114- from_sql_impl ! ( i32 , Type :: Int4Array ) ;
115- from_sql_impl ! ( String , Type :: TextArray , Type :: CharNArray , Type :: VarcharArray , Type :: NameArray ) ;
116- from_sql_impl ! ( i64 , Type :: Int8Array ) ;
117- from_sql_impl ! ( Json , Type :: JsonArray ) ;
118- from_sql_impl ! ( f32 , Type :: Float4Array ) ;
119- from_sql_impl ! ( f64 , Type :: Float8Array ) ;
120- from_sql_impl ! ( Timespec , Type :: TimestampArray , Type :: TimestampTZArray ) ;
121-
122- fn raw_to_array < T > ( array : & ArrayBase < Option < T > > , ty : & Type ) -> Vec < u8 > where T : RawToSql {
123- let mut buf = vec ! [ ] ;
124-
125- let _ = buf. write_be_i32 ( array. dimension_info ( ) . len ( ) as i32 ) ;
126- let _ = buf. write_be_i32 ( 1 ) ;
127- let _ = buf. write_be_u32 ( ty. element_type ( ) . unwrap ( ) . to_oid ( ) ) ;
128-
129- for info in array. dimension_info ( ) . iter ( ) {
130- let _ = buf. write_be_i32 ( info. len as i32 ) ;
131- let _ = buf. write_be_i32 ( info. lower_bound as i32 ) ;
51+ fn accepts ( ty : & Type ) -> bool {
52+ match ty. kind ( ) {
53+ & Kind :: Array ( ref ty) => <T as FromSql >:: accepts ( ty) ,
54+ _ => false
55+ }
13256 }
57+ }
13358
134- for v in array. values ( ) {
135- match * v {
136- Some ( ref val) => {
137- let mut inner_buf = vec ! [ ] ;
138- let _ = val. raw_to_sql ( & ty. element_type ( ) . unwrap ( ) , & mut inner_buf) ;
139- let _ = buf. write_be_i32 ( inner_buf. len ( ) as i32 ) ;
140- let _ = buf. write_all ( & * inner_buf) ;
141- }
142- None => {
143- let _ = buf. write_be_i32 ( -1 ) ;
59+ impl < T > ToSql for ArrayBase < Option < T > > where T : ToSql {
60+ fn to_sql < W : ?Sized +Write > ( & self , ty : & Type , mut w : & mut W ) -> postgres:: Result < IsNull > {
61+ let element_type = match ty. kind ( ) {
62+ & Kind :: Array ( ref ty) => ty,
63+ _ => panic ! ( "unexpected type {:?}" , ty) ,
64+ } ;
65+
66+ try!( w. write_u32 :: < BigEndian > ( self . dimension_info ( ) . len ( ) as u32 ) ) ;
67+ try!( w. write_i32 :: < BigEndian > ( 1 ) ) ;
68+ try!( w. write_u32 :: < BigEndian > ( element_type. to_oid ( ) ) ) ;
69+
70+ for info in self . dimension_info ( ) {
71+ try!( w. write_u32 :: < BigEndian > ( info. len as u32 ) ) ;
72+ try!( w. write_i32 :: < BigEndian > ( info. lower_bound as i32 ) ) ;
73+ }
74+
75+ for v in self . values ( ) {
76+ match * v {
77+ Some ( ref val) => {
78+ let mut inner_buf = vec ! [ ] ;
79+ try!( val. to_sql ( element_type, & mut inner_buf) ) ;
80+ try!( w. write_i32 :: < BigEndian > ( inner_buf. len ( ) as i32 ) ) ;
81+ try!( w. write_all ( & inner_buf) ) ;
82+ }
83+ None => {
84+ try!( w. write_i32 :: < BigEndian > ( -1 ) ) ;
85+ }
14486 }
14587 }
88+
89+ Ok ( IsNull :: No )
14690 }
14791
148- buf
149- }
92+ fn accepts ( ty : & Type ) -> bool {
93+ match ty. kind ( ) {
94+ & Kind :: Array ( ref ty) => <T as ToSql >:: accepts ( ty) ,
95+ _ => false
96+ }
97+ }
15098
151- to_sql_impl ! ( bool , Type :: BoolArray ) ;
152- to_sql_impl ! ( Vec <u8 >, Type :: ByteAArray ) ;
153- to_sql_impl ! ( i8 , Type :: CharArray ) ;
154- to_sql_impl ! ( i16 , Type :: Int2Array ) ;
155- to_sql_impl ! ( i32 , Type :: Int4Array ) ;
156- to_sql_impl ! ( i64 , Type :: Int8Array ) ;
157- to_sql_impl ! ( String , Type :: TextArray , Type :: CharNArray , Type :: VarcharArray , Type :: NameArray ) ;
158- to_sql_impl ! ( f32 , Type :: Float4Array ) ;
159- to_sql_impl ! ( f64 , Type :: Float8Array ) ;
160- to_sql_impl ! ( Json , Type :: JsonArray ) ;
161- to_sql_impl ! ( Timespec , Type :: TimestampArray , Type :: TimestampTZArray ) ;
99+ to_sql_checked ! ( ) ;
100+ }
162101
163102#[ cfg( test) ]
164103mod test {
@@ -170,12 +109,12 @@ mod test {
170109 fn test_type < T : PartialEq +FromSql +ToSql , S : fmt:: Display > ( sql_type : & str , checks : & [ ( T , S ) ] ) {
171110 let conn = Connection :: connect ( "postgres://postgres@localhost" , & SslMode :: None ) . unwrap ( ) ;
172111 for & ( ref val, ref repr) in checks. iter ( ) {
173- let stmt = conn. prepare ( & format ! ( "SELECT {}::{}" , * repr, sql_type) [ ] ) . unwrap ( ) ;
174- let result = stmt. query ( & [ ] ) . unwrap ( ) . next ( ) . unwrap ( ) . get ( 0 ) ;
112+ let stmt = conn. prepare ( & format ! ( "SELECT {}::{}" , * repr, sql_type) ) . unwrap ( ) ;
113+ let result = stmt. query ( & [ ] ) . unwrap ( ) . iter ( ) . next ( ) . unwrap ( ) . get ( 0 ) ;
175114 assert ! ( val == & result) ;
176115
177- let stmt = conn. prepare ( & format ! ( "SELECT $1::{}" , sql_type) [ ] ) . unwrap ( ) ;
178- let result = stmt. query ( & [ val] ) . unwrap ( ) . next ( ) . unwrap ( ) . get ( 0 ) ;
116+ let stmt = conn. prepare ( & format ! ( "SELECT $1::{}" , sql_type) ) . unwrap ( ) ;
117+ let result = stmt. query ( & [ val] ) . unwrap ( ) . iter ( ) . next ( ) . unwrap ( ) . get ( 0 ) ;
179118 assert ! ( val == & result) ;
180119 }
181120 }
@@ -186,13 +125,13 @@ mod test {
186125 let tests = & [ ( Some ( ArrayBase :: from_vec( vec!( Some ( $v1) , Some ( $v2) , None ) , 1 ) ) ,
187126 format!( "'{{{},{},NULL}}'" , $s1, $s2) ) ,
188127 ( None , "NULL" . to_string( ) ) ] ;
189- test_type( & format!( "{}[]" , $name) [ ] , tests) ;
128+ test_type( & format!( "{}[]" , $name) , tests) ;
190129 let mut a = ArrayBase :: from_vec( vec!( Some ( $v1) , Some ( $v2) ) , 0 ) ;
191130 a. wrap( -1 ) ;
192131 a. push_move( ArrayBase :: from_vec( vec!( None , Some ( $v3) ) , 0 ) ) ;
193132 let tests = & [ ( Some ( a) , format!( "'[-1:0][0:1]={{{{{},{}}},{{NULL,{}}}}}'" ,
194133 $s1, $s2, $s3) ) ] ;
195- test_type( & format!( "{}[][]" , $name) [ ] , tests) ;
134+ test_type( & format!( "{}[][]" , $name) , tests) ;
196135 } )
197136 }
198137
@@ -266,6 +205,6 @@ mod test {
266205 fn test_empty_array ( ) {
267206 let conn = Connection :: connect ( "postgres://postgres@localhost" , & SslMode :: None ) . unwrap ( ) ;
268207 let stmt = conn. prepare ( "SELECT '{}'::INT4[]" ) . unwrap ( ) ;
269- stmt. query ( & [ ] ) . unwrap ( ) . next ( ) . unwrap ( ) . get :: < _ , ArrayBase < Option < i32 > > > ( 0 ) ;
208+ stmt. query ( & [ ] ) . unwrap ( ) . iter ( ) . next ( ) . unwrap ( ) . get :: < _ , ArrayBase < Option < i32 > > > ( 0 ) ;
270209 }
271210}
0 commit comments