use std::collections::HashMap;
use std::error;
use std::fmt;
use std::io::prelude::*;
use std::sync::Arc;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
pub use self::slice::Slice;
use {Result, SessionInfoNew, InnerConnection, OtherNew, WrongTypeNew, FieldNew};
use error::Error;
use util;
#[macro_export]
macro_rules! accepts {
($($expected:pat),+) => (
fn accepts(ty: &$crate::types::Type) -> bool {
match *ty {
$($expected)|+ => true,
_ => false
}
}
)
}
#[macro_export]
macro_rules! to_sql_checked {
() => {
fn to_sql_checked(&self,
ty: &$crate::types::Type,
out: &mut ::std::io::Write,
ctx: &$crate::types::SessionInfo)
-> $crate::Result<$crate::types::IsNull> {
$crate::types::__to_sql_checked(self, ty, out, ctx)
}
}
}
#[doc(hidden)]
pub fn __to_sql_checked<T>(v: &T, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>
where T: ToSql
{
if !T::accepts(ty) {
return Err(Error::Conversion(Box::new(WrongType(ty.clone()))));
}
v.to_sql(ty, out, ctx)
}
#[cfg(feature = "bit-vec")]
mod bit_vec;
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(feature = "time")]
mod time;
mod slice;
#[cfg(feature = "rustc-serialize")]
mod rustc_serialize;
#[cfg(feature = "serde_json")]
mod serde_json;
#[cfg(feature = "chrono")]
mod chrono;
#[cfg(feature = "eui48")]
mod eui48;
pub struct SessionInfo<'a> {
conn: &'a InnerConnection,
}
impl<'a> SessionInfoNew<'a> for SessionInfo<'a> {
fn new(conn: &'a InnerConnection) -> SessionInfo<'a> {
SessionInfo { conn: conn }
}
}
impl<'a> SessionInfo<'a> {
pub fn parameter(&self, param: &str) -> Option<&'a str> {
self.conn.parameters.get(param).map(|s| &**s)
}
}
impl<'a> fmt::Debug for SessionInfo<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SessionInfo")
.field("parameters", &self.conn.parameters)
.finish()
}
}
pub type Oid = u32;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Kind {
Simple,
Enum(Vec<String>),
Pseudo,
Array(Type),
Range(Type),
Domain(Type),
Composite(Vec<Field>),
#[doc(hidden)]
__PseudoPrivateForExtensibility,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Field {
name: String,
type_: Type,
}
impl Field {
pub fn name(&self) -> &str {
&self.name
}
pub fn type_(&self) -> &Type {
&self.type_
}
}
impl FieldNew for Field {
fn new(name: String, type_: Type) -> Field {
Field {
name: name,
type_: type_,
}
}
}
macro_rules! as_pat {
($p:pat) => ($p)
}
macro_rules! as_expr {
($e:expr) => ($e)
}
macro_rules! make_postgres_type {
($(#[$doc:meta] $oid:tt: $name:expr => $variant:ident: $kind:expr),+) => (
#[derive(PartialEq, Eq, Clone)]
pub enum Type {
$(
#[$doc]
$variant,
)+
Other(Other),
}
impl fmt::Debug for Type {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
$(Type::$variant => stringify!($variant),)+
Type::Other(ref u) => return fmt::Debug::fmt(u, fmt),
};
fmt.write_str(s)
}
}
impl fmt::Display for Type {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self.schema() {
"public" | "pg_catalog" => {}
schema => try!(write!(fmt, "{}.", schema)),
}
fmt.write_str(self.name())
}
}
impl Type {
pub fn from_oid(oid: Oid) -> Option<Type> {
match oid {
$(as_pat!($oid) => Some(Type::$variant),)+
_ => None
}
}
pub fn oid(&self) -> Oid {
match *self {
$(Type::$variant => as_expr!($oid),)+
Type::Other(ref u) => u.oid(),
}
}
pub fn kind(&self) -> &Kind {
match *self {
$(
Type::$variant => {
const V: &'static Kind = &$kind;
V
}
)+
Type::Other(ref u) => u.kind(),
}
}
pub fn schema(&self) -> &str {
match *self {
Type::Other(ref u) => u.schema(),
_ => "pg_catalog",
}
}
pub fn name(&self) -> &str {
match *self {
$(
Type::$variant => $name,
)+
Type::Other(ref u) => u.name(),
}
}
}
)
}
make_postgres_type! {
16: "bool" => Bool: Kind::Simple,
17: "bytea" => Bytea: Kind::Simple,
18: "char" => Char: Kind::Simple,
19: "name" => Name: Kind::Simple,
20: "int8" => Int8: Kind::Simple,
21: "int2" => Int2: Kind::Simple,
22: "int2vector" => Int2Vector: Kind::Array(Type::Int2),
23: "int4" => Int4: Kind::Simple,
24: "regproc" => Regproc: Kind::Simple,
25: "text" => Text: Kind::Simple,
26: "oid" => Oid: Kind::Simple,
27: "tid" => Tid: Kind::Simple,
28: "xid" => Xid: Kind::Simple,
29: "cid" => Cid: Kind::Simple,
30: "oidvector" => OidVector: Kind::Array(Type::Oid),
71: "pg_type" => PgType: Kind::Simple,
75: "pg_attribute" => PgAttribute: Kind::Simple,
81: "pg_proc" => PgProc: Kind::Simple,
83: "pg_class" => PgClass: Kind::Simple,
114: "json" => Json: Kind::Simple,
142: "xml" => Xml: Kind::Simple,
143: "_xml" => XmlArray: Kind::Array(Type::Xml),
194: "pg_node_tree" => PgNodeTree: Kind::Simple,
199: "_json" => JsonArray: Kind::Array(Type::Json),
210: "smgr" => Smgr: Kind::Simple,
600: "point" => Point: Kind::Simple,
601: "lseg" => Lseg: Kind::Simple,
602: "path" => Path: Kind::Simple,
603: "box" => Box: Kind::Simple,
604: "polygon" => Polygon: Kind::Simple,
628: "line" => Line: Kind::Simple,
629: "_line" => LineArray: Kind::Array(Type::Line),
650: "cidr" => Cidr: Kind::Simple,
651: "_cidr" => CidrArray: Kind::Array(Type::Cidr),
700: "float4" => Float4: Kind::Simple,
701: "float8" => Float8: Kind::Simple,
702: "abstime" => Abstime: Kind::Simple,
703: "reltime" => Reltime: Kind::Simple,
704: "tinterval" => Tinterval: Kind::Simple,
705: "unknown" => Unknown: Kind::Simple,
718: "circle" => Circle: Kind::Simple,
719: "_circle" => CircleArray: Kind::Array(Type::Circle),
790: "money" => Money: Kind::Simple,
791: "_money" => MoneyArray: Kind::Array(Type::Money),
829: "macaddr" => Macaddr: Kind::Simple,
869: "inet" => Inet: Kind::Simple,
1000: "_bool" => BoolArray: Kind::Array(Type::Bool),
1001: "_bytea" => ByteaArray: Kind::Array(Type::Bytea),
1002: "_char" => CharArray: Kind::Array(Type::Char),
1003: "_name" => NameArray: Kind::Array(Type::Name),
1005: "_int2" => Int2Array: Kind::Array(Type::Int2),
1006: "_int2vector" => Int2VectorArray: Kind::Array(Type::Int2Vector),
1007: "_int4" => Int4Array: Kind::Array(Type::Int4),
1008: "_regproc" => RegprocArray: Kind::Array(Type::Regproc),
1009: "_text" => TextArray: Kind::Array(Type::Text),
1010: "_tid" => TidArray: Kind::Array(Type::Tid),
1011: "_xid" => XidArray: Kind::Array(Type::Xid),
1012: "_cid" => CidArray: Kind::Array(Type::Cid),
1013: "_oidvector" => OidVectorArray: Kind::Array(Type::OidVector),
1014: "_bpchar" => BpcharArray: Kind::Array(Type::Bpchar),
1015: "_varchar" => VarcharArray: Kind::Array(Type::Varchar),
1016: "_int8" => Int8Array: Kind::Array(Type::Int8),
1017: "_point" => PointArray: Kind::Array(Type::Point),
1018: "_lseg" => LsegArray: Kind::Array(Type::Lseg),
1019: "_path" => PathArray: Kind::Array(Type::Path),
1020: "_box" => BoxArray: Kind::Array(Type::Box),
1021: "_float4" => Float4Array: Kind::Array(Type::Float4),
1022: "_float8" => Float8Array: Kind::Array(Type::Float8),
1023: "_abstime" => AbstimeArray: Kind::Array(Type::Abstime),
1024: "_reltime" => ReltimeArray: Kind::Array(Type::Reltime),
1025: "_tinterval" => TintervalArray: Kind::Array(Type::Tinterval),
1027: "_polygon" => PolygonArray: Kind::Array(Type::Polygon),
1028: "_oid" => OidArray: Kind::Array(Type::Oid),
1033: "aclitem" => Aclitem: Kind::Simple,
1034: "_aclitem" => AclitemArray: Kind::Array(Type::Aclitem),
1040: "_macaddr" => MacaddrArray: Kind::Array(Type::Macaddr),
1041: "_inet" => InetArray: Kind::Array(Type::Inet),
1042: "bpchar" => Bpchar: Kind::Simple,
1043: "varchar" => Varchar: Kind::Simple,
1082: "date" => Date: Kind::Simple,
1083: "time" => Time: Kind::Simple,
1114: "timestamp" => Timestamp: Kind::Simple,
1115: "_timestamp" => TimestampArray: Kind::Array(Type::Timestamp),
1182: "_date" => DateArray: Kind::Array(Type::Date),
1183: "_time" => TimeArray: Kind::Array(Type::Time),
1184: "timestamptz" => TimestampTZ: Kind::Simple,
1185: "_timestamptz" => TimestampTZArray: Kind::Array(Type::TimestampTZ),
1186: "interval" => Interval: Kind::Simple,
1187: "_interval" => IntervalArray: Kind::Array(Type::Interval),
1231: "_numeric" => NumericArray: Kind::Array(Type::Numeric),
1263: "_cstring" => CstringArray: Kind::Array(Type::Cstring),
1266: "timetz" => Timetz: Kind::Simple,
1270: "_timetz" => TimetzArray: Kind::Array(Type::Timetz),
1560: "bit" => Bit: Kind::Simple,
1561: "_bit" => BitArray: Kind::Array(Type::Bit),
1562: "varbit" => Varbit: Kind::Simple,
1563: "_varbit" => VarbitArray: Kind::Array(Type::Varbit),
1700: "numeric" => Numeric: Kind::Simple,
1790: "refcursor" => Refcursor: Kind::Simple,
2201: "_refcursor" => RefcursorArray: Kind::Array(Type::Refcursor),
2202: "regprocedure" => Regprocedure: Kind::Simple,
2203: "regoper" => Regoper: Kind::Simple,
2204: "regoperator" => Regoperator: Kind::Simple,
2205: "regclass" => Regclass: Kind::Simple,
2206: "regtype" => Regtype: Kind::Simple,
2207: "_regprocedure" => RegprocedureArray: Kind::Array(Type::Regprocedure),
2208: "_regoper" => RegoperArray: Kind::Array(Type::Regoper),
2209: "_regoperator" => RegoperatorArray: Kind::Array(Type::Regoperator),
2210: "_regclass" => RegclassArray: Kind::Array(Type::Regclass),
2211: "_regtype" => RegtypeArray: Kind::Array(Type::Regtype),
2249: "record" => Record: Kind::Pseudo,
2275: "cstring" => Cstring: Kind::Pseudo,
2276: "any" => Any: Kind::Pseudo,
2277: "anyarray" => AnyArray: Kind::Pseudo,
2278: "void" => Void: Kind::Pseudo,
2279: "trigger" => Trigger: Kind::Pseudo,
2280: "language_handler" => LanguageHandler: Kind::Pseudo,
2281: "internal" => Internal: Kind::Pseudo,
2282: "opaque" => Opaque: Kind::Pseudo,
2283: "anyelement" => Anyelement: Kind::Pseudo,
2287: "_record" => RecordArray: Kind::Pseudo,
2776: "anynonarray" => Anynonarray: Kind::Pseudo,
2949: "_txid_snapshot" => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
2950: "uuid" => Uuid: Kind::Simple,
2970: "txid_snapshot" => TxidSnapshot: Kind::Simple,
2951: "_uuid" => UuidArray: Kind::Array(Type::Uuid),
3115: "fdw_handler" => FdwHandler: Kind::Pseudo,
3220: "pg_lsn" => PgLsn: Kind::Simple,
3221: "_pg_lsn" => PgLsnArray: Kind::Array(Type::PgLsn),
3500: "anyenum" => Anyenum: Kind::Pseudo,
3614: "tsvector" => Tsvector: Kind::Simple,
3615: "tsquery" => Tsquery: Kind::Simple,
3642: "gtsvector" => Gtsvector: Kind::Simple,
3643: "_tsvector" => TsvectorArray: Kind::Array(Type::Tsvector),
3644: "_gtsvector" => GtsvectorArray: Kind::Array(Type::Gtsvector),
3645: "_tsquery" => TsqueryArray: Kind::Array(Type::Tsquery),
3734: "regconfig" => Regconfig: Kind::Simple,
3735: "_regconfig" => RegconfigArray: Kind::Array(Type::Regconfig),
3769: "regdictionary" => Regdictionary: Kind::Simple,
3770: "_regdictionary" => RegdictionaryArray: Kind::Array(Type::Regdictionary),
3802: "jsonb" => Jsonb: Kind::Simple,
3831: "anyrange" => Anyrange: Kind::Pseudo,
3807: "_jsonb" => JsonbArray: Kind::Array(Type::Jsonb),
3904: "int4range" => Int4Range: Kind::Range(Type::Int4),
3905: "_int4range" => Int4RangeArray: Kind::Array(Type::Int4Range),
3906: "numrange" => NumRange: Kind::Range(Type::Numeric),
3907: "_numrange" => NumRangeArray: Kind::Array(Type::NumRange),
3908: "tsrange" => TsRange: Kind::Range(Type::Timestamp),
3909: "_tsrange" => TsRangeArray: Kind::Array(Type::TsRange),
3910: "tstzrange" => TstzRange: Kind::Range(Type::TimestampTZ),
3911: "_tstzrange" => TstzRangeArray: Kind::Array(Type::TstzRange),
3912: "daterange" => DateRange: Kind::Range(Type::Date),
3913: "_daterange" => DateRangeArray: Kind::Array(Type::DateRange),
3926: "int8range" => Int8Range: Kind::Range(Type::Int8),
3927: "_int8range" => Int8RangeArray: Kind::Array(Type::Int8Range),
3838: "event_trigger" => EventTrigger: Kind::Pseudo
}
#[derive(PartialEq, Eq, Clone)]
pub struct Other(Arc<OtherInner>);
impl fmt::Debug for Other {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Other")
.field("name", &self.0.name)
.field("oid", &self.0.oid)
.field("kind", &self.0.kind)
.field("schema", &self.0.schema)
.finish()
}
}
#[derive(PartialEq, Eq)]
struct OtherInner {
name: String,
oid: Oid,
kind: Kind,
schema: String,
}
impl OtherNew for Other {
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other {
Other(Arc::new(OtherInner {
name: name,
oid: oid,
kind: kind,
schema: schema,
}))
}
}
impl Other {
pub fn name(&self) -> &str {
&self.0.name
}
pub fn oid(&self) -> Oid {
self.0.oid
}
pub fn kind(&self) -> &Kind {
&self.0.kind
}
pub fn schema(&self) -> &str {
&self.0.schema
}
}
#[derive(Debug, Clone, Copy)]
pub struct WasNull;
impl fmt::Display for WasNull {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(error::Error::description(self))
}
}
impl error::Error for WasNull {
fn description(&self) -> &str {
"a Postgres value was `NULL`"
}
}
#[derive(Debug)]
pub struct WrongType(Type);
impl fmt::Display for WrongType {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt,
"cannot convert to or from a Postgres value of type `{}`",
self.0)
}
}
impl error::Error for WrongType {
fn description(&self) -> &str {
"cannot convert to or from a Postgres value"
}
}
impl WrongTypeNew for WrongType {
fn new(ty: Type) -> WrongType {
WrongType(ty)
}
}
pub trait FromSql: Sized {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self>;
#[allow(unused_variables)]
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self> {
Err(Error::Conversion(Box::new(WasNull)))
}
fn accepts(ty: &Type) -> bool;
}
impl<T: FromSql> FromSql for Option<T> {
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Option<T>> {
<T as FromSql>::from_sql(ty, raw, ctx).map(Some)
}
fn from_sql_null(_: &Type, _: &SessionInfo) -> Result<Option<T>> {
Ok(None)
}
fn accepts(ty: &Type) -> bool {
<T as FromSql>::accepts(ty)
}
}
impl FromSql for bool {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<bool> {
Ok(try!(raw.read_u8()) != 0)
}
accepts!(Type::Bool);
}
impl FromSql for Vec<u8> {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Vec<u8>> {
let mut buf = vec![];
try!(raw.read_to_end(&mut buf));
Ok(buf)
}
accepts!(Type::Bytea);
}
impl FromSql for String {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<String> {
let mut buf = vec![];
try!(raw.read_to_end(&mut buf));
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
}
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Varchar | Type::Text | Type::Bpchar | Type::Name => true,
Type::Other(ref u) if u.name() == "citext" => true,
_ => false,
}
}
}
impl FromSql for i8 {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<i8> {
Ok(try!(raw.read_i8()))
}
accepts!(Type::Char);
}
macro_rules! primitive_from {
($t:ty, $f:ident, $($expected:pat),+) => {
impl FromSql for $t {
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<$t> {
Ok(try!(raw.$f::<BigEndian>()))
}
accepts!($($expected),+);
}
}
}
primitive_from!(i16, read_i16, Type::Int2);
primitive_from!(i32, read_i32, Type::Int4);
primitive_from!(u32, read_u32, Type::Oid);
primitive_from!(i64, read_i64, Type::Int8);
primitive_from!(f32, read_f32, Type::Float4);
primitive_from!(f64, read_f64, Type::Float8);
impl FromSql for HashMap<String, Option<String>> {
fn from_sql<R: Read>(_: &Type,
raw: &mut R,
_: &SessionInfo)
-> Result<HashMap<String, Option<String>>> {
let mut map = HashMap::new();
let count = try!(raw.read_i32::<BigEndian>());
for _ in 0..count {
let key_len = try!(raw.read_i32::<BigEndian>());
let mut key = vec![0; key_len as usize];
try!(util::read_all(raw, &mut key));
let key = match String::from_utf8(key) {
Ok(key) => key,
Err(err) => return Err(Error::Conversion(Box::new(err))),
};
let val_len = try!(raw.read_i32::<BigEndian>());
let val = if val_len < 0 {
None
} else {
let mut val = vec![0; val_len as usize];
try!(util::read_all(raw, &mut val));
match String::from_utf8(val) {
Ok(val) => Some(val),
Err(err) => return Err(Error::Conversion(Box::new(err))),
}
};
map.insert(key, val);
}
Ok(map)
}
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Other(ref u) if u.name() == "hstore" => true,
_ => false,
}
}
}
pub enum IsNull {
Yes,
No,
}
pub trait ToSql: fmt::Debug {
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
where Self: Sized,
W: Write;
fn accepts(ty: &Type) -> bool where Self: Sized;
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>;
}
impl<'a, T> ToSql for &'a T
where T: ToSql
{
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
(*self).to_sql(ty, out, ctx)
}
fn accepts(ty: &Type) -> bool {
T::accepts(ty)
}
}
impl<T: ToSql> ToSql for Option<T> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
ty: &Type,
out: &mut W,
ctx: &SessionInfo)
-> Result<IsNull> {
match *self {
Some(ref val) => val.to_sql(ty, out, ctx),
None => Ok(IsNull::Yes),
}
}
fn accepts(ty: &Type) -> bool {
<T as ToSql>::accepts(ty)
}
}
impl ToSql for bool {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_u8(*self as u8));
Ok(IsNull::No)
}
accepts!(Type::Bool);
}
impl<'a> ToSql for &'a [u8] {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(*self));
Ok(IsNull::No)
}
accepts!(Type::Bytea);
}
impl ToSql for Vec<u8> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
}
fn accepts(ty: &Type) -> bool {
<&[u8] as ToSql>::accepts(ty)
}
}
impl<'a> ToSql for &'a str {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
try!(w.write_all(self.as_bytes()));
Ok(IsNull::No)
}
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Varchar | Type::Text | Type::Bpchar | Type::Name => true,
Type::Other(ref u) if u.name() == "citext" => true,
_ => false,
}
}
}
impl ToSql for String {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
}
fn accepts(ty: &Type) -> bool {
<&str as ToSql>::accepts(ty)
}
}
impl ToSql for i8 {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_i8(*self));
Ok(IsNull::No)
}
accepts!(Type::Char);
}
macro_rules! to_primitive {
($t:ty, $f:ident, $($expected:pat),+) => {
impl ToSql for $t {
to_sql_checked!();
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
-> Result<IsNull> {
try!(w.$f::<BigEndian>(*self));
Ok(IsNull::No)
}
accepts!($($expected),+);
}
}
}
to_primitive!(i16, write_i16, Type::Int2);
to_primitive!(i32, write_i32, Type::Int4);
to_primitive!(u32, write_u32, Type::Oid);
to_primitive!(i64, write_i64, Type::Int8);
to_primitive!(f32, write_f32, Type::Float4);
to_primitive!(f64, write_f64, Type::Float8);
impl ToSql for HashMap<String, Option<String>> {
to_sql_checked!();
fn to_sql<W: Write + ?Sized>(&self,
_: &Type,
mut w: &mut W,
_: &SessionInfo)
-> Result<IsNull> {
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
for (key, val) in self {
try!(w.write_i32::<BigEndian>(try!(downcast(key.len()))));
try!(w.write_all(key.as_bytes()));
match *val {
Some(ref val) => {
try!(w.write_i32::<BigEndian>(try!(downcast(val.len()))));
try!(w.write_all(val.as_bytes()));
}
None => try!(w.write_i32::<BigEndian>(-1)),
}
}
Ok(IsNull::No)
}
fn accepts(ty: &Type) -> bool {
match *ty {
Type::Other(ref u) if u.name() == "hstore" => true,
_ => false,
}
}
}
fn downcast(len: usize) -> Result<i32> {
if len > i32::max_value() as usize {
let err: Box<error::Error + Sync + Send> = "value too large to transmit".into();
Err(Error::Conversion(err))
} else {
Ok(len as i32)
}
}