1
- use std:: old_io:: ByRefReader ;
2
- use std:: old_io:: util:: LimitReader ;
3
1
use std:: iter:: MultiplicativeIterator ;
2
+ use std:: io:: prelude:: * ;
3
+ use byteorder:: { ReadBytesExt , WriteBytesExt , BigEndian } ;
4
4
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 } ;
9
7
10
8
use { Array , ArrayBase , DimensionInfo } ;
11
9
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
+ } ;
71
16
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 > ( ) ) ;
77
20
78
21
let mut dim_info = Vec :: with_capacity ( ndim) ;
79
22
for _ in range ( 0 , ndim) {
80
23
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 ,
83
26
} ) ;
84
27
}
85
28
let nele = if dim_info. len ( ) == 0 {
@@ -90,75 +33,71 @@ impl<T> RawFromSql for ArrayBase<Option<T>> where T: RawFromSql {
90
33
91
34
let mut elements = Vec :: with_capacity ( nele) ;
92
35
for _ in range ( 0 , nele) {
93
- let len = try!( raw. read_be_i32 ( ) ) ;
36
+ let len = try!( raw. read_i32 :: < BigEndian > ( ) ) ;
94
37
if len < 0 {
95
38
elements. push ( None ) ;
96
39
} 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) ) ) ) ;
100
42
if limit. limit ( ) != 0 {
101
- return Err ( Error :: BadData ) ;
43
+ return Err ( Error :: BadResponse ) ;
102
44
}
103
45
}
104
46
}
105
47
106
48
Ok ( ArrayBase :: from_raw ( elements, dim_info) )
107
49
}
108
- }
109
50
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
+ }
132
56
}
57
+ }
133
58
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
+ }
144
86
}
145
87
}
88
+
89
+ Ok ( IsNull :: No )
146
90
}
147
91
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
+ }
150
98
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
+ }
162
101
163
102
#[ cfg( test) ]
164
103
mod test {
@@ -170,12 +109,12 @@ mod test {
170
109
fn test_type < T : PartialEq +FromSql +ToSql , S : fmt:: Display > ( sql_type : & str , checks : & [ ( T , S ) ] ) {
171
110
let conn = Connection :: connect ( "postgres://postgres@localhost" , & SslMode :: None ) . unwrap ( ) ;
172
111
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 ) ;
175
114
assert ! ( val == & result) ;
176
115
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 ) ;
179
118
assert ! ( val == & result) ;
180
119
}
181
120
}
@@ -186,13 +125,13 @@ mod test {
186
125
let tests = & [ ( Some ( ArrayBase :: from_vec( vec!( Some ( $v1) , Some ( $v2) , None ) , 1 ) ) ,
187
126
format!( "'{{{},{},NULL}}'" , $s1, $s2) ) ,
188
127
( None , "NULL" . to_string( ) ) ] ;
189
- test_type( & format!( "{}[]" , $name) [ ] , tests) ;
128
+ test_type( & format!( "{}[]" , $name) , tests) ;
190
129
let mut a = ArrayBase :: from_vec( vec!( Some ( $v1) , Some ( $v2) ) , 0 ) ;
191
130
a. wrap( -1 ) ;
192
131
a. push_move( ArrayBase :: from_vec( vec!( None , Some ( $v3) ) , 0 ) ) ;
193
132
let tests = & [ ( Some ( a) , format!( "'[-1:0][0:1]={{{{{},{}}},{{NULL,{}}}}}'" ,
194
133
$s1, $s2, $s3) ) ] ;
195
- test_type( & format!( "{}[][]" , $name) [ ] , tests) ;
134
+ test_type( & format!( "{}[][]" , $name) , tests) ;
196
135
} )
197
136
}
198
137
@@ -266,6 +205,6 @@ mod test {
266
205
fn test_empty_array ( ) {
267
206
let conn = Connection :: connect ( "postgres://postgres@localhost" , & SslMode :: None ) . unwrap ( ) ;
268
207
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 ) ;
270
209
}
271
210
}
0 commit comments