2013-10-20 21:34:50 +00:00
|
|
|
//! Traits dealing with Postgres data types
|
2015-02-13 06:52:55 +00:00
|
|
|
|
2014-06-06 03:50:23 +00:00
|
|
|
use std::collections::HashMap;
|
2015-05-23 04:20:56 +00:00
|
|
|
use std::error;
|
2015-01-09 18:50:54 +00:00
|
|
|
use std::fmt;
|
2015-02-26 17:02:32 +00:00
|
|
|
use std::io::prelude::*;
|
2016-01-03 04:07:33 +00:00
|
|
|
use std::sync::Arc;
|
2015-02-26 17:02:32 +00:00
|
|
|
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
2013-08-28 04:36:27 +00:00
|
|
|
|
2016-02-21 21:37:29 +00:00
|
|
|
pub use self::types::Type;
|
2016-06-24 23:03:20 +00:00
|
|
|
pub use self::special::{Date, Timestamp};
|
2016-02-16 07:11:01 +00:00
|
|
|
use {Result, SessionInfoNew, InnerConnection, OtherNew, WrongTypeNew, FieldNew};
|
2014-11-21 05:47:13 +00:00
|
|
|
use error::Error;
|
2013-10-29 06:55:11 +00:00
|
|
|
|
2015-03-04 04:44:47 +00:00
|
|
|
/// Generates a simple implementation of `ToSql::accepts` which accepts the
|
|
|
|
/// types passed to it.
|
2015-02-15 23:11:15 +00:00
|
|
|
#[macro_export]
|
2015-02-15 01:07:10 +00:00
|
|
|
macro_rules! accepts {
|
|
|
|
($($expected:pat),+) => (
|
2015-02-28 04:46:43 +00:00
|
|
|
fn accepts(ty: &$crate::types::Type) -> bool {
|
2015-02-15 01:07:10 +00:00
|
|
|
match *ty {
|
|
|
|
$($expected)|+ => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-03-04 04:44:47 +00:00
|
|
|
/// Generates an implementation of `ToSql::to_sql_checked`.
|
|
|
|
///
|
|
|
|
/// All `ToSql` implementations should use this macro.
|
2015-02-15 23:11:15 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! to_sql_checked {
|
|
|
|
() => {
|
2015-12-27 05:05:23 +00:00
|
|
|
fn to_sql_checked(&self,
|
|
|
|
ty: &$crate::types::Type,
|
|
|
|
out: &mut ::std::io::Write,
|
2015-05-22 05:28:51 +00:00
|
|
|
ctx: &$crate::types::SessionInfo)
|
2015-02-28 04:46:43 +00:00
|
|
|
-> $crate::Result<$crate::types::IsNull> {
|
2015-12-27 05:05:23 +00:00
|
|
|
$crate::types::__to_sql_checked(self, ty, out, ctx)
|
2014-11-17 17:43:10 +00:00
|
|
|
}
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
2014-12-19 18:43:42 +00:00
|
|
|
}
|
2014-12-15 00:43:17 +00:00
|
|
|
|
2015-12-27 05:05:23 +00:00
|
|
|
// WARNING: this function is not considered part of this crate's public API.
|
|
|
|
// It is subject to change at any time.
|
|
|
|
#[doc(hidden)]
|
2016-01-03 00:02:34 +00:00
|
|
|
pub fn __to_sql_checked<T>(v: &T, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>
|
2015-12-27 05:05:23 +00:00
|
|
|
where T: ToSql
|
|
|
|
{
|
|
|
|
if !T::accepts(ty) {
|
|
|
|
return Err(Error::Conversion(Box::new(WrongType(ty.clone()))));
|
|
|
|
}
|
|
|
|
v.to_sql(ty, out, ctx)
|
|
|
|
}
|
|
|
|
|
2015-12-06 20:40:00 +00:00
|
|
|
#[cfg(feature = "bit-vec")]
|
|
|
|
mod bit_vec;
|
2014-11-17 17:43:10 +00:00
|
|
|
#[cfg(feature = "uuid")]
|
|
|
|
mod uuid;
|
2015-02-08 03:52:45 +00:00
|
|
|
#[cfg(feature = "time")]
|
2014-11-18 03:11:32 +00:00
|
|
|
mod time;
|
2015-02-08 03:20:18 +00:00
|
|
|
#[cfg(feature = "rustc-serialize")]
|
2015-04-13 04:48:38 +00:00
|
|
|
mod rustc_serialize;
|
2015-11-08 00:28:20 +00:00
|
|
|
#[cfg(feature = "serde_json")]
|
|
|
|
mod serde_json;
|
2015-05-14 05:21:40 +00:00
|
|
|
#[cfg(feature = "chrono")]
|
|
|
|
mod chrono;
|
2016-02-14 01:36:16 +00:00
|
|
|
#[cfg(feature = "eui48")]
|
|
|
|
mod eui48;
|
2013-10-29 05:35:52 +00:00
|
|
|
|
2016-06-24 23:03:20 +00:00
|
|
|
mod special;
|
2016-02-21 21:37:29 +00:00
|
|
|
mod types;
|
|
|
|
|
2015-05-22 05:28:51 +00:00
|
|
|
/// A structure providing information for conversion methods.
|
|
|
|
pub struct SessionInfo<'a> {
|
|
|
|
conn: &'a InnerConnection,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> SessionInfoNew<'a> for SessionInfo<'a> {
|
|
|
|
fn new(conn: &'a InnerConnection) -> SessionInfo<'a> {
|
2015-11-16 03:51:04 +00:00
|
|
|
SessionInfo { conn: conn }
|
2015-05-22 05:28:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> SessionInfo<'a> {
|
|
|
|
/// Returns the value of the specified Postgres backend parameter, such
|
|
|
|
/// as `timezone` or `server_version`.
|
|
|
|
pub fn parameter(&self, param: &str) -> Option<&'a str> {
|
|
|
|
self.conn.parameters.get(param).map(|s| &**s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 20:47:32 +00:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-02 22:55:53 +00:00
|
|
|
/// A Postgres OID.
|
2014-01-03 07:10:26 +00:00
|
|
|
pub type Oid = u32;
|
2013-08-30 05:58:26 +00:00
|
|
|
|
2015-02-14 20:46:18 +00:00
|
|
|
/// Represents the kind of a Postgres type.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub enum Kind {
|
|
|
|
/// A simple type like `VARCHAR` or `INTEGER`.
|
|
|
|
Simple,
|
2016-02-18 06:22:31 +00:00
|
|
|
/// An enumerated type along with its variants.
|
|
|
|
Enum(Vec<String>),
|
2016-02-14 05:51:37 +00:00
|
|
|
/// A pseudo-type.
|
|
|
|
Pseudo,
|
2015-02-14 20:46:18 +00:00
|
|
|
/// An array type along with the type of its elements.
|
|
|
|
Array(Type),
|
|
|
|
/// A range type along with the type of its elements.
|
|
|
|
Range(Type),
|
2016-02-01 23:31:20 +00:00
|
|
|
/// A domain type along with its underlying type.
|
2016-01-23 04:00:42 +00:00
|
|
|
Domain(Type),
|
2016-02-16 07:11:01 +00:00
|
|
|
/// A composite type along with information about its fields.
|
|
|
|
Composite(Vec<Field>),
|
2015-12-27 20:40:28 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
__PseudoPrivateForExtensibility,
|
2015-02-14 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
2016-02-16 07:11:01 +00:00
|
|
|
/// Information about a field of a composite type.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct Field {
|
|
|
|
name: String,
|
|
|
|
type_: Type,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Field {
|
|
|
|
/// Returns the name of the field.
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
&self.name
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the type of the field.
|
|
|
|
pub fn type_(&self) -> &Type {
|
|
|
|
&self.type_
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FieldNew for Field {
|
|
|
|
fn new(name: String, type_: Type) -> Field {
|
|
|
|
Field {
|
|
|
|
name: name,
|
|
|
|
type_: type_,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-23 02:51:44 +00:00
|
|
|
/// Information about an unknown type.
|
2016-01-03 04:07:33 +00:00
|
|
|
#[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 {
|
2015-05-23 02:51:44 +00:00
|
|
|
name: String,
|
|
|
|
oid: Oid,
|
|
|
|
kind: Kind,
|
2015-09-26 20:23:55 +00:00
|
|
|
schema: String,
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl OtherNew for Other {
|
2015-09-26 20:23:55 +00:00
|
|
|
fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other {
|
2016-01-03 04:07:33 +00:00
|
|
|
Other(Arc::new(OtherInner {
|
2015-05-23 02:51:44 +00:00
|
|
|
name: name,
|
|
|
|
oid: oid,
|
|
|
|
kind: kind,
|
2015-09-26 20:23:55 +00:00
|
|
|
schema: schema,
|
2016-01-03 04:07:33 +00:00
|
|
|
}))
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Other {
|
|
|
|
/// The name of the type.
|
|
|
|
pub fn name(&self) -> &str {
|
2016-01-03 04:07:33 +00:00
|
|
|
&self.0.name
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The OID of this type.
|
|
|
|
pub fn oid(&self) -> Oid {
|
2016-01-03 04:07:33 +00:00
|
|
|
self.0.oid
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The kind of this type.
|
|
|
|
pub fn kind(&self) -> &Kind {
|
2016-01-03 04:07:33 +00:00
|
|
|
&self.0.kind
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
2015-09-26 20:23:55 +00:00
|
|
|
|
|
|
|
/// The schema of this type.
|
|
|
|
pub fn schema(&self) -> &str {
|
2016-01-03 04:07:33 +00:00
|
|
|
&self.0.schema
|
2015-09-26 20:23:55 +00:00
|
|
|
}
|
2015-05-23 02:51:44 +00:00
|
|
|
}
|
|
|
|
|
2015-05-23 04:20:56 +00:00
|
|
|
/// An error indicating that a `NULL` Postgres value was passed to a `FromSql`
|
|
|
|
/// implementation that does not support `NULL` values.
|
|
|
|
#[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`"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-27 05:05:23 +00:00
|
|
|
/// An error indicating that a conversion was attempted between incompatible
|
|
|
|
/// Rust and Postgres types.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct WrongType(Type);
|
|
|
|
|
|
|
|
impl fmt::Display for WrongType {
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
2016-01-03 00:02:34 +00:00
|
|
|
write!(fmt,
|
|
|
|
"cannot convert to or from a Postgres value of type `{}`",
|
|
|
|
self.0)
|
2015-12-27 05:05:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
/// A trait for types that can be created from a Postgres value.
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
|
|
|
/// # Types
|
|
|
|
///
|
|
|
|
/// The following implementations are provided by this crate, along with the
|
|
|
|
/// corresponding Postgres types:
|
|
|
|
///
|
2016-08-05 20:34:53 +00:00
|
|
|
/// | Rust type | Postgres type(s) |
|
|
|
|
/// |-----------------------------------|--------------------------------|
|
|
|
|
/// | `bool` | BOOL |
|
|
|
|
/// | `i8` | "char" |
|
|
|
|
/// | `i16` | SMALLINT, SMALLSERIAL |
|
|
|
|
/// | `i32` | INT, SERIAL |
|
|
|
|
/// | `u32` | OID |
|
|
|
|
/// | `i64` | BIGINT, BIGSERIAL |
|
|
|
|
/// | `f32` | REAL |
|
|
|
|
/// | `f64` | DOUBLE PRECISION |
|
|
|
|
/// | `String` | VARCHAR, CHAR(n), TEXT, CITEXT |
|
|
|
|
/// | `Vec<u8>` | BYTEA |
|
|
|
|
/// | `HashMap<String, Option<String>>` | HSTORE |
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
|
|
|
/// In addition, some implementations are provided for types in third party
|
|
|
|
/// crates. These are disabled by default; to opt into one of these
|
2015-05-18 03:34:49 +00:00
|
|
|
/// implementations, activate the Cargo feature corresponding to the crate's
|
2015-11-08 00:28:20 +00:00
|
|
|
/// name. For example, the `serde_json` feature enables the implementation for
|
|
|
|
/// the `serde_json::Value` type.
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
2016-08-05 20:34:53 +00:00
|
|
|
/// | Rust type | Postgres type(s) |
|
|
|
|
/// |---------------------------------|-------------------------------------|
|
|
|
|
/// | `serialize::json::Json` | JSON, JSONB |
|
|
|
|
/// | `serde_json::Value` | JSON, JSONB |
|
|
|
|
/// | `time::Timespec` | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::NaiveDateTime` | TIMESTAMP |
|
|
|
|
/// | `chrono::DateTime<UTC>` | TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::DateTime<Local>` | TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::DateTime<FixedOffset>` | TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::NaiveDate` | DATE |
|
|
|
|
/// | `chrono::NaiveTime` | TIME |
|
|
|
|
/// | `eui48::MacAddress` | MACADDR |
|
|
|
|
/// | `uuid::Uuid` | UUID |
|
|
|
|
/// | `bit_vec::BitVec` | BIT, VARBIT |
|
|
|
|
/// | `eui48::MacAddress` | MACADDR |
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
|
|
|
/// # Nullability
|
|
|
|
///
|
|
|
|
/// In addition to the types listed above, `FromSql` is implemented for
|
|
|
|
/// `Option<T>` where `T` implements `FromSql`. An `Option<T>` represents a
|
|
|
|
/// nullable Postgres value.
|
2016-03-27 16:42:21 +00:00
|
|
|
///
|
|
|
|
/// # Arrays
|
|
|
|
///
|
|
|
|
/// `FromSql` is implemented for `Vec<T>` where `T` implements `FromSql`, and
|
|
|
|
/// corresponds to one-dimensional Postgres arrays.
|
2015-02-15 01:07:10 +00:00
|
|
|
pub trait FromSql: Sized {
|
2015-04-08 06:57:22 +00:00
|
|
|
/// Creates a new value of this type from a `Read`er of the binary format
|
2015-02-15 23:31:07 +00:00
|
|
|
/// of the specified Postgres `Type`.
|
2015-01-22 06:31:04 +00:00
|
|
|
///
|
2015-02-15 01:07:10 +00:00
|
|
|
/// The caller of this method is responsible for ensuring that this type
|
|
|
|
/// is compatible with the Postgres `Type`.
|
2015-05-22 05:28:51 +00:00
|
|
|
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self>;
|
2015-02-15 01:07:10 +00:00
|
|
|
|
2015-10-25 02:24:00 +00:00
|
|
|
/// Creates a new value of this type from a `NULL` SQL value.
|
|
|
|
///
|
|
|
|
/// The caller of this method is responsible for ensuring that this type
|
|
|
|
/// is compatible with the Postgres `Type`.
|
|
|
|
///
|
|
|
|
/// The default implementation returns
|
|
|
|
/// `Err(Error::Conversion(Box::new(WasNull))`.
|
2015-11-08 00:28:20 +00:00
|
|
|
#[allow(unused_variables)]
|
2015-10-25 02:24:00 +00:00
|
|
|
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self> {
|
|
|
|
Err(Error::Conversion(Box::new(WasNull)))
|
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
/// Determines if a value of this type can be created from the specified
|
|
|
|
/// Postgres `Type`.
|
|
|
|
fn accepts(ty: &Type) -> bool;
|
2013-10-31 02:55:25 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
impl<T: FromSql> FromSql for Option<T> {
|
2015-05-22 05:28:51 +00:00
|
|
|
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)
|
2015-02-15 01:07:10 +00:00
|
|
|
}
|
|
|
|
|
2015-10-25 02:24:00 +00:00
|
|
|
fn from_sql_null(_: &Type, _: &SessionInfo) -> Result<Option<T>> {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
<T as FromSql>::accepts(ty)
|
2013-12-07 23:39:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
impl FromSql for bool {
|
2015-05-22 05:28:51 +00:00
|
|
|
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<bool> {
|
2015-02-15 01:07:10 +00:00
|
|
|
Ok(try!(raw.read_u8()) != 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
accepts!(Type::Bool);
|
|
|
|
}
|
|
|
|
|
2016-03-27 16:42:21 +00:00
|
|
|
impl<T: FromSql> FromSql for Vec<T> {
|
|
|
|
fn from_sql<R: Read>(ty: &Type, raw: &mut R, info: &SessionInfo) -> Result<Vec<T>> {
|
|
|
|
let member_type = match *ty.kind() {
|
|
|
|
Kind::Array(ref member) => member,
|
|
|
|
_ => panic!("expected array type"),
|
|
|
|
};
|
|
|
|
|
2016-07-09 17:06:35 +00:00
|
|
|
let dimensions = try!(raw.read_i32::<BigEndian>());
|
|
|
|
if dimensions > 1 {
|
|
|
|
return Err(Error::Conversion("array contains too many dimensions".into()));
|
|
|
|
}
|
2016-03-27 16:42:21 +00:00
|
|
|
|
|
|
|
let _has_nulls = try!(raw.read_i32::<BigEndian>());
|
|
|
|
let _member_oid = try!(raw.read_u32::<BigEndian>());
|
|
|
|
|
2016-07-09 17:06:35 +00:00
|
|
|
if dimensions == 0 {
|
|
|
|
return Ok(vec![]);
|
|
|
|
}
|
|
|
|
|
2016-03-27 16:42:21 +00:00
|
|
|
let count = try!(raw.read_i32::<BigEndian>());
|
|
|
|
let _index_offset = try!(raw.read_i32::<BigEndian>());
|
|
|
|
|
|
|
|
let mut out = Vec::with_capacity(count as usize);
|
|
|
|
for _ in 0..count {
|
|
|
|
let len = try!(raw.read_i32::<BigEndian>());
|
|
|
|
let value = if len < 0 {
|
|
|
|
try!(T::from_sql_null(&member_type, info))
|
|
|
|
} else {
|
|
|
|
let mut raw = raw.take(len as u64);
|
|
|
|
try!(T::from_sql(&member_type, &mut raw, info))
|
|
|
|
};
|
|
|
|
out.push(value)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(out)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
match *ty.kind() {
|
|
|
|
Kind::Array(ref inner) => T::accepts(inner),
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
impl FromSql for Vec<u8> {
|
2015-05-22 05:28:51 +00:00
|
|
|
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<Vec<u8>> {
|
2015-02-26 17:02:32 +00:00
|
|
|
let mut buf = vec![];
|
|
|
|
try!(raw.read_to_end(&mut buf));
|
|
|
|
Ok(buf)
|
2014-11-17 17:43:10 +00:00
|
|
|
}
|
2015-02-15 01:07:10 +00:00
|
|
|
|
2015-02-19 07:30:06 +00:00
|
|
|
accepts!(Type::Bytea);
|
2014-11-17 17:43:10 +00:00
|
|
|
}
|
2013-12-08 22:37:31 +00:00
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
impl FromSql for String {
|
2015-05-22 05:28:51 +00:00
|
|
|
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<String> {
|
2015-02-26 17:02:32 +00:00
|
|
|
let mut buf = vec![];
|
|
|
|
try!(raw.read_to_end(&mut buf));
|
2015-05-23 04:20:56 +00:00
|
|
|
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
|
2014-11-17 17:43:10 +00:00
|
|
|
}
|
2015-02-15 01:07:10 +00:00
|
|
|
|
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
match *ty {
|
2015-02-19 05:04:44 +00:00
|
|
|
Type::Varchar | Type::Text | Type::Bpchar | Type::Name => true,
|
|
|
|
Type::Other(ref u) if u.name() == "citext" => true,
|
2015-02-15 01:07:10 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
2014-11-17 17:43:10 +00:00
|
|
|
}
|
|
|
|
|
2015-05-02 22:55:53 +00:00
|
|
|
impl FromSql for i8 {
|
2015-05-22 05:28:51 +00:00
|
|
|
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<i8> {
|
2015-05-02 22:55:53 +00:00
|
|
|
Ok(try!(raw.read_i8()))
|
|
|
|
}
|
|
|
|
|
|
|
|
accepts!(Type::Char);
|
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
macro_rules! primitive_from {
|
|
|
|
($t:ty, $f:ident, $($expected:pat),+) => {
|
|
|
|
impl FromSql for $t {
|
2015-05-22 05:28:51 +00:00
|
|
|
fn from_sql<R: Read>(_: &Type, raw: &mut R, _: &SessionInfo) -> Result<$t> {
|
2015-02-26 17:02:32 +00:00
|
|
|
Ok(try!(raw.$f::<BigEndian>()))
|
2015-02-15 01:07:10 +00:00
|
|
|
}
|
2014-11-17 17:43:10 +00:00
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
accepts!($($expected),+);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-26 17:02:32 +00:00
|
|
|
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);
|
2015-02-15 01:07:10 +00:00
|
|
|
|
|
|
|
impl FromSql for HashMap<String, Option<String>> {
|
2015-11-16 03:51:04 +00:00
|
|
|
fn from_sql<R: Read>(_: &Type,
|
|
|
|
raw: &mut R,
|
|
|
|
_: &SessionInfo)
|
2015-05-22 05:28:51 +00:00
|
|
|
-> Result<HashMap<String, Option<String>>> {
|
2015-02-15 01:07:10 +00:00
|
|
|
let mut map = HashMap::new();
|
|
|
|
|
2015-02-26 17:02:32 +00:00
|
|
|
let count = try!(raw.read_i32::<BigEndian>());
|
2015-02-15 01:07:10 +00:00
|
|
|
|
2015-02-26 17:02:32 +00:00
|
|
|
for _ in 0..count {
|
|
|
|
let key_len = try!(raw.read_i32::<BigEndian>());
|
2015-05-02 22:55:53 +00:00
|
|
|
let mut key = vec![0; key_len as usize];
|
2016-03-04 05:19:46 +00:00
|
|
|
try!(raw.read_exact(&mut key));
|
2015-02-15 01:07:10 +00:00
|
|
|
let key = match String::from_utf8(key) {
|
|
|
|
Ok(key) => key,
|
2015-05-23 04:20:56 +00:00
|
|
|
Err(err) => return Err(Error::Conversion(Box::new(err))),
|
2015-02-15 01:07:10 +00:00
|
|
|
};
|
|
|
|
|
2015-02-26 17:02:32 +00:00
|
|
|
let val_len = try!(raw.read_i32::<BigEndian>());
|
2015-02-15 01:07:10 +00:00
|
|
|
let val = if val_len < 0 {
|
|
|
|
None
|
|
|
|
} else {
|
2015-05-02 22:55:53 +00:00
|
|
|
let mut val = vec![0; val_len as usize];
|
2016-03-04 05:19:46 +00:00
|
|
|
try!(raw.read_exact(&mut val));
|
2015-02-15 01:07:10 +00:00
|
|
|
match String::from_utf8(val) {
|
|
|
|
Ok(val) => Some(val),
|
2015-05-23 04:20:56 +00:00
|
|
|
Err(err) => return Err(Error::Conversion(Box::new(err))),
|
2015-02-15 01:07:10 +00:00
|
|
|
}
|
|
|
|
};
|
2014-12-15 00:43:17 +00:00
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
map.insert(key, val);
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
Ok(map)
|
|
|
|
}
|
2013-12-06 05:58:22 +00:00
|
|
|
|
2015-02-15 01:07:10 +00:00
|
|
|
fn accepts(ty: &Type) -> bool {
|
2014-03-13 06:50:10 +00:00
|
|
|
match *ty {
|
2015-02-19 05:04:44 +00:00
|
|
|
Type::Other(ref u) if u.name() == "hstore" => true,
|
2015-11-16 03:51:04 +00:00
|
|
|
_ => false,
|
2014-03-28 05:43:10 +00:00
|
|
|
}
|
2013-12-05 05:20:48 +00:00
|
|
|
}
|
2014-03-13 06:50:10 +00:00
|
|
|
}
|
2013-12-05 05:20:48 +00:00
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
/// An enum representing the nullability of a Postgres value.
|
|
|
|
pub enum IsNull {
|
|
|
|
/// The value is NULL.
|
|
|
|
Yes,
|
|
|
|
/// The value is not NULL.
|
|
|
|
No,
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
/// A trait for types that can be converted into Postgres values.
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
|
|
|
/// # Types
|
|
|
|
///
|
|
|
|
/// The following implementations are provided by this crate, along with the
|
|
|
|
/// corresponding Postgres types:
|
|
|
|
///
|
2016-08-05 20:34:53 +00:00
|
|
|
/// | Rust type | Postgres type(s) |
|
|
|
|
/// |-----------------------------------|--------------------------------|
|
|
|
|
/// | `bool` | BOOL |
|
|
|
|
/// | `i8` | "char" |
|
|
|
|
/// | `i16` | SMALLINT, SMALLSERIAL |
|
|
|
|
/// | `i32` | INT, SERIAL |
|
|
|
|
/// | `u32` | OID |
|
|
|
|
/// | `i64` | BIGINT, BIGSERIAL |
|
|
|
|
/// | `f32` | REAL |
|
|
|
|
/// | `f64` | DOUBLE PRECISION |
|
|
|
|
/// | `String` | VARCHAR, CHAR(n), TEXT, CITEXT |
|
|
|
|
/// | `&str` | VARCHAR, CHAR(n), TEXT, CITEXT |
|
|
|
|
/// | `Vec<u8>` | BYTEA |
|
|
|
|
/// | `&[u8]` | BYTEA |
|
|
|
|
/// | `HashMap<String, Option<String>>` | HSTORE |
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
|
|
|
/// In addition, some implementations are provided for types in third party
|
|
|
|
/// crates. These are disabled by default; to opt into one of these
|
2015-05-18 03:34:49 +00:00
|
|
|
/// implementations, activate the Cargo feature corresponding to the crate's
|
2015-11-08 00:28:20 +00:00
|
|
|
/// name. For example, the `serde_json` feature enables the implementation for
|
|
|
|
/// the `serde_json::Value` type.
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
2016-08-05 20:34:53 +00:00
|
|
|
/// | Rust type | Postgres type(s) |
|
|
|
|
/// |---------------------------------|-------------------------------------|
|
|
|
|
/// | `serialize::json::Json` | JSON, JSONB |
|
|
|
|
/// | `serde_json::Value` | JSON, JSONB |
|
|
|
|
/// | `time::Timespec` | TIMESTAMP, TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::NaiveDateTime` | TIMESTAMP |
|
|
|
|
/// | `chrono::DateTime<UTC>` | TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::DateTime<Local>` | TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::DateTime<FixedOffset>` | TIMESTAMP WITH TIME ZONE |
|
|
|
|
/// | `chrono::NaiveDate` | DATE |
|
|
|
|
/// | `chrono::NaiveTime` | TIME |
|
|
|
|
/// | `uuid::Uuid` | UUID |
|
|
|
|
/// | `bit_vec::BitVec` | BIT, VARBIT |
|
|
|
|
/// | `eui48::MacAddress` | MACADDR |
|
2015-05-18 03:27:39 +00:00
|
|
|
///
|
|
|
|
/// # Nullability
|
|
|
|
///
|
|
|
|
/// In addition to the types listed above, `ToSql` is implemented for
|
|
|
|
/// `Option<T>` where `T` implements `ToSql`. An `Option<T>` represents a
|
|
|
|
/// nullable Postgres value.
|
2016-03-27 16:42:21 +00:00
|
|
|
///
|
|
|
|
/// # Arrays
|
|
|
|
///
|
|
|
|
/// `ToSql` is implemented for `Vec<T>` and `&[T]` where `T` implements `ToSql`,
|
|
|
|
/// and corresponds to one-dimentional Postgres arrays with an index offset of
|
2016-05-02 06:06:57 +00:00
|
|
|
/// 1.
|
2015-03-31 06:22:31 +00:00
|
|
|
pub trait ToSql: fmt::Debug {
|
2015-02-15 23:31:07 +00:00
|
|
|
/// Converts the value of `self` into the binary format of the specified
|
|
|
|
/// Postgres `Type`, writing it to `out`.
|
2015-01-22 06:31:04 +00:00
|
|
|
///
|
2015-02-15 23:11:15 +00:00
|
|
|
/// The caller of this method is responsible for ensuring that this type
|
|
|
|
/// is compatible with the Postgres `Type`.
|
|
|
|
///
|
|
|
|
/// The return value indicates if this value should be represented as
|
|
|
|
/// `NULL`. If this is the case, implementations **must not** write
|
|
|
|
/// anything to `out`.
|
2015-05-22 05:28:51 +00:00
|
|
|
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
|
2015-11-16 03:51:04 +00:00
|
|
|
where Self: Sized,
|
|
|
|
W: Write;
|
2015-02-15 23:11:15 +00:00
|
|
|
|
|
|
|
/// Determines if a value of this type can be converted to the specified
|
|
|
|
/// Postgres `Type`.
|
|
|
|
fn accepts(ty: &Type) -> bool where Self: Sized;
|
|
|
|
|
|
|
|
/// An adaptor method used internally by Rust-Postgres.
|
|
|
|
///
|
|
|
|
/// *All* implementations of this method should be generated by the
|
|
|
|
/// `to_sql_checked!()` macro.
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo) -> Result<IsNull>;
|
2013-10-31 02:55:25 +00:00
|
|
|
}
|
|
|
|
|
2016-01-23 05:22:05 +00:00
|
|
|
impl<'a, T> ToSql for &'a T
|
|
|
|
where T: ToSql
|
2015-12-05 22:44:40 +00:00
|
|
|
{
|
2015-11-13 04:55:29 +00:00
|
|
|
to_sql_checked!();
|
2015-08-01 01:25:41 +00:00
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self,
|
|
|
|
ty: &Type,
|
|
|
|
out: &mut W,
|
|
|
|
ctx: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
2015-08-01 01:25:41 +00:00
|
|
|
(*self).to_sql(ty, out, ctx)
|
|
|
|
}
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
T::accepts(ty)
|
|
|
|
}
|
2015-08-01 01:25:41 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
impl<T: ToSql> ToSql for Option<T> {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self,
|
|
|
|
ty: &Type,
|
|
|
|
out: &mut W,
|
|
|
|
ctx: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
2015-02-15 23:11:15 +00:00
|
|
|
match *self {
|
2015-05-22 05:28:51 +00:00
|
|
|
Some(ref val) => val.to_sql(ty, out, ctx),
|
2015-02-15 23:11:15 +00:00
|
|
|
None => Ok(IsNull::Yes),
|
|
|
|
}
|
2013-12-07 23:39:44 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
<T as ToSql>::accepts(ty)
|
2014-03-15 06:01:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
impl ToSql for bool {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self,
|
|
|
|
_: &Type,
|
|
|
|
mut w: &mut W,
|
|
|
|
_: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
2015-02-15 23:11:15 +00:00
|
|
|
try!(w.write_u8(*self as u8));
|
|
|
|
Ok(IsNull::No)
|
2013-12-08 03:13:21 +00:00
|
|
|
}
|
2015-02-15 23:11:15 +00:00
|
|
|
|
|
|
|
accepts!(Type::Bool);
|
2013-12-08 03:13:21 +00:00
|
|
|
}
|
|
|
|
|
2016-03-27 16:42:21 +00:00
|
|
|
impl<'a, T: ToSql> ToSql for &'a [T] {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
|
|
|
fn to_sql<W: Write + ?Sized>(&self, ty: &Type,
|
|
|
|
mut w: &mut W,
|
|
|
|
ctx: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
|
|
|
let member_type = match *ty.kind() {
|
|
|
|
Kind::Array(ref member) => member,
|
|
|
|
_ => panic!("expected array type"),
|
|
|
|
};
|
|
|
|
|
|
|
|
try!(w.write_i32::<BigEndian>(1)); // number of dimensions
|
|
|
|
try!(w.write_i32::<BigEndian>(1)); // has nulls
|
|
|
|
try!(w.write_u32::<BigEndian>(member_type.oid()));
|
|
|
|
|
|
|
|
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
|
2016-05-02 06:06:57 +00:00
|
|
|
try!(w.write_i32::<BigEndian>(1)); // index offset
|
2016-03-27 16:42:21 +00:00
|
|
|
|
|
|
|
let mut inner_buf = vec![];
|
|
|
|
for e in *self {
|
|
|
|
match try!(e.to_sql(&member_type, &mut inner_buf, ctx)) {
|
|
|
|
IsNull::No => {
|
|
|
|
try!(w.write_i32::<BigEndian>(try!(downcast(inner_buf.len()))));
|
|
|
|
try!(w.write_all(&inner_buf));
|
|
|
|
}
|
|
|
|
IsNull::Yes => try!(w.write_i32::<BigEndian>(-1)),
|
|
|
|
}
|
|
|
|
inner_buf.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(IsNull::No)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
match *ty.kind() {
|
|
|
|
Kind::Array(ref member) => T::accepts(member),
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
impl<'a> ToSql for &'a [u8] {
|
2015-11-13 04:55:29 +00:00
|
|
|
to_sql_checked!();
|
2013-10-31 02:55:25 +00:00
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
2015-02-15 23:11:15 +00:00
|
|
|
try!(w.write_all(*self));
|
|
|
|
Ok(IsNull::No)
|
2014-12-14 19:39:26 +00:00
|
|
|
}
|
2015-02-15 23:11:15 +00:00
|
|
|
|
|
|
|
accepts!(Type::Bytea);
|
2014-12-14 19:39:26 +00:00
|
|
|
}
|
|
|
|
|
2016-03-27 16:42:21 +00:00
|
|
|
impl<T: ToSql> ToSql for Vec<T> {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
|
|
|
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
|
|
|
<&[T] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
<&[T] as ToSql>::accepts(ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
impl ToSql for Vec<u8> {
|
|
|
|
to_sql_checked!();
|
2014-12-15 00:43:17 +00:00
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
2015-05-22 05:28:51 +00:00
|
|
|
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
<&[u8] as ToSql>::accepts(ty)
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-14 23:07:48 +00:00
|
|
|
|
2014-10-26 03:24:08 +00:00
|
|
|
impl<'a> ToSql for &'a str {
|
2015-11-13 04:55:29 +00:00
|
|
|
to_sql_checked!();
|
2015-02-15 23:11:15 +00:00
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self, _: &Type, w: &mut W, _: &SessionInfo) -> Result<IsNull> {
|
2015-02-15 23:11:15 +00:00
|
|
|
try!(w.write_all(self.as_bytes()));
|
|
|
|
Ok(IsNull::No)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accepts(ty: &Type) -> bool {
|
2014-12-15 00:43:17 +00:00
|
|
|
match *ty {
|
2015-02-15 23:11:15 +00:00
|
|
|
Type::Varchar | Type::Text | Type::Bpchar | Type::Name => true,
|
|
|
|
Type::Other(ref u) if u.name() == "citext" => true,
|
|
|
|
_ => false,
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
2013-08-28 04:36:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
impl ToSql for String {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self, ty: &Type, w: &mut W, ctx: &SessionInfo) -> Result<IsNull> {
|
2015-05-22 05:28:51 +00:00
|
|
|
<&str as ToSql>::to_sql(&&**self, ty, w, ctx)
|
2015-02-15 23:11:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn accepts(ty: &Type) -> bool {
|
|
|
|
<&str as ToSql>::accepts(ty)
|
2014-12-15 00:43:17 +00:00
|
|
|
}
|
|
|
|
}
|
2013-09-02 19:42:24 +00:00
|
|
|
|
2015-05-02 22:55:53 +00:00
|
|
|
impl ToSql for i8 {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self,
|
|
|
|
_: &Type,
|
|
|
|
mut w: &mut W,
|
|
|
|
_: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
2015-05-02 22:55:53 +00:00
|
|
|
try!(w.write_i8(*self));
|
|
|
|
Ok(IsNull::No)
|
|
|
|
}
|
|
|
|
|
|
|
|
accepts!(Type::Char);
|
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
macro_rules! to_primitive {
|
|
|
|
($t:ty, $f:ident, $($expected:pat),+) => {
|
|
|
|
impl ToSql for $t {
|
|
|
|
to_sql_checked!();
|
|
|
|
|
2015-05-22 05:28:51 +00:00
|
|
|
fn to_sql<W: Write+?Sized>(&self, _: &Type, mut w: &mut W, _: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
2015-02-26 17:02:32 +00:00
|
|
|
try!(w.$f::<BigEndian>(*self));
|
2015-02-15 23:11:15 +00:00
|
|
|
Ok(IsNull::No)
|
|
|
|
}
|
|
|
|
|
|
|
|
accepts!($($expected),+);
|
|
|
|
}
|
2013-09-02 19:42:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-26 17:02:32 +00:00
|
|
|
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);
|
2014-12-19 18:43:42 +00:00
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
impl ToSql for HashMap<String, Option<String>> {
|
|
|
|
to_sql_checked!();
|
2013-12-05 05:20:48 +00:00
|
|
|
|
2015-11-16 03:51:04 +00:00
|
|
|
fn to_sql<W: Write + ?Sized>(&self,
|
|
|
|
_: &Type,
|
|
|
|
mut w: &mut W,
|
|
|
|
_: &SessionInfo)
|
|
|
|
-> Result<IsNull> {
|
2015-06-02 03:28:23 +00:00
|
|
|
try!(w.write_i32::<BigEndian>(try!(downcast(self.len()))));
|
2013-12-05 05:20:48 +00:00
|
|
|
|
2015-05-02 22:55:53 +00:00
|
|
|
for (key, val) in self {
|
2015-06-02 03:28:23 +00:00
|
|
|
try!(w.write_i32::<BigEndian>(try!(downcast(key.len()))));
|
2015-02-15 23:11:15 +00:00
|
|
|
try!(w.write_all(key.as_bytes()));
|
2013-12-05 05:20:48 +00:00
|
|
|
|
|
|
|
match *val {
|
|
|
|
Some(ref val) => {
|
2015-06-02 03:28:23 +00:00
|
|
|
try!(w.write_i32::<BigEndian>(try!(downcast(val.len()))));
|
2015-02-15 23:11:15 +00:00
|
|
|
try!(w.write_all(val.as_bytes()));
|
2013-12-05 05:20:48 +00:00
|
|
|
}
|
2015-11-16 03:51:04 +00:00
|
|
|
None => try!(w.write_i32::<BigEndian>(-1)),
|
2013-12-05 05:20:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
Ok(IsNull::No)
|
2013-12-05 05:20:48 +00:00
|
|
|
}
|
2014-03-13 06:50:10 +00:00
|
|
|
|
2015-02-15 23:11:15 +00:00
|
|
|
fn accepts(ty: &Type) -> bool {
|
2014-03-13 06:50:10 +00:00
|
|
|
match *ty {
|
2015-02-15 23:11:15 +00:00
|
|
|
Type::Other(ref u) if u.name() == "hstore" => true,
|
|
|
|
_ => false,
|
2014-03-13 06:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-02 03:28:23 +00:00
|
|
|
|
|
|
|
fn downcast(len: usize) -> Result<i32> {
|
|
|
|
if len > i32::max_value() as usize {
|
2016-07-10 01:41:10 +00:00
|
|
|
Err(Error::Conversion("value too large to transmit".into()))
|
2015-06-02 03:28:23 +00:00
|
|
|
} else {
|
|
|
|
Ok(len as i32)
|
|
|
|
}
|
|
|
|
}
|