From 1db85d1069cb2af9bf436d5dee49b4d9b8eb9602 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 6 Aug 2019 08:58:51 -0700 Subject: [PATCH] Generalize ToSql, AsSql, FromSql, and FromSql over Backend --- src/backend.rs | 8 ++ src/deserialize.rs | 27 +++++ src/lib.rs | 3 + src/postgres/connection/get.rs | 13 ++- src/postgres/connection/prepare.rs | 14 ++- src/postgres/connection/select.rs | 11 ++- src/postgres/mod.rs | 11 +++ src/postgres/protocol/bind.rs | 16 +-- src/postgres/protocol/data_row.rs | 10 +- src/postgres/types/boolean.rs | 32 ++++-- src/postgres/types/character.rs | 50 +++++++--- src/postgres/types/mod.rs | 5 + src/postgres/types/numeric.rs | 122 +++++++++++++++++------ src/row.rs | 153 ++++++++++++++++++++++------- src/serialize.rs | 36 +++++++ src/types.rs | 75 +++++++------- 16 files changed, 437 insertions(+), 149 deletions(-) create mode 100644 src/backend.rs create mode 100644 src/deserialize.rs create mode 100644 src/serialize.rs diff --git a/src/backend.rs b/src/backend.rs new file mode 100644 index 00000000..45451f6a --- /dev/null +++ b/src/backend.rs @@ -0,0 +1,8 @@ +use crate::row::RawRow; + +pub trait Backend { + type RawRow: RawRow; + + /// The type used to represent metadata associated with a SQL type. + type TypeMetadata; +} diff --git a/src/deserialize.rs b/src/deserialize.rs new file mode 100644 index 00000000..8ebaed77 --- /dev/null +++ b/src/deserialize.rs @@ -0,0 +1,27 @@ +use crate::{ + backend::Backend, + types::{AsSql, SqlType}, +}; + +// TODO: Allow from_sql to return an error (that can be unified) +// TODO: Consider using a RawValue wrapper type instead of exposing raw bytes (as different back-ends may want to expose different data here.. maybe?) + +pub trait FromSql: AsSql +where + B: Backend, + ST: SqlType, +{ + fn from_sql(raw: Option<&[u8]>) -> Self; +} + +impl FromSql for Option +where + B: Backend, + ST: SqlType, + T: FromSql, +{ + #[inline] + fn from_sql(raw: Option<&[u8]>) -> Self { + Some(T::from_sql(Some(raw?))) + } +} diff --git a/src/lib.rs b/src/lib.rs index 22f394e1..0c754f68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,5 +22,8 @@ pub mod postgres; #[macro_use] pub mod macros; +pub mod backend; +pub mod deserialize; pub mod row; +pub mod serialize; pub mod types; diff --git a/src/postgres/connection/get.rs b/src/postgres/connection/get.rs index 60906532..ed28df43 100644 --- a/src/postgres/connection/get.rs +++ b/src/postgres/connection/get.rs @@ -1,6 +1,9 @@ use super::prepare::Prepare; use crate::{ - postgres::protocol::{self, DataRow, Message}, + postgres::{ + protocol::{self, DataRow, Message}, + Postgres, + }, row::{FromRow, Row}, types::SqlType, }; @@ -12,19 +15,19 @@ impl<'a, 'b> Prepare<'a, 'b> { #[inline] pub async fn get(self) -> io::Result where - T: FromRow, + T: FromRow, { Ok(T::from_row(self.get_raw().await?.unwrap())) } // TODO: Better name? // TODO: Should this be public? - async fn get_raw(self) -> io::Result> { + async fn get_raw(self) -> io::Result>> { let conn = self.finish(); conn.flush().await?; - let mut row: Option = None; + let mut row: Option> = None; while let Some(message) = conn.receive().await? { match message { @@ -37,7 +40,7 @@ impl<'a, 'b> Prepare<'a, 'b> { Message::DataRow(body) => { // note: because we used `EXECUTE 1` this will only execute once - row = Some(Row(body)); + row = Some(Row::(body)); } Message::CommandComplete(_) => {} diff --git a/src/postgres/connection/prepare.rs b/src/postgres/connection/prepare.rs index 89ee593b..1852cbfb 100644 --- a/src/postgres/connection/prepare.rs +++ b/src/postgres/connection/prepare.rs @@ -1,7 +1,11 @@ use super::Connection; use crate::{ - postgres::protocol::{self, BindValues}, - types::{SqlType, ToSql, ToSqlAs}, + postgres::{ + protocol::{self, BindValues}, + Postgres, + }, + serialize::ToSql, + types::{AsSql, SqlType}, }; pub struct Prepare<'a, 'b> { @@ -23,16 +27,16 @@ pub fn prepare<'a, 'b>(connection: &'a mut Connection, query: &'b str) -> Prepar impl<'a, 'b> Prepare<'a, 'b> { #[inline] - pub fn bind(mut self, value: T) -> Self + pub fn bind>(mut self, value: T) -> Self where - T: ToSqlAs<::Type>, + T: ToSql>::Type>, { self.bind.add(value); self } #[inline] - pub fn bind_as>(mut self, value: T) -> Self { + pub fn bind_as, T: ToSql>(mut self, value: T) -> Self { self.bind.add_as::(value); self } diff --git a/src/postgres/connection/select.rs b/src/postgres/connection/select.rs index 1bad14f0..12b71b3a 100644 --- a/src/postgres/connection/select.rs +++ b/src/postgres/connection/select.rs @@ -1,6 +1,9 @@ use super::prepare::Prepare; use crate::{ - postgres::protocol::{self, DataRow, Message}, + postgres::{ + protocol::{self, DataRow, Message}, + Postgres, + }, row::{FromRow, Row}, }; use futures::{stream, Stream, TryStreamExt}; @@ -12,14 +15,14 @@ impl<'a, 'b> Prepare<'a, 'b> { self, ) -> impl Stream> + 'a + Unpin where - T: FromRow, + T: FromRow, { self.select_raw().map_ok(T::from_row) } // TODO: Better name? // TODO: Should this be public? - fn select_raw(self) -> impl Stream> + 'a + Unpin { + fn select_raw(self) -> impl Stream, io::Error>> + 'a + Unpin { // FIXME: Manually implement Stream on a new type to avoid the unfold adapter stream::unfold(self.finish(), |conn| { Box::pin(async { @@ -43,7 +46,7 @@ impl<'a, 'b> Prepare<'a, 'b> { } Message::DataRow(row) => { - break Some((Ok(Row(row)), conn)); + break Some((Ok(Row::(row)), conn)); } Message::CommandComplete(_) => {} diff --git a/src/postgres/mod.rs b/src/postgres/mod.rs index 63964864..d11eccc0 100644 --- a/src/postgres/mod.rs +++ b/src/postgres/mod.rs @@ -1,5 +1,16 @@ +use crate::backend::Backend; + mod connection; + pub use connection::Connection; pub(crate) mod protocol; + pub mod types; + +pub struct Postgres; + +impl Backend for Postgres { + type RawRow = protocol::DataRow; + type TypeMetadata = types::TypeMetadata; +} diff --git a/src/postgres/protocol/bind.rs b/src/postgres/protocol/bind.rs index 211b19e9..f2655b81 100644 --- a/src/postgres/protocol/bind.rs +++ b/src/postgres/protocol/bind.rs @@ -1,5 +1,9 @@ use super::{BufMut, Encode}; -use crate::types::{SqlType, ToSql, ToSqlAs}; +use crate::{ + postgres::Postgres, + serialize::ToSql, + types::{AsSql, SqlType}, +}; use byteorder::{BigEndian, ByteOrder}; const TEXT: i16 = 0; @@ -24,18 +28,18 @@ impl BindValues { } #[inline] - pub fn add(&mut self, value: T) + pub fn add>(&mut self, value: T) where - T: ToSqlAs<::Type>, + T: ToSql>::Type>, { self.add_as::(value); } - pub fn add_as>(&mut self, value: T) { + pub fn add_as, T: ToSql>(&mut self, value: T) { // TODO: When/if we receive types that do _not_ support BINARY, we need to check here // TODO: There is no need to be explicit unless we are expecting mixed BINARY / TEXT - self.types.push(ST::OID as i32); + self.types.push(ST::metadata().oid as i32); let pos = self.values.len(); self.values.put_int_32(0); // skip over len @@ -120,7 +124,7 @@ impl Encode for Bind<'_> { mod tests { use super::{Bind, BindValues, BufMut, Encode}; - const BIND: &[u8] = b"B\0\0\0\x16\0\0\0\0\0\x02\0\0\0\x011\0\0\0\x012\0\0"; + const BIND: &[u8] = b"B\0\0\0\x18\0\0\0\x01\0\x01\0\x02\0\0\0\x011\0\0\0\x012\0\0"; #[test] fn it_encodes_bind_for_two() { diff --git a/src/postgres/protocol/data_row.rs b/src/postgres/protocol/data_row.rs index 52169a1d..a663a146 100644 --- a/src/postgres/protocol/data_row.rs +++ b/src/postgres/protocol/data_row.rs @@ -1,4 +1,5 @@ use super::Decode; +use crate::row::RawRow; use bytes::Bytes; use std::{ convert::TryInto, @@ -46,19 +47,19 @@ impl Decode for DataRow { } } -impl DataRow { +impl RawRow for DataRow { #[inline] - pub fn is_empty(&self) -> bool { + fn is_empty(&self) -> bool { self.ranges.is_empty() } #[inline] - pub fn len(&self) -> usize { + fn len(&self) -> usize { self.ranges.len() } #[inline] - pub fn get(&self, index: usize) -> Option<&[u8]> { + fn get(&self, index: usize) -> Option<&[u8]> { Some(&self.buf[self.ranges[index].clone()?]) } } @@ -81,6 +82,7 @@ impl Debug for DataRow { #[cfg(test)] mod tests { use super::{DataRow, Decode}; + use crate::row::RawRow; use bytes::Bytes; use std::io; diff --git a/src/postgres/types/boolean.rs b/src/postgres/types/boolean.rs index 42b14163..5ea66d43 100644 --- a/src/postgres/types/boolean.rs +++ b/src/postgres/types/boolean.rs @@ -1,25 +1,39 @@ -use crate::types::{FromSql, SqlType, ToSql, ToSqlAs}; +use super::TypeMetadata; +use crate::{ + deserialize::FromSql, + postgres::Postgres, + serialize::{IsNull, ToSql}, + types::{AsSql, SqlType}, +}; pub struct Bool; -impl SqlType for Bool { - const OID: u32 = 16; +impl SqlType for Bool { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 16, + array_oid: 1000, + } + } } -impl ToSql for bool { +impl AsSql for bool { type Type = Bool; } -impl ToSqlAs for bool { +impl ToSql for bool { #[inline] - fn to_sql(self, buf: &mut Vec) { + fn to_sql(self, buf: &mut Vec) -> IsNull { buf.push(self as u8); + + IsNull::No } } -impl FromSql for bool { +impl FromSql for bool { #[inline] - fn from_sql(buf: &[u8]) -> Self { - buf[0] != 0 + fn from_sql(buf: Option<&[u8]>) -> Self { + // TODO: Handle optionals + buf.unwrap()[0] != 0 } } diff --git a/src/postgres/types/character.rs b/src/postgres/types/character.rs index 1bf0ccec..9f73c0b1 100644 --- a/src/postgres/types/character.rs +++ b/src/postgres/types/character.rs @@ -1,31 +1,51 @@ -use crate::types::{FromSql, Text, ToSql, ToSqlAs}; +use super::TypeMetadata; +use crate::{ + deserialize::FromSql, + postgres::Postgres, + serialize::{IsNull, ToSql}, + types::{AsSql, SqlType, Text}, +}; -impl ToSql for &'_ str { - type Type = Text; -} - -impl ToSqlAs for &'_ str { - #[inline] - fn to_sql(self, buf: &mut Vec) { - buf.extend_from_slice(self.as_bytes()); +impl SqlType for Text { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 25, + array_oid: 1009, + } } } -impl ToSql for String { +impl AsSql for &'_ str { type Type = Text; } -impl ToSqlAs for String { +impl ToSql for &'_ str { #[inline] - fn to_sql(self, buf: &mut Vec) { + fn to_sql(self, buf: &mut Vec) -> IsNull { buf.extend_from_slice(self.as_bytes()); + + IsNull::No } } -impl FromSql for String { +impl AsSql for String { + type Type = Text; +} + +impl ToSql for String { #[inline] - fn from_sql(buf: &[u8]) -> Self { + fn to_sql(self, buf: &mut Vec) -> IsNull { + buf.extend_from_slice(self.as_bytes()); + + IsNull::No + } +} + +impl FromSql for String { + #[inline] + fn from_sql(buf: Option<&[u8]>) -> Self { + // TODO: Handle optionals // Using lossy here as it should be impossible to get non UTF8 data here - String::from_utf8_lossy(buf).into() + String::from_utf8_lossy(buf.unwrap()).into() } } diff --git a/src/postgres/types/mod.rs b/src/postgres/types/mod.rs index 34ef342c..01cf50af 100644 --- a/src/postgres/types/mod.rs +++ b/src/postgres/types/mod.rs @@ -3,3 +3,8 @@ mod character; mod numeric; pub use self::boolean::Bool; + +pub struct TypeMetadata { + pub oid: u32, + pub array_oid: u32, +} diff --git a/src/postgres/types/numeric.rs b/src/postgres/types/numeric.rs index 47aea654..d41554ea 100644 --- a/src/postgres/types/numeric.rs +++ b/src/postgres/types/numeric.rs @@ -1,92 +1,152 @@ -use crate::types::{BigInt, Double, FromSql, Int, Real, SmallInt, ToSql, ToSqlAs}; +use super::TypeMetadata; +use crate::{ + deserialize::FromSql, + postgres::Postgres, + serialize::{IsNull, ToSql}, + types::{AsSql, BigInt, Double, Int, Real, SmallInt, SqlType}, +}; use byteorder::{BigEndian, ByteOrder}; -impl ToSql for i16 { +impl SqlType for SmallInt { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 21, + array_oid: 1005, + } + } +} + +impl AsSql for i16 { type Type = SmallInt; } -impl ToSqlAs for i16 { +impl ToSql for i16 { #[inline] - fn to_sql(self, buf: &mut Vec) { + fn to_sql(self, buf: &mut Vec) -> IsNull { buf.extend_from_slice(&self.to_be_bytes()); + + IsNull::No } } -impl FromSql for i16 { +impl FromSql for i16 { #[inline] - fn from_sql(buf: &[u8]) -> Self { - BigEndian::read_i16(buf) + fn from_sql(buf: Option<&[u8]>) -> Self { + // TODO: Handle optionals + BigEndian::read_i16(buf.unwrap()) } } -impl ToSql for i32 { +impl SqlType for Int { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 23, + array_oid: 1007, + } + } +} + +impl AsSql for i32 { type Type = Int; } -impl ToSqlAs for i32 { +impl ToSql for i32 { #[inline] - fn to_sql(self, buf: &mut Vec) { + fn to_sql(self, buf: &mut Vec) -> IsNull { buf.extend_from_slice(&self.to_be_bytes()); + + IsNull::No } } -impl FromSql for i32 { +impl FromSql for i32 { #[inline] - fn from_sql(buf: &[u8]) -> Self { - BigEndian::read_i32(buf) + fn from_sql(buf: Option<&[u8]>) -> Self { + // TODO: Handle optionals + BigEndian::read_i32(buf.unwrap()) } } -impl ToSql for i64 { +impl SqlType for BigInt { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 20, + array_oid: 1016, + } + } +} + +impl AsSql for i64 { type Type = BigInt; } -impl ToSqlAs for i64 { +impl ToSql for i64 { #[inline] - fn to_sql(self, buf: &mut Vec) { + fn to_sql(self, buf: &mut Vec) -> IsNull { buf.extend_from_slice(&self.to_be_bytes()); + + IsNull::No } } -impl FromSql for i64 { +impl FromSql for i64 { #[inline] - fn from_sql(buf: &[u8]) -> Self { - BigEndian::read_i64(buf) + fn from_sql(buf: Option<&[u8]>) -> Self { + // TODO: Handle optionals + BigEndian::read_i64(buf.unwrap()) } } -impl ToSql for f32 { +impl SqlType for Real { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 700, + array_oid: 1021, + } + } +} + +impl AsSql for f32 { type Type = Real; } -impl ToSqlAs for f32 { +impl ToSql for f32 { #[inline] - fn to_sql(self, buf: &mut Vec) { - (self.to_bits() as i32).to_sql(buf); + fn to_sql(self, buf: &mut Vec) -> IsNull { + (self.to_bits() as i32).to_sql(buf) } } -impl FromSql for f32 { +impl FromSql for f32 { #[inline] - fn from_sql(buf: &[u8]) -> Self { + fn from_sql(buf: Option<&[u8]>) -> Self { f32::from_bits(i32::from_sql(buf) as u32) } } -impl ToSql for f64 { +impl SqlType for Double { + fn metadata() -> TypeMetadata { + TypeMetadata { + oid: 701, + array_oid: 1022, + } + } +} + +impl AsSql for f64 { type Type = Double; } -impl ToSqlAs for f64 { +impl ToSql for f64 { #[inline] - fn to_sql(self, buf: &mut Vec) { - (self.to_bits() as i64).to_sql(buf); + fn to_sql(self, buf: &mut Vec) -> IsNull { + (self.to_bits() as i64).to_sql(buf) } } -impl FromSql for f64 { +impl FromSql for f64 { #[inline] - fn from_sql(buf: &[u8]) -> Self { + fn from_sql(buf: Option<&[u8]>) -> Self { f64::from_bits(i64::from_sql(buf) as u64) } } diff --git a/src/row.rs b/src/row.rs index e9c8eaf0..f1429a1c 100644 --- a/src/row.rs +++ b/src/row.rs @@ -1,57 +1,140 @@ use crate::{ - postgres::protocol::DataRow, - types::{FromSql, SqlType}, + backend::Backend, + deserialize::FromSql, + postgres::{protocol::DataRow, Postgres}, + types::SqlType, }; -// TODO: Make this generic over backend -pub struct Row(pub(crate) DataRow); +pub trait RawRow { + fn is_empty(&self) -> bool; -impl Row { + fn len(&self) -> usize; + + fn get(&self, index: usize) -> Option<&[u8]>; +} + +pub struct Row(pub(crate) B::RawRow) +where + B: Backend; + +impl Row +where + B: Backend, +{ #[inline] pub fn get(&self, index: usize) -> T where - ST: SqlType, - T: FromSql, + ST: SqlType, + T: FromSql, { - T::from_sql(self.0.get(index).unwrap()) + T::from_sql(self.0.get(index)) } } -pub trait FromRow { - fn from_row(row: Row) -> Self; +pub trait FromRow +where + B: Backend, +{ + fn from_row(row: Row) -> Self; } -impl FromRow for T +impl FromRow for T where - ST: SqlType, - T: FromSql, + B: Backend, + ST: SqlType, + T: FromSql, { #[inline] - fn from_row(row: Row) -> Self { + fn from_row(row: Row) -> Self { row.get::(0) } } -impl FromRow<(ST1,)> for (T1,) -where - ST1: SqlType, - T1: FromSql, -{ - #[inline] - fn from_row(row: Row) -> Self { - (row.get::(0),) - } +// TODO: Think of a better way to generate these tuple implementations + +macro_rules! impl_from_row_tuple { + ($B:ident: $( ($idx:tt) -> $T:ident, $ST:ident );+;) => { + impl<$($ST,)+ $($T,)+> FromRow for ($($T,)+) + where + $($ST: SqlType,)+ + $($T: FromSql,)+ + { + #[inline] + fn from_row(row: Row<$B>) -> Self { + ($(row.get::<$ST, $T>($idx),)+) + } + } + }; } -impl FromRow<(ST1, ST2)> for (T1, T2) -where - ST1: SqlType, - ST2: SqlType, - T1: FromSql, - T2: FromSql, -{ - #[inline] - fn from_row(row: Row) -> Self { - (row.get::(0), row.get::(1)) - } -} +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; + (3) -> ST4, T4; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; + (3) -> ST4, T4; + (4) -> ST5, T5; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; + (3) -> ST4, T4; + (4) -> ST5, T5; + (5) -> ST6, T6; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; + (3) -> ST4, T4; + (4) -> ST5, T5; + (5) -> ST6, T6; + (6) -> ST7, T7; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; + (3) -> ST4, T4; + (4) -> ST5, T5; + (5) -> ST6, T6; + (6) -> ST7, T7; + (7) -> ST8, T8; +); + +impl_from_row_tuple!(Postgres: + (0) -> ST1, T1; + (1) -> ST2, T2; + (2) -> ST3, T3; + (3) -> ST4, T4; + (4) -> ST5, T5; + (5) -> ST6, T6; + (6) -> ST7, T7; + (7) -> ST8, T8; + (8) -> ST9, T9; +); diff --git a/src/serialize.rs b/src/serialize.rs new file mode 100644 index 00000000..ec25ca1c --- /dev/null +++ b/src/serialize.rs @@ -0,0 +1,36 @@ +use crate::{ + backend::Backend, + types::{AsSql, SqlType}, +}; + +/// Annotates the result of [ToSql] to differentiate between an empty value and a null value. +pub enum IsNull { + /// The value was null (and no data was written to the buffer). + Yes, + + /// The value was not null. + /// + /// This does not necessarily mean that any data was written to the buffer. + No, +} + +/// Serializes a single value to be sent to the database. +pub trait ToSql: AsSql +where + B: Backend, + ST: SqlType, +{ + fn to_sql(self, buf: &mut Vec) -> IsNull; +} + +impl ToSql for Option +where + B: Backend, + ST: SqlType, + T: ToSql, +{ + #[inline] + fn to_sql(self, _buf: &mut Vec) -> IsNull { + IsNull::Yes + } +} diff --git a/src/types.rs b/src/types.rs index 8c897e1a..eccbee60 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,27 +1,33 @@ +use crate::backend::Backend; + pub use crate::postgres::types::*; -// TODO: Better name for ToSql/ToSqlAs. ToSqlAs is the _conversion_ trait. -// ToSql is type fallback for Rust/SQL (e.g., what is the probable SQL type for this Rust type) +// TODO: Does [AsSql] need to be generic over back-end ? -// TODO: Make generic over backend - -pub trait SqlType { - // FIXME: This is a postgres thing - const OID: u32; +pub trait SqlType +where + B: Backend, +{ + // FIXME: This should be a const fn + fn metadata() -> B::TypeMetadata; } -pub trait ToSql { +/// Defines the canonical SQL that the implementing Rust type represents. +/// This trait is used to map Rust types to SQL types when the explicit mapping is missing. +pub trait AsSql +where + B: Backend, +{ /// SQL type that should be inferred from the implementing Rust type. - type Type: SqlType; + type Type: SqlType; } -pub trait ToSqlAs: ToSql { - fn to_sql(self, buf: &mut Vec); -} - -pub trait FromSql: ToSql { - // TODO: Errors? - fn from_sql(buf: &[u8]) -> Self; +impl AsSql for Option +where + B: Backend, + T: AsSql, +{ + type Type = T::Type; } // Character types @@ -30,33 +36,32 @@ pub trait FromSql: ToSql { pub struct Text; -impl SqlType for Text { - // FIXME: This is postgres-specific - const OID: u32 = 25; -} +// impl SqlType for Text { +// const OID: u32 = 25; +// } // Numeric types // i16 pub struct SmallInt; -impl SqlType for SmallInt { - const OID: u32 = 21; -} +// impl SqlType for SmallInt { +// const OID: u32 = 21; +// } // i32 pub struct Int; -impl SqlType for Int { - const OID: u32 = 23; -} +// impl SqlType for Int { +// const OID: u32 = 23; +// } // i64 pub struct BigInt; -impl SqlType for BigInt { - const OID: u32 = 20; -} +// impl SqlType for BigInt { +// const OID: u32 = 20; +// } // decimal? // TODO pub struct Decimal; @@ -64,13 +69,13 @@ impl SqlType for BigInt { // f32 pub struct Real; -impl SqlType for Real { - const OID: u32 = 700; -} +// impl SqlType for Real { +// const OID: u32 = 700; +// } // f64 pub struct Double; -impl SqlType for Double { - const OID: u32 = 701; -} +// impl SqlType for Double { +// const OID: u32 = 701; +// }