rust-postgres/src/types/mod.rs

762 lines
24 KiB
Rust
Raw Normal View History

2013-10-20 21:34:50 +00:00
//! Traits dealing with Postgres data types
use fallible_iterator::FallibleIterator;
2016-09-20 03:46:25 +00:00
use postgres_protocol;
use postgres_protocol::types::{self, ArrayDimension};
2014-06-06 03:50:23 +00:00
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
2016-01-03 04:07:33 +00:00
use std::sync::Arc;
2016-09-12 04:56:22 +00:00
#[doc(inline)]
pub use postgres_protocol::Oid;
2016-09-12 04:56:22 +00:00
pub use self::type_gen::Type;
pub use self::special::{Date, Timestamp};
2016-09-20 03:46:25 +00:00
use {SessionInfoNew, OtherNew, WrongTypeNew, FieldNew};
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]
macro_rules! accepts {
($($expected:pat),+) => (
2015-02-28 04:46:43 +00:00
fn accepts(ty: &$crate::types::Type) -> bool {
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 {
() => {
fn to_sql_checked(&self,
ty: &$crate::types::Type,
out: &mut ::std::vec::Vec<u8>,
ctx: &$crate::types::SessionInfo)
2016-09-18 12:00:12 +00:00
-> ::std::result::Result<$crate::types::IsNull,
Box<::std::error::Error +
::std::marker::Sync +
::std::marker::Send>> {
$crate::types::__to_sql_checked(self, ty, out, ctx)
2014-11-17 17:43:10 +00:00
}
}
2014-12-19 18:43:42 +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-09-16 03:51:26 +00:00
pub fn __to_sql_checked<T>(v: &T,
ty: &Type,
out: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>>
where T: ToSql
{
if !T::accepts(ty) {
return Err(Box::new(WrongType(ty.clone())));
}
v.to_sql(ty, out, ctx)
}
#[cfg(feature = "with-bit-vec")]
mod bit_vec;
#[cfg(feature = "with-uuid")]
2014-11-17 17:43:10 +00:00
mod uuid;
#[cfg(feature = "with-time")]
2014-11-18 03:11:32 +00:00
mod time;
#[cfg(feature = "with-rustc-serialize")]
2015-04-13 04:48:38 +00:00
mod rustc_serialize;
#[cfg(feature = "with-serde_json")]
2015-11-08 00:28:20 +00:00
mod serde_json;
#[cfg(feature = "with-chrono")]
2015-05-14 05:21:40 +00:00
mod chrono;
#[cfg(feature = "with-eui48")]
mod eui48;
2013-10-29 05:35:52 +00:00
mod special;
mod type_gen;
/// A structure providing information for conversion methods.
2016-09-20 03:46:25 +00:00
#[derive(Debug)]
pub struct SessionInfo<'a> {
2016-09-20 03:46:25 +00:00
parameters: &'a HashMap<String, String>,
}
impl<'a> SessionInfoNew<'a> for SessionInfo<'a> {
2016-09-20 03:46:25 +00:00
fn new(parameters: &'a HashMap<String, String>) -> SessionInfo<'a> {
SessionInfo { parameters: parameters }
}
}
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> {
2016-09-20 03:46:25 +00:00
self.parameters.get(param).map(|s| &**s)
}
}
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,
/// 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.
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_,
}
}
}
/// 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")
2016-09-13 04:48:49 +00:00
.field("name", &self.0.name)
.field("oid", &self.0.oid)
.field("kind", &self.0.kind)
.field("schema", &self.0.schema)
.finish()
2016-01-03 04:07:33 +00:00
}
}
#[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 {
2016-01-03 04:07:33 +00:00
Other(Arc::new(OtherInner {
name: name,
oid: oid,
kind: kind,
schema: schema,
2016-01-03 04:07:33 +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
}
/// The OID of this type.
pub fn oid(&self) -> Oid {
2016-01-03 04:07:33 +00:00
self.0.oid
}
/// The kind of this type.
pub fn kind(&self) -> &Kind {
2016-01-03 04:07:33 +00:00
&self.0.kind
}
/// The schema of this type.
pub fn schema(&self) -> &str {
2016-01-03 04:07:33 +00:00
&self.0.schema
}
}
/// 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(self.description())
}
}
impl Error for WasNull {
fn description(&self) -> &str {
"a Postgres value was `NULL`"
}
}
/// 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)
}
}
impl 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)
}
}
/// A trait for types that can be created from a Postgres value.
///
/// # 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 |
///
/// 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
/// name prefixed by `with-`. For example, the `with-serde_json` feature enables
/// the implementation for the `serde_json::Value` type.
///
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 |
///
/// # 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.
///
/// # Arrays
///
/// `FromSql` is implemented for `Vec<T>` where `T` implements `FromSql`, and
/// corresponds to one-dimensional Postgres arrays.
pub trait FromSql: Sized {
/// Creates a new value of this type from a buffer of data of the specified
/// Postgres `Type` in its binary format.
///
/// The caller of this method is responsible for ensuring that this type
/// is compatible with the Postgres `Type`.
2016-09-16 03:51:26 +00:00
fn from_sql(ty: &Type,
raw: &[u8],
ctx: &SessionInfo)
-> Result<Self, Box<Error + Sync + Send>>;
/// 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(Box::new(WasNull))`.
2015-11-08 00:28:20 +00:00
#[allow(unused_variables)]
fn from_sql_null(ty: &Type, ctx: &SessionInfo) -> Result<Self, Box<Error + Sync + Send>> {
Err(Box::new(WasNull))
}
/// 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
}
impl<T: FromSql> FromSql for Option<T> {
2016-09-16 03:51:26 +00:00
fn from_sql(ty: &Type,
raw: &[u8],
ctx: &SessionInfo)
-> Result<Option<T>, Box<Error + Sync + Send>> {
<T as FromSql>::from_sql(ty, raw, ctx).map(Some)
}
fn from_sql_null(_: &Type, _: &SessionInfo) -> Result<Option<T>, Box<Error + Sync + Send>> {
Ok(None)
}
fn accepts(ty: &Type) -> bool {
<T as FromSql>::accepts(ty)
2013-12-07 23:39:44 +00:00
}
}
impl<T: FromSql> FromSql for Vec<T> {
2016-09-16 03:51:26 +00:00
fn from_sql(ty: &Type,
raw: &[u8],
info: &SessionInfo)
-> Result<Vec<T>, Box<Error + Sync + Send>> {
let member_type = match *ty.kind() {
Kind::Array(ref member) => member,
_ => panic!("expected array type"),
};
let array = try!(types::array_from_sql(raw));
if try!(array.dimensions().count()) > 1 {
return Err("array contains too many dimensions".into());
}
array.values()
.and_then(|v| {
match v {
Some(v) => T::from_sql(&member_type, v, info),
None => T::from_sql_null(&member_type, info),
}
})
.collect()
}
fn accepts(ty: &Type) -> bool {
match *ty.kind() {
Kind::Array(ref inner) => T::accepts(inner),
_ => false,
}
}
}
impl FromSql for Vec<u8> {
2016-09-16 03:51:26 +00:00
fn from_sql(_: &Type,
raw: &[u8],
_: &SessionInfo)
-> Result<Vec<u8>, Box<Error + Sync + Send>> {
Ok(types::bytea_from_sql(raw).to_owned())
2014-11-17 17:43: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
impl FromSql for String {
fn from_sql(_: &Type, raw: &[u8], _: &SessionInfo) -> Result<String, Box<Error + Sync + Send>> {
types::text_from_sql(raw).map(|b| b.to_owned())
2014-11-17 17:43: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,
_ => false,
}
}
2014-11-17 17:43:10 +00:00
}
macro_rules! simple_from {
($t:ty, $f:ident, $($expected:pat),+) => {
impl FromSql for $t {
2016-09-18 12:00:12 +00:00
fn from_sql(_: &Type,
raw: &[u8],
_: &SessionInfo)
-> Result<$t, Box<Error + Sync + Send>> {
types::$f(raw)
}
2014-11-17 17:43:10 +00:00
accepts!($($expected),+);
}
}
}
simple_from!(bool, bool_from_sql, Type::Bool);
simple_from!(i8, char_from_sql, Type::Char);
simple_from!(i16, int2_from_sql, Type::Int2);
simple_from!(i32, int4_from_sql, Type::Int4);
simple_from!(u32, oid_from_sql, Type::Oid);
simple_from!(i64, int8_from_sql, Type::Int8);
simple_from!(f32, float4_from_sql, Type::Float4);
simple_from!(f64, float8_from_sql, Type::Float8);
impl FromSql for HashMap<String, Option<String>> {
2016-09-16 03:51:26 +00:00
fn from_sql(_: &Type,
raw: &[u8],
_: &SessionInfo)
-> Result<HashMap<String, Option<String>>, Box<Error + Sync + Send>> {
try!(types::hstore_from_sql(raw))
.map(|(k, v)| (k.to_owned(), v.map(|v| v.to_owned())))
.collect()
}
2013-12-06 05:58:22 +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,
}
2015-02-15 23:11:15 +00:00
/// A trait for types that can be converted into Postgres values.
///
/// # 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 |
///
/// 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
/// name prefixed by `with-`. For example, the `with-serde_json` feature enables
/// the implementation for the `serde_json::Value` type.
///
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 |
///
/// # 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.
///
/// # 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
/// 1.
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`, appending it to `out`.
///
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`.
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
out: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>>
where Self: Sized;
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.
2016-09-16 03:51:26 +00:00
fn to_sql_checked(&self,
ty: &Type,
out: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>>;
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
{
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
out: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
(*self).to_sql(ty, out, ctx)
}
2015-11-16 03:51:04 +00:00
fn accepts(ty: &Type) -> bool {
T::accepts(ty)
}
2015-02-15 23:11:15 +00:00
to_sql_checked!();
}
2015-02-15 23:11:15 +00:00
impl<T: ToSql> ToSql for Option<T> {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
out: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
2015-02-15 23:11:15 +00:00
match *self {
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
to_sql_checked!();
2013-12-08 03:13:21 +00:00
}
impl<'a, T: ToSql> ToSql for &'a [T] {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
w: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
let member_type = match *ty.kind() {
Kind::Array(ref member) => member,
_ => panic!("expected array type"),
};
2016-09-16 03:51:26 +00:00
let dimensions = [ArrayDimension {
len: try!(downcast(self.len())),
lower_bound: 1,
}];
try!(types::array_to_sql(dimensions.iter().cloned(),
true,
member_type.oid(),
self.iter(),
|e, w| {
match try!(e.to_sql(member_type, w, ctx)) {
2016-09-20 03:46:25 +00:00
IsNull::No => Ok(postgres_protocol::IsNull::No),
IsNull::Yes => Ok(postgres_protocol::IsNull::Yes),
}
},
w));
Ok(IsNull::No)
}
fn accepts(ty: &Type) -> bool {
match *ty.kind() {
Kind::Array(ref member) => T::accepts(member),
_ => false,
}
}
2015-11-13 04:55:29 +00:00
to_sql_checked!();
}
2013-10-31 02:55:25 +00:00
impl<'a> ToSql for &'a [u8] {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
_: &Type,
w: &mut Vec<u8>,
_: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
types::bytea_to_sql(*self, w);
2015-02-15 23:11:15 +00:00
Ok(IsNull::No)
}
2015-02-15 23:11:15 +00:00
accepts!(Type::Bytea);
to_sql_checked!();
}
impl<T: ToSql> ToSql for Vec<T> {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
w: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
<&[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
to_sql_checked!();
}
impl ToSql for Vec<u8> {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
w: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
<&[u8] as ToSql>::to_sql(&&**self, ty, w, ctx)
}
2015-02-15 23:11:15 +00:00
fn accepts(ty: &Type) -> bool {
<&[u8] as ToSql>::accepts(ty)
}
2015-11-13 04:55:29 +00:00
to_sql_checked!();
}
2015-02-15 23:11:15 +00:00
impl<'a> ToSql for &'a str {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
_: &Type,
w: &mut Vec<u8>,
_: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
types::text_to_sql(*self, w);
2015-02-15 23:11:15 +00:00
Ok(IsNull::No)
}
fn accepts(ty: &Type) -> bool {
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,
}
}
2015-02-15 23:11:15 +00:00
to_sql_checked!();
}
2015-02-15 23:11:15 +00:00
impl ToSql for String {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
ty: &Type,
w: &mut Vec<u8>,
ctx: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
<&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)
}
2015-05-02 22:55:53 +00:00
to_sql_checked!();
}
macro_rules! simple_to {
2015-02-15 23:11:15 +00:00
($t:ty, $f:ident, $($expected:pat),+) => {
impl ToSql for $t {
2016-09-18 12:00:12 +00:00
fn to_sql(&self,
_: &Type,
w: &mut Vec<u8>,
_: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
types::$f(*self, w);
2015-02-15 23:11:15 +00:00
Ok(IsNull::No)
}
accepts!($($expected),+);
to_sql_checked!();
2015-02-15 23:11:15 +00:00
}
}
}
simple_to!(bool, bool_to_sql, Type::Bool);
simple_to!(i8, char_to_sql, Type::Char);
simple_to!(i16, int2_to_sql, Type::Int2);
simple_to!(i32, int4_to_sql, Type::Int4);
simple_to!(u32, oid_to_sql, Type::Oid);
simple_to!(i64, int8_to_sql, Type::Int8);
simple_to!(f32, float4_to_sql, Type::Float4);
simple_to!(f64, float8_to_sql, 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>> {
2016-09-16 03:51:26 +00:00
fn to_sql(&self,
_: &Type,
w: &mut Vec<u8>,
_: &SessionInfo)
-> Result<IsNull, Box<Error + Sync + Send>> {
try!(types::hstore_to_sql(self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))),
w));
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
}
}
to_sql_checked!();
2014-03-13 06:50:10 +00:00
}
2015-06-02 03:28:23 +00:00
fn downcast(len: usize) -> Result<i32, Box<Error + Sync + Send>> {
2015-06-02 03:28:23 +00:00
if len > i32::max_value() as usize {
Err("value too large to transmit".into())
2015-06-02 03:28:23 +00:00
} else {
Ok(len as i32)
}
}