rust-postgres/src/types/mod.rs

990 lines
34 KiB
Rust
Raw Normal View History

2013-10-20 21:34:50 +00:00
//! Traits dealing with Postgres data types
2014-06-06 03:50:23 +00:00
use std::collections::HashMap;
use std::error;
use std::fmt;
2015-02-26 17:02:32 +00:00
use std::io::prelude::*;
use std::io;
2015-02-26 17:02:32 +00:00
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
2015-05-27 04:42:34 +00:00
pub use self::slice::Slice;
2015-05-27 04:47:42 +00:00
use {Result, SessionInfoNew, InnerConnection, OtherNew, TypeNew};
use error::Error;
2015-04-08 06:57:22 +00:00
use util;
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::io::Write,
ctx: &$crate::types::SessionInfo)
2015-02-28 04:46:43 +00:00
-> $crate::Result<$crate::types::IsNull> {
if !<Self as $crate::types::ToSql>::accepts(ty) {
2015-05-26 05:47:25 +00:00
return Err($crate::error::Error::WrongType(ty.clone()));
2014-11-17 17:43:10 +00:00
}
self.to_sql(ty, out, ctx)
2014-11-17 17:43:10 +00:00
}
}
2014-12-19 18:43:42 +00:00
}
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;
mod slice;
#[cfg(feature = "rustc-serialize")]
2015-04-13 04:48:38 +00:00
mod rustc_serialize;
#[cfg(feature = "serde")]
mod serde;
2015-05-14 05:21:40 +00:00
#[cfg(feature = "chrono")]
mod chrono;
2013-10-29 05:35:52 +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> {
SessionInfo {
conn: conn
}
}
}
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)
}
}
/// Like `Read` except that a `SessionInfo` object is provided as well.
///
/// All types that implement `Read` also implement this trait.
pub trait ReadWithInfo {
/// Like `Read::read`.
fn read_with_info(&mut self, buf: &mut [u8], info: &SessionInfo) -> io::Result<usize>;
}
impl<R: Read> ReadWithInfo for R {
fn read_with_info(&mut self, buf: &mut [u8], _: &SessionInfo) -> io::Result<usize> {
self.read(buf)
}
}
2015-05-02 22:55:53 +00:00
/// A Postgres OID.
2014-01-03 07:10:26 +00:00
pub type Oid = u32;
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 array type along with the type of its elements.
Array(Type),
/// A range type along with the type of its elements.
Range(Type),
}
2015-02-19 05:04:44 +00:00
macro_rules! as_pat {
($p:pat) => ($p)
}
macro_rules! as_expr {
($e:expr) => ($e)
}
2014-12-19 18:43:42 +00:00
macro_rules! make_postgres_type {
2015-02-19 05:04:44 +00:00
($(#[$doc:meta] $oid:tt => $variant:ident: $kind:expr),+) => (
2015-05-02 22:55:53 +00:00
/// A Postgres type.
2015-01-10 21:58:46 +00:00
#[derive(PartialEq, Eq, Clone)]
2014-11-04 05:29:16 +00:00
pub enum Type {
2013-12-08 03:34:48 +00:00
$(
2014-03-29 21:33:11 +00:00
#[$doc]
2013-12-08 03:34:48 +00:00
$variant,
)+
2015-05-02 22:55:53 +00:00
/// An unknown type.
2015-02-19 05:04:44 +00:00
Other(Box<Other>),
}
2015-01-23 18:44:15 +00:00
impl fmt::Debug for Type {
2015-01-10 21:58:46 +00:00
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
$(Type::$variant => stringify!($variant),)+
2015-02-19 05:04:44 +00:00
Type::Other(ref u) => return fmt::Debug::fmt(u, fmt),
2015-01-10 21:58:46 +00:00
};
fmt.write_str(s)
}
}
2015-05-27 04:47:42 +00:00
impl TypeNew for Type {
fn new(oid: Oid) -> Option<Type> {
2013-12-08 03:34:48 +00:00
match oid {
2015-02-19 05:04:44 +00:00
$(as_pat!($oid) => Some(Type::$variant),)+
2015-01-22 06:11:43 +00:00
_ => None
2013-12-08 03:34:48 +00:00
}
}
2015-05-27 04:47:42 +00:00
}
impl Type {
2015-04-08 06:57:22 +00:00
/// Returns the OID of the `Type`.
pub fn oid(&self) -> Oid {
2013-12-08 19:44:37 +00:00
match *self {
2015-02-19 05:04:44 +00:00
$(Type::$variant => as_expr!($oid),)+
Type::Other(ref u) => u.oid(),
2013-12-08 19:44:37 +00:00
}
}
2015-05-02 22:55:53 +00:00
/// The kind of this type.
2015-02-18 07:49:11 +00:00
pub fn kind(&self) -> &Kind {
2013-12-08 19:44:37 +00:00
match *self {
$(
2015-02-18 07:49:11 +00:00
Type::$variant => {
const V: &'static Kind = &$kind;
V
}
2013-12-08 19:44:37 +00:00
)+
2015-02-19 05:04:44 +00:00
Type::Other(ref u) => u.kind(),
2013-12-08 19:44:37 +00:00
}
}
}
2013-12-08 03:34:48 +00:00
)
2014-12-19 18:43:42 +00:00
}
2013-12-08 03:34:48 +00:00
2015-02-19 05:04:44 +00:00
// Values from pg_type.h
2014-12-19 18:43:42 +00:00
make_postgres_type! {
2015-02-19 05:04:44 +00:00
#[doc="BOOL - boolean, 'true'/'false'"]
16 => Bool: Kind::Simple,
#[doc="BYTEA - variable-length string, binary values escaped"]
2015-02-19 07:30:06 +00:00
17 => Bytea: Kind::Simple,
2015-02-19 05:04:44 +00:00
#[doc="\"char\" - single character"]
18 => Char: Kind::Simple,
#[doc="NAME - 63-byte type for storing system identifiers"]
19 => Name: Kind::Simple,
#[doc="INT8/BIGINT - ~18 digit integer, 8-byte storage"]
20 => Int8: Kind::Simple,
#[doc="INT2/SMALLINT - -32 thousand to 32 thousand, 2-byte storage"]
21 => Int2: Kind::Simple,
#[doc="INT2VECTOR - array of int2, used in system tables"]
22 => Int2Vector: Kind::Array(Type::Int2),
#[doc="INT4/INT - -2 billion to 2 billion integer, 4-byte storage"]
23 => Int4: Kind::Simple,
#[doc="REGPROC - registered procedure"]
24 => Regproc: Kind::Simple,
#[doc="TEXT - variable-length string, no limit specified"]
25 => Text: Kind::Simple,
#[doc="OID - object identifier(oid), maximum 4 billion"]
26 => Oid: Kind::Simple,
#[doc="TID - (block, offset), physical location of tuple"]
27 => Tid: Kind::Simple,
#[doc="XID - transaction id"]
28 => Xid: Kind::Simple,
#[doc="CID - command identifier type, sequence in transaction id"]
29 => Cid: Kind::Simple,
#[doc="OIDVECTOR - array of oids, used in system tables"]
30 => OidVector: Kind::Array(Type::Oid),
#[doc="PG_TYPE"]
71 => PgType: Kind::Simple,
#[doc="PG_ATTRIBUTE"]
75 => PgAttribute: Kind::Simple,
#[doc="PG_PROC"]
81 => PgProc: Kind::Simple,
#[doc="PG_CLASS"]
83 => PgClass: Kind::Simple,
2013-12-08 03:34:48 +00:00
#[doc="JSON"]
2015-02-19 05:04:44 +00:00
114 => Json: Kind::Simple,
#[doc="XML - XML content"]
142 => Xml: Kind::Simple,
#[doc="XML[]"]
143 => XmlArray: Kind::Array(Type::Xml),
#[doc="PG_NODE_TREE - string representing an internal node tree"]
194 => PgNodeTree: Kind::Simple,
2013-12-09 00:00:33 +00:00
#[doc="JSON[]"]
2015-02-19 05:04:44 +00:00
199 => JsonArray: Kind::Array(Type::Json),
#[doc="SMGR - storage manager"]
210 => Smgr: Kind::Simple,
#[doc="POINT - geometric point '(x, y)'"]
600 => Point: Kind::Simple,
#[doc="LSEG - geometric line segment '(pt1,pt2)'"]
601 => Lseg: Kind::Simple,
#[doc="PATH - geometric path '(pt1,...)'"]
602 => Path: Kind::Simple,
#[doc="BOX - geometric box '(lower left,upper right)'"]
603 => Box: Kind::Simple,
#[doc="POLYGON - geometric polygon '(pt1,...)'"]
604 => Polygon: Kind::Simple,
#[doc="LINE - geometric line"]
628 => Line: Kind::Simple,
#[doc="LINE[]"]
629 => LineArray: Kind::Array(Type::Line),
#[doc="CIDR - network IP address/netmask, network address"]
650 => Cidr: Kind::Simple,
#[doc="CIDR[]"]
651 => CidrArray: Kind::Array(Type::Cidr),
#[doc="FLOAT4/REAL - single-precision floating point number, 4-byte storage"]
700 => Float4: Kind::Simple,
#[doc="FLOAT8/DOUBLE PRECISION - double-precision floating point number, 8-byte storage"]
701 => Float8: Kind::Simple,
#[doc="ABSTIME - absolute, limited-range date and time (Unix system time)"]
702 => Abstime: Kind::Simple,
#[doc="RELTIME - relative, limited-range date and time (Unix delta time)"]
703 => Reltime: Kind::Simple,
#[doc="TINTERVAL - (abstime,abstime), time interval"]
704 => Tinterval: Kind::Simple,
#[doc="UNKNOWN"]
705 => Unknown: Kind::Simple,
#[doc="CIRCLE - geometric circle '(center,radius)'"]
718 => Circle: Kind::Simple,
#[doc="CIRCLE[]"]
719 => CircleArray: Kind::Array(Type::Circle),
#[doc="MONEY - monetary amounts, $d,ddd.cc"]
790 => Money: Kind::Simple,
#[doc="MONEY[]"]
791 => MoneyArray: Kind::Array(Type::Money),
#[doc="MACADDR - XX:XX:XX:XX:XX:XX, MAC address"]
829 => Macaddr: Kind::Simple,
#[doc="INET - IP address/netmask, host address, netmask optional"]
869 => Inet: Kind::Simple,
2013-12-08 03:34:48 +00:00
#[doc="BOOL[]"]
2015-02-19 05:04:44 +00:00
1000 => BoolArray: Kind::Array(Type::Bool),
2013-12-08 03:34:48 +00:00
#[doc="BYTEA[]"]
2015-02-19 07:30:06 +00:00
1001 => ByteaArray: Kind::Array(Type::Bytea),
2013-12-08 03:34:48 +00:00
#[doc="\"char\"[]"]
2015-02-19 05:04:44 +00:00
1002 => CharArray: Kind::Array(Type::Char),
#[doc="NAME[]"]
2015-02-19 05:04:44 +00:00
1003 => NameArray: Kind::Array(Type::Name),
2013-12-08 03:34:48 +00:00
#[doc="INT2[]"]
2015-02-19 05:04:44 +00:00
1005 => Int2Array: Kind::Array(Type::Int2),
#[doc="INT2VECTOR[]"]
1006 => Int2VectorArray: Kind::Array(Type::Int2Vector),
2013-12-08 03:34:48 +00:00
#[doc="INT4[]"]
2015-02-19 05:04:44 +00:00
1007 => Int4Array: Kind::Array(Type::Int4),
#[doc="REGPROC[]"]
1008 => RegprocArray: Kind::Array(Type::Regproc),
2013-12-08 03:34:48 +00:00
#[doc="TEXT[]"]
2015-02-19 05:04:44 +00:00
1009 => TextArray: Kind::Array(Type::Text),
#[doc="TID[]"]
1010 => TidArray: Kind::Array(Type::Tid),
#[doc="XID[]"]
1011 => XidArray: Kind::Array(Type::Xid),
#[doc="CID[]"]
1012 => CidArray: Kind::Array(Type::Cid),
#[doc="OIDVECTOR[]"]
1013 => OidVectorArray: Kind::Array(Type::OidVector),
#[doc="BPCHAR[]"]
1014 => BpcharArray: Kind::Array(Type::Bpchar),
2013-12-08 21:58:41 +00:00
#[doc="VARCHAR[]"]
2015-02-19 05:04:44 +00:00
1015 => VarcharArray: Kind::Array(Type::Varchar),
2013-12-08 03:34:48 +00:00
#[doc="INT8[]"]
2015-02-19 05:04:44 +00:00
1016 => Int8Array: Kind::Array(Type::Int8),
#[doc="POINT[]"]
1017 => PointArray: Kind::Array(Type::Point),
#[doc="LSEG[]"]
1018 => LsegArray: Kind::Array(Type::Lseg),
#[doc="PATH[]"]
1019 => PathArray: Kind::Array(Type::Path),
#[doc="BOX[]"]
1020 => BoxArray: Kind::Array(Type::Box),
2013-12-08 03:34:48 +00:00
#[doc="FLOAT4[]"]
2015-02-19 05:04:44 +00:00
1021 => Float4Array: Kind::Array(Type::Float4),
2013-12-08 03:34:48 +00:00
#[doc="FLOAT8[]"]
2015-02-19 05:04:44 +00:00
1022 => Float8Array: Kind::Array(Type::Float8),
#[doc="ABSTIME[]"]
1023 => AbstimeArray: Kind::Array(Type::Abstime),
#[doc="RELTIME[]"]
1024 => ReltimeArray: Kind::Array(Type::Reltime),
#[doc="TINTERVAL[]"]
1025 => TintervalArray: Kind::Array(Type::Tinterval),
#[doc="POLYGON[]"]
1027 => PolygonArray: Kind::Array(Type::Polygon),
#[doc="OID[]"]
1028 => OidArray: Kind::Array(Type::Oid),
#[doc="ACLITEM - access control list"]
1033 => Aclitem: Kind::Simple,
#[doc="ACLITEM[]"]
1034 => AclitemArray: Kind::Array(Type::Aclitem),
#[doc="MACADDR[]"]
1040 => MacaddrArray: Kind::Array(Type::Macaddr),
#[doc="INET[]"]
1041 => InetArray: Kind::Array(Type::Inet),
#[doc="BPCHAR - char(length), blank-padded string, fixed storage length"]
1042 => Bpchar: Kind::Simple,
#[doc="VARCHAR - varchar(length), non-blank-padded string, variable storage length"]
1043 => Varchar: Kind::Simple,
#[doc="DATE - date"]
1082 => Date: Kind::Simple,
#[doc="TIME - time of day"]
1083 => Time: Kind::Simple,
#[doc="TIMESTAMP - date and time"]
1114 => Timestamp: Kind::Simple,
2013-12-08 22:04:26 +00:00
#[doc="TIMESTAMP[]"]
2015-02-19 05:04:44 +00:00
1115 => TimestampArray: Kind::Array(Type::Timestamp),
#[doc="DATE[]"]
1182 => DateArray: Kind::Array(Type::Date),
#[doc="TIME[]"]
1183 => TimeArray: Kind::Array(Type::Time),
#[doc="TIMESTAMPTZ - date and time with time zone"]
1184 => TimestampTZ: Kind::Simple,
#[doc="TIMESTAMPTZ[]"]
1185 => TimestampTZArray: Kind::Array(Type::TimestampTZ),
2015-02-19 07:32:35 +00:00
#[doc="INTERVAL - @ &lt;number&gt; &lt;units&gt;, time interval"]
2015-02-19 05:04:44 +00:00
1186 => Interval: Kind::Simple,
#[doc="INTERVAL[]"]
1187 => IntervalArray: Kind::Array(Type::Interval),
#[doc="NUMERIC[]"]
1231 => NumericArray: Kind::Array(Type::Numeric),
#[doc="CSTRING[]"]
1263 => CstringArray: Kind::Array(Type::Cstring),
#[doc="TIMETZ - time of day with time zone"]
1266 => Timetz: Kind::Simple,
#[doc="TIMETZ[]"]
1270 => TimetzArray: Kind::Array(Type::Timetz),
#[doc="BIT - fixed-length bit string"]
1560 => Bit: Kind::Simple,
#[doc="BIT[]"]
1561 => BitArray: Kind::Array(Type::Bit),
#[doc="VARBIT - variable-length bit string"]
1562 => Varbit: Kind::Simple,
#[doc="VARBIT[]"]
1563 => VarbitArray: Kind::Array(Type::Varbit),
#[doc="NUMERIC - numeric(precision, decimal), arbitrary precision number"]
1700 => Numeric: Kind::Simple,
#[doc="REFCURSOR - reference to cursor (portal name)"]
1790 => Refcursor: Kind::Simple,
#[doc="REFCURSOR[]"]
2201 => RefcursorArray: Kind::Array(Type::Refcursor),
#[doc="REGPROCEDURE - registered procedure (with args)"]
2202 => Regprocedure: Kind::Simple,
#[doc="REGOPER - registered operator"]
2203 => Regoper: Kind::Simple,
#[doc="REGOPERATOR - registered operator (with args)"]
2204 => Regoperator: Kind::Simple,
#[doc="REGCLASS - registered class"]
2205 => Regclass: Kind::Simple,
#[doc="REGTYPE - registered type"]
2206 => Regtype: Kind::Simple,
#[doc="REGPROCEDURE[]"]
2207 => RegprocedureArray: Kind::Array(Type::Regprocedure),
#[doc="REGOPER[]"]
2208 => RegoperArray: Kind::Array(Type::Regoper),
#[doc="REGOPERATOR[]"]
2209 => RegoperatorArray: Kind::Array(Type::Regoperator),
#[doc="REGCLASS[]"]
2210 => RegclassArray: Kind::Array(Type::Regclass),
#[doc="REGTYPE[]"]
2211 => RegtypeArray: Kind::Array(Type::Regtype),
#[doc="RECORD"]
2249 => Record: Kind::Simple,
#[doc="CSTRING"]
2275 => Cstring: Kind::Simple,
#[doc="ANY"]
2276 => Any: Kind::Simple,
#[doc="ANY[]"]
2277 => AnyArray: Kind::Array(Type::Any),
#[doc="VOID"]
2278 => Void: Kind::Simple,
#[doc="TRIGGER"]
2279 => Trigger: Kind::Simple,
#[doc="LANGUAGE_HANDLER"]
2280 => LanguageHandler: Kind::Simple,
#[doc="INTERNAL"]
2281 => Internal: Kind::Simple,
#[doc="OPAQUE"]
2282 => Opaque: Kind::Simple,
#[doc="ANYELEMENT"]
2283 => Anyelement: Kind::Simple,
#[doc="RECORD[]"]
2287 => RecordArray: Kind::Array(Type::Record),
#[doc="ANYNONARRAY"]
2776 => Anynonarray: Kind::Simple,
#[doc="TXID_SNAPSHOT[]"]
2949 => TxidSnapshotArray: Kind::Array(Type::TxidSnapshot),
#[doc="UUID - UUID datatype"]
2950 => Uuid: Kind::Simple,
#[doc="TXID_SNAPSHOT - txid snapshot"]
2970 => TxidSnapshot: Kind::Simple,
2014-11-06 15:53:16 +00:00
#[doc="UUID[]"]
2015-02-19 05:04:44 +00:00
2951 => UuidArray: Kind::Array(Type::Uuid),
#[doc="FDW_HANDLER"]
3115 => FdwHandler: Kind::Simple,
#[doc="PG_LSN - PostgreSQL LSN datatype"]
3320 => PgLsn: Kind::Simple,
#[doc="PG_LSN[]"]
3321 => PgLsnArray: Kind::Array(Type::PgLsn),
#[doc="ANYENUM"]
3500 => Anyenum: Kind::Simple,
#[doc="TSVECTOR - text representation for text search"]
3614 => Tsvector: Kind::Simple,
#[doc="TSQUERY - query representation for text search"]
3615 => Tsquery: Kind::Simple,
#[doc="GTSVECTOR - GiST index internal text representation for text search"]
3642 => Gtsvector: Kind::Simple,
#[doc="TSVECTOR[]"]
3643 => TsvectorArray: Kind::Array(Type::Tsvector),
#[doc="GTSVECTOR[]"]
3644 => GtsvectorArray: Kind::Array(Type::Gtsvector),
#[doc="TSQUERY[]"]
3645 => TsqueryArray: Kind::Array(Type::Tsquery),
#[doc="REGCONFIG - registered text search configuration"]
3734 => Regconfig: Kind::Simple,
#[doc="REGCONFIG[]"]
3735 => RegconfigArray: Kind::Array(Type::Regconfig),
#[doc="REGDICTIONARY - registered text search dictionary"]
3769 => Regdictionary: Kind::Simple,
#[doc="REGDICTIONARY[]"]
3770 => RegdictionaryArray: Kind::Array(Type::Regdictionary),
2014-12-23 02:04:13 +00:00
#[doc="JSONB"]
2015-02-19 05:04:44 +00:00
3802 => Jsonb: Kind::Simple,
#[doc="ANYRANGE"]
3831 => Anyrange: Kind::Simple,
2014-12-23 02:04:13 +00:00
#[doc="JSONB[]"]
2015-02-19 05:04:44 +00:00
3807 => JsonbArray: Kind::Array(Type::Jsonb),
#[doc="INT4RANGE - range of integers"]
3904 => Int4Range: Kind::Range(Type::Int4),
2013-12-08 22:37:31 +00:00
#[doc="INT4RANGE[]"]
2015-02-19 05:04:44 +00:00
3905 => Int4RangeArray: Kind::Array(Type::Int4Range),
#[doc="NUMRANGE - range of numerics"]
3906 => NumRange: Kind::Range(Type::Numeric),
#[doc="NUMRANGE[]"]
3907 => NumRangeArray: Kind::Array(Type::NumRange),
#[doc="TSRANGE - range of timestamps without time zone"]
3908 => TsRange: Kind::Range(Type::Timestamp),
2013-12-08 23:02:38 +00:00
#[doc="TSRANGE[]"]
2015-02-19 05:04:44 +00:00
3909 => TsRangeArray: Kind::Array(Type::TsRange),
#[doc="TSTZRANGE - range of timestamps with time zone"]
3910 => TstzRange: Kind::Range(Type::TimestampTZ),
2013-12-08 23:02:38 +00:00
#[doc="TSTZRANGE[]"]
2015-02-19 05:04:44 +00:00
3911 => TstzRangeArray: Kind::Array(Type::TstzRange),
#[doc="DATERANGE - range of dates"]
3912 => DateRange: Kind::Range(Type::Date),
#[doc="DATERANGE[]"]
3913 => DateRangeArray: Kind::Array(Type::DateRange),
#[doc="INT8RANGE - range of bigints"]
3926 => Int8Range: Kind::Range(Type::Int8),
2013-12-08 23:07:11 +00:00
#[doc="INT8RANGE[]"]
2015-02-19 05:04:44 +00:00
3927 => Int8RangeArray: Kind::Array(Type::Int8Range),
#[doc="EVENT_TRIGGER"]
3838 => EventTrigger: Kind::Simple
2014-12-19 18:43:42 +00:00
}
/// Information about an unknown type.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Other {
name: String,
oid: Oid,
kind: Kind,
}
impl OtherNew for Other {
fn new(name: String, oid: Oid, kind: Kind) -> Other {
Other {
name: name,
oid: oid,
kind: kind,
}
}
}
impl Other {
/// The name of the type.
pub fn name(&self) -> &str {
&self.name
}
/// The OID of this type.
pub fn oid(&self) -> Oid {
self.oid
}
/// The kind of this type.
pub fn kind(&self) -> &Kind {
&self.kind
}
}
/// 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`"
}
}
/// 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:
///
/// | 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&lt;u8&gt; | BYTEA |
/// | HashMap&lt;String, Option&lt;String&gt;&gt; | 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. For example, the `serde` feature enables the implementation for the
/// `serde::json::Value` type.
///
2015-07-21 06:16:50 +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&lt;UTC&gt; | TIMESTAMP WITH TIME ZONE |
/// | chrono::DateTime&lt;Local&gt; | TIMESTAMP WITH TIME ZONE |
/// | chrono::DateTime&lt;FixedOffset&gt; | TIMESTAMP WITH TIME ZONE |
/// | chrono::NaiveDate | DATE |
/// | chrono::NaiveTime | TIME |
/// | uuid::Uuid | UUID |
///
/// # 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.
pub trait FromSql: Sized {
2015-02-26 17:02:32 +00:00
/// Creates a new value of this type from a `Read` of Postgres data.
2013-09-30 02:47:30 +00:00
///
2015-02-26 17:02:32 +00:00
/// If the value was `NULL`, the `Read` will be `None`.
///
/// The caller of this method is responsible for ensuring that this type
/// is compatible with the Postgres `Type`.
///
/// The default implementation calls `FromSql::from_sql` when `raw` is
/// `Some` and returns `Err(Error::Conversion(Box::new(WasNull))` when
/// `raw` is `None`. It does not typically need to be overridden.
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
-> Result<Self> {
match raw {
Some(raw) => FromSql::from_sql(ty, raw, ctx),
None => Err(Error::Conversion(Box::new(WasNull))),
}
}
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`.
///
/// The caller of this method is responsible for ensuring that this type
/// is compatible with the Postgres `Type`.
fn from_sql<R: Read>(ty: &Type, raw: &mut R, ctx: &SessionInfo) -> Result<Self>;
/// 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> {
fn from_sql_nullable<R: Read>(ty: &Type, raw: Option<&mut R>, ctx: &SessionInfo)
-> Result<Option<T>> {
match raw {
Some(raw) => <T as FromSql>::from_sql(ty, raw, ctx).map(Some),
None => Ok(None),
}
}
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 accepts(ty: &Type) -> bool {
<T as FromSql>::accepts(ty)
2013-12-07 23:39:44 +00:00
}
}
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>> {
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-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<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));
String::from_utf8(buf).map_err(|err| Error::Conversion(Box::new(err)))
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
}
2015-05-02 22:55:53 +00:00
impl FromSql for i8 {
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);
}
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> {
2015-02-26 17:02:32 +00:00
Ok(try!(raw.$f::<BigEndian>()))
}
2014-11-17 17:43: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);
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();
2015-02-26 17:02:32 +00:00
let count = try!(raw.read_i32::<BigEndian>());
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];
2015-04-08 06:57:22 +00:00
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))),
};
2015-02-26 17:02:32 +00:00
let val_len = try!(raw.read_i32::<BigEndian>());
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];
2015-04-08 06:57:22 +00:00
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)
}
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,
_ => 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:
///
/// | 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&lt;u8&gt; | BYTEA |
/// | &[u8] | BYTEA |
/// | HashMap&lt;String, Option&lt;String&gt;&gt; | 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. For example, the `serde` feature enables the implementation for the
/// `serde::json::Value` type.
///
2015-07-21 06:16:50 +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&lt;UTC&gt; | TIMESTAMP WITH TIME ZONE |
/// | chrono::DateTime&lt;Local&gt; | TIMESTAMP WITH TIME ZONE |
/// | chrono::DateTime&lt;FixedOffset&gt; | TIMESTAMP WITH TIME ZONE |
/// | chrono::NaiveDate | DATE |
/// | chrono::NaiveTime | TIME |
/// | uuid::Uuid | UUID |
///
/// # 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.
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-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`.
fn to_sql<W: ?Sized>(&self, ty: &Type, out: &mut W, ctx: &SessionInfo) -> Result<IsNull>
2015-02-26 17:02:32 +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.
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull>;
2013-10-31 02:55:25 +00:00
}
2015-02-15 23:11:15 +00:00
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> {
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
impl ToSql for bool {
to_sql_checked!();
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
}
2015-02-15 23:11:15 +00:00
impl<'a> ToSql for &'a [u8] {
// FIXME should use to_sql_checked!() but blocked on rust-lang/rust#24308
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull> {
if !<&'a [u8] as ToSql>::accepts(ty) {
return Err(Error::WrongType(ty.clone()));
}
self.to_sql(ty, out, ctx)
}
2013-10-31 02:55:25 +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)
}
2015-02-15 23:11:15 +00:00
accepts!(Type::Bytea);
}
2015-02-15 23:11:15 +00:00
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)
}
2015-02-15 23:11:15 +00:00
fn accepts(ty: &Type) -> bool {
<&[u8] as ToSql>::accepts(ty)
}
}
impl<'a> ToSql for &'a str {
// FIXME should use to_sql_checked!() but blocked on rust-lang/rust#24308
fn to_sql_checked(&self, ty: &Type, out: &mut Write, ctx: &SessionInfo)
-> Result<IsNull> {
if !<&'a str as ToSql>::accepts(ty) {
return Err(Error::WrongType(ty.clone()));
}
self.to_sql(ty, out, ctx)
}
2015-02-15 23:11:15 +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 {
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
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)
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
impl ToSql for i8 {
to_sql_checked!();
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!();
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),+);
}
}
}
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
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-02-26 17:02:32 +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 {
let err: Box<error::Error+Sync+Send> = "value too large to transmit".into();
Err(Error::Conversion(err))
} else {
Ok(len as i32)
}
}