1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
extern crate byteorder; use self::byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use std::error::Error; use std::io::Write; use Queriable; use super::option::UnexpectedNullError; use types::{NativeSqlType, FromSql, ToSql, Array, IsNull}; impl<T: NativeSqlType> NativeSqlType for Array<T> { fn oid(&self) -> u32 { self.0.array_oid() } fn array_oid(&self) -> u32 { 0 } fn new() -> Self { Array(T::new()) } } impl<T, ST> FromSql<Array<ST>> for Vec<T> where T: FromSql<ST>, ST: NativeSqlType, { fn from_sql(bytes: Option<&[u8]>) -> Result<Self, Box<Error>> { let mut bytes = not_none!(bytes); let num_dimensions = try!(bytes.read_i32::<BigEndian>()); let has_null = try!(bytes.read_i32::<BigEndian>()) != 0; let _oid = try!(bytes.read_i32::<BigEndian>()); if num_dimensions == 0 { return Ok(Vec::new()) } let num_elements = try!(bytes.read_i32::<BigEndian>()); let lower_bound = try!(bytes.read_i32::<BigEndian>()); assert!(num_dimensions == 1, "multi-dimensional arrays are not supported"); assert!(lower_bound == 1, "lower bound must be 1"); (0..num_elements).map(|_| { let elem_size = try!(bytes.read_i32::<BigEndian>()); if has_null && elem_size == -1 { T::from_sql(None) } else { let (elem_bytes, new_bytes) = bytes.split_at(elem_size as usize); bytes = new_bytes; T::from_sql(Some(&elem_bytes)) } }).collect() } } impl<T, ST> Queriable<Array<ST>> for Vec<T> where T: FromSql<ST> + Queriable<ST>, ST: NativeSqlType, { type Row = Self; fn build(row: Self) -> Self { row } } use expression::AsExpression; use expression::bound::Bound; impl<'a, ST, T> AsExpression<Array<ST>> for &'a [T] where ST: NativeSqlType, T: ToSql<ST>, { type Expression = Bound<Array<ST>, Self>; fn as_expression(self) -> Self::Expression { Bound::new(self) } } impl<ST, T> AsExpression<Array<ST>> for Vec<T> where ST: NativeSqlType, T: ToSql<ST>, { type Expression = Bound<Array<ST>, Self>; fn as_expression(self) -> Self::Expression { Bound::new(self) } } impl<'a, ST, T> AsExpression<Array<ST>> for &'a Vec<T> where ST: NativeSqlType, T: ToSql<ST>, { type Expression = Bound<Array<ST>, Self>; fn as_expression(self) -> Self::Expression { Bound::new(self) } } impl<'a, ST, T> ToSql<Array<ST>> for &'a [T] where ST: NativeSqlType, T: ToSql<ST>, { fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error>> { let num_dimensions = 1; try!(out.write_i32::<BigEndian>(num_dimensions)); let flags = 0; try!(out.write_i32::<BigEndian>(flags)); try!(out.write_u32::<BigEndian>(ST::new().oid())); try!(out.write_i32::<BigEndian>(self.len() as i32)); let lower_bound = 1; try!(out.write_i32::<BigEndian>(lower_bound)); let mut buffer = Vec::new(); for elem in self.iter() { let is_null = try!(elem.to_sql(&mut buffer)); assert!(is_null == IsNull::No, "Arrays containing null are not supported"); try!(out.write_i32::<BigEndian>(buffer.len() as i32)); try!(out.write_all(&buffer)); buffer.clear(); } Ok(IsNull::No) } } impl<ST, T> ToSql<Array<ST>> for Vec<T> where ST: NativeSqlType, T: ToSql<ST>, { fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error>> { (&self as &[T]).to_sql(out) } }