@@ -156,11 +156,11 @@ impl Other {
|
||||
#[doc(hidden)]
|
||||
pub fn new(name: String, oid: Oid, kind: Kind, schema: String) -> Other {
|
||||
Other(Arc::new(OtherInner {
|
||||
name: name,
|
||||
oid: oid,
|
||||
kind: kind,
|
||||
schema: schema,
|
||||
}))
|
||||
name: name,
|
||||
oid: oid,
|
||||
kind: kind,
|
||||
schema: schema,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,19 +236,19 @@ impl WrongType {
|
||||
/// 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, NAME |
|
||||
/// | `Vec<u8>` | BYTEA |
|
||||
/// | `HashMap<String, Option<String>>` | HSTORE |
|
||||
/// | 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, NAME, UNKNOWN |
|
||||
/// | `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
|
||||
@@ -288,9 +288,7 @@ pub trait FromSql: Sized {
|
||||
///
|
||||
/// The caller of this method is responsible for ensuring that this type
|
||||
/// is compatible with the Postgres `Type`.
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Self, Box<Error + Sync + Send>>;
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<Error + Sync + Send>>;
|
||||
|
||||
/// Creates a new value of this type from a `NULL` SQL value.
|
||||
///
|
||||
@@ -306,9 +304,7 @@ pub trait FromSql: Sized {
|
||||
|
||||
/// A convenience function that delegates to `from_sql` and `from_sql_null` depending on the
|
||||
/// value of `raw`.
|
||||
fn from_sql_nullable(ty: &Type,
|
||||
raw: Option<&[u8]>)
|
||||
-> Result<Self, Box<Error + Sync + Send>> {
|
||||
fn from_sql_nullable(ty: &Type, raw: Option<&[u8]>) -> Result<Self, Box<Error + Sync + Send>> {
|
||||
match raw {
|
||||
Some(raw) => Self::from_sql(ty, raw),
|
||||
None => Self::from_sql_null(ty),
|
||||
@@ -321,9 +317,7 @@ pub trait FromSql: Sized {
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Option<T> {
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Option<T>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Option<T>, Box<Error + Sync + Send>> {
|
||||
<T as FromSql>::from_sql(ty, raw).map(Some)
|
||||
}
|
||||
|
||||
@@ -337,9 +331,7 @@ impl<T: FromSql> FromSql for Option<T> {
|
||||
}
|
||||
|
||||
impl<T: FromSql> FromSql for Vec<T> {
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Vec<T>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> Result<Vec<T>, Box<Error + Sync + Send>> {
|
||||
let member_type = match *ty.kind() {
|
||||
Kind::Array(ref member) => member,
|
||||
_ => panic!("expected array type"),
|
||||
@@ -350,7 +342,8 @@ impl<T: FromSql> FromSql for Vec<T> {
|
||||
return Err("array contains too many dimensions".into());
|
||||
}
|
||||
|
||||
array.values()
|
||||
array
|
||||
.values()
|
||||
.and_then(|v| T::from_sql_nullable(member_type, v))
|
||||
.collect()
|
||||
}
|
||||
@@ -364,9 +357,7 @@ impl<T: FromSql> FromSql for Vec<T> {
|
||||
}
|
||||
|
||||
impl FromSql for Vec<u8> {
|
||||
fn from_sql(_: &Type,
|
||||
raw: &[u8])
|
||||
-> Result<Vec<u8>, Box<Error + Sync + Send>> {
|
||||
fn from_sql(_: &Type, raw: &[u8]) -> Result<Vec<u8>, Box<Error + Sync + Send>> {
|
||||
Ok(types::bytea_from_sql(raw).to_owned())
|
||||
}
|
||||
|
||||
@@ -380,7 +371,7 @@ impl FromSql for String {
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
match *ty {
|
||||
Type::Varchar | Type::Text | Type::Bpchar | Type::Name => true,
|
||||
Type::Varchar | Type::Text | Type::Bpchar | Type::Name | Type::Unknown => true,
|
||||
Type::Other(ref u) if u.name() == "citext" => true,
|
||||
_ => false,
|
||||
}
|
||||
@@ -500,10 +491,7 @@ pub trait ToSql: fmt::Debug {
|
||||
/// 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(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>>
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>>
|
||||
where Self: Sized;
|
||||
|
||||
/// Determines if a value of this type can be converted to the specified
|
||||
@@ -523,10 +511,7 @@ pub trait ToSql: fmt::Debug {
|
||||
impl<'a, T> ToSql for &'a T
|
||||
where T: ToSql
|
||||
{
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
(*self).to_sql(ty, out)
|
||||
}
|
||||
|
||||
@@ -538,10 +523,7 @@ impl<'a, T> ToSql for &'a T
|
||||
}
|
||||
|
||||
impl<T: ToSql> ToSql for Option<T> {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
match *self {
|
||||
Some(ref val) => val.to_sql(ty, out),
|
||||
None => Ok(IsNull::Yes),
|
||||
@@ -556,10 +538,7 @@ impl<T: ToSql> ToSql for Option<T> {
|
||||
}
|
||||
|
||||
impl<'a, T: ToSql> ToSql for &'a [T] {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
let member_type = match *ty.kind() {
|
||||
Kind::Array(ref member) => member,
|
||||
_ => panic!("expected array type"),
|
||||
@@ -571,16 +550,14 @@ impl<'a, T: ToSql> ToSql for &'a [T] {
|
||||
};
|
||||
|
||||
types::array_to_sql(Some(dimension),
|
||||
true,
|
||||
member_type.oid(),
|
||||
self.iter(),
|
||||
|e, w| {
|
||||
match e.to_sql(member_type, w)? {
|
||||
IsNull::No => Ok(postgres_protocol::IsNull::No),
|
||||
IsNull::Yes => Ok(postgres_protocol::IsNull::Yes),
|
||||
}
|
||||
},
|
||||
w)?;
|
||||
true,
|
||||
member_type.oid(),
|
||||
self.iter(),
|
||||
|e, w| match e.to_sql(member_type, w)? {
|
||||
IsNull::No => Ok(postgres_protocol::IsNull::No),
|
||||
IsNull::Yes => Ok(postgres_protocol::IsNull::Yes),
|
||||
},
|
||||
w)?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
@@ -595,10 +572,7 @@ impl<'a, T: ToSql> ToSql for &'a [T] {
|
||||
}
|
||||
|
||||
impl<'a> ToSql for &'a [u8] {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::bytea_to_sql(*self, w);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
@@ -609,10 +583,7 @@ impl<'a> ToSql for &'a [u8] {
|
||||
}
|
||||
|
||||
impl<T: ToSql> ToSql for Vec<T> {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
<&[T] as ToSql>::to_sql(&&**self, ty, w)
|
||||
}
|
||||
|
||||
@@ -624,10 +595,7 @@ impl<T: ToSql> ToSql for Vec<T> {
|
||||
}
|
||||
|
||||
impl ToSql for Vec<u8> {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
<&[u8] as ToSql>::to_sql(&&**self, ty, w)
|
||||
}
|
||||
|
||||
@@ -639,10 +607,7 @@ impl ToSql for Vec<u8> {
|
||||
}
|
||||
|
||||
impl<'a> ToSql for &'a str {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::text_to_sql(*self, w);
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
@@ -659,10 +624,7 @@ impl<'a> ToSql for &'a str {
|
||||
}
|
||||
|
||||
impl ToSql for String {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
fn to_sql(&self, ty: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
<&str as ToSql>::to_sql(&&**self, ty, w)
|
||||
}
|
||||
|
||||
@@ -701,11 +663,9 @@ simple_to!(f32, float4_to_sql, Type::Float4);
|
||||
simple_to!(f64, float8_to_sql, Type::Float8);
|
||||
|
||||
impl ToSql for HashMap<String, Option<String>> {
|
||||
fn to_sql(&self,
|
||||
_: &Type,
|
||||
w: &mut Vec<u8>)
|
||||
-> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::hstore_to_sql(self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))), w)?;
|
||||
fn to_sql(&self, _: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
|
||||
types::hstore_to_sql(self.iter().map(|(k, v)| (&**k, v.as_ref().map(|v| &**v))),
|
||||
w)?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ mod chrono;
|
||||
#[cfg(feature = "with-geo")]
|
||||
mod geo;
|
||||
|
||||
fn test_type<T: PartialEq+FromSql+ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
|
||||
fn test_type<T: PartialEq + FromSql + ToSql, S: fmt::Display>(sql_type: &str, checks: &[(T, S)]) {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
for &(ref val, ref repr) in checks.iter() {
|
||||
let stmt = or_panic!(conn.prepare(&*format!("SELECT {}::{}", *repr, sql_type)));
|
||||
@@ -49,8 +49,8 @@ fn test_ref_tosql() {
|
||||
|
||||
#[test]
|
||||
fn test_bool_params() {
|
||||
test_type("BOOL", &[(Some(true), "'t'"), (Some(false), "'f'"),
|
||||
(None, "NULL")]);
|
||||
test_type("BOOL",
|
||||
&[(Some(true), "'t'"), (Some(false), "'f'"), (None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -60,63 +60,79 @@ fn test_i8_params() {
|
||||
|
||||
#[test]
|
||||
fn test_name_params() {
|
||||
test_type("NAME", &[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
test_type("NAME",
|
||||
&[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i16_params() {
|
||||
test_type("SMALLINT", &[(Some(15001i16), "15001"),
|
||||
(Some(-15001i16), "-15001"), (None, "NULL")]);
|
||||
test_type("SMALLINT",
|
||||
&[(Some(15001i16), "15001"),
|
||||
(Some(-15001i16), "-15001"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i32_params() {
|
||||
test_type("INT", &[(Some(2147483548i32), "2147483548"),
|
||||
(Some(-2147483548i32), "-2147483548"), (None, "NULL")]);
|
||||
test_type("INT",
|
||||
&[(Some(2147483548i32), "2147483548"),
|
||||
(Some(-2147483548i32), "-2147483548"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_oid_params() {
|
||||
test_type("OID", &[(Some(2147483548u32), "2147483548"),
|
||||
(Some(4000000000), "4000000000"), (None, "NULL")]);
|
||||
test_type("OID",
|
||||
&[(Some(2147483548u32), "2147483548"),
|
||||
(Some(4000000000), "4000000000"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_i64_params() {
|
||||
test_type("BIGINT", &[(Some(9223372036854775708i64), "9223372036854775708"),
|
||||
(Some(-9223372036854775708i64), "-9223372036854775708"),
|
||||
(None, "NULL")]);
|
||||
test_type("BIGINT",
|
||||
&[(Some(9223372036854775708i64), "9223372036854775708"),
|
||||
(Some(-9223372036854775708i64), "-9223372036854775708"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_params() {
|
||||
test_type("REAL", &[(Some(f32::INFINITY), "'infinity'"),
|
||||
(Some(f32::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(1000.55), "1000.55"), (None, "NULL")]);
|
||||
test_type("REAL",
|
||||
&[(Some(f32::INFINITY), "'infinity'"),
|
||||
(Some(f32::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(1000.55), "1000.55"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64_params() {
|
||||
test_type("DOUBLE PRECISION", &[(Some(f64::INFINITY), "'infinity'"),
|
||||
(Some(f64::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(10000.55), "10000.55"),
|
||||
(None, "NULL")]);
|
||||
test_type("DOUBLE PRECISION",
|
||||
&[(Some(f64::INFINITY), "'infinity'"),
|
||||
(Some(f64::NEG_INFINITY), "'-infinity'"),
|
||||
(Some(10000.55), "10000.55"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_varchar_params() {
|
||||
test_type("VARCHAR", &[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
test_type("VARCHAR",
|
||||
&[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_text_params() {
|
||||
test_type("TEXT", &[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()), "'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
test_type("TEXT",
|
||||
&[(Some("hello world".to_owned()), "'hello world'"),
|
||||
(Some("イロハニホヘト チリヌルヲ".to_owned()),
|
||||
"'イロハニホヘト チリヌルヲ'"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -125,13 +141,14 @@ fn test_bpchar_params() {
|
||||
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
|
||||
id SERIAL PRIMARY KEY,
|
||||
b CHAR(5)
|
||||
)", &[]));
|
||||
)",
|
||||
&[]));
|
||||
or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
|
||||
&[&Some("12345"), &Some("123"), &None::<&'static str>]));
|
||||
let stmt = or_panic!(conn.prepare("SELECT b FROM foo ORDER BY id"));
|
||||
let res = or_panic!(stmt.query(&[]));
|
||||
|
||||
assert_eq!(vec!(Some("12345".to_owned()), Some("123 ".to_owned()), None),
|
||||
assert_eq!(vec![Some("12345".to_owned()), Some("123 ".to_owned()), None],
|
||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
@@ -141,19 +158,22 @@ fn test_citext_params() {
|
||||
or_panic!(conn.execute("CREATE TEMPORARY TABLE foo (
|
||||
id SERIAL PRIMARY KEY,
|
||||
b CITEXT
|
||||
)", &[]));
|
||||
)",
|
||||
&[]));
|
||||
or_panic!(conn.execute("INSERT INTO foo (b) VALUES ($1), ($2), ($3)",
|
||||
&[&Some("foobar"), &Some("FooBar"), &None::<&'static str>]));
|
||||
let stmt = or_panic!(conn.prepare("SELECT id FROM foo WHERE b = 'FOOBAR' ORDER BY id"));
|
||||
let res = or_panic!(stmt.query(&[]));
|
||||
|
||||
assert_eq!(vec!(Some(1i32), Some(2i32)), res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
||||
assert_eq!(vec![Some(1i32), Some(2i32)],
|
||||
res.iter().map(|row| row.get(0)).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bytea_params() {
|
||||
test_type("BYTEA", &[(Some(vec!(0u8, 1, 2, 3, 254, 255)), "'\\x00010203feff'"),
|
||||
(None, "NULL")]);
|
||||
test_type("BYTEA",
|
||||
&[(Some(vec![0u8, 1, 2, 3, 254, 255]), "'\\x00010203feff'"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -167,22 +187,23 @@ fn test_hstore_params() {
|
||||
}
|
||||
test_type("hstore",
|
||||
&[(Some(make_map!("a".to_owned() => Some("1".to_owned()))), "'a=>1'"),
|
||||
(Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
|
||||
(Some(make_map!("hello".to_owned() => Some("world!".to_owned()),
|
||||
"hola".to_owned() => Some("mundo!".to_owned()),
|
||||
"what".to_owned() => None)),
|
||||
"'hello=>world!,hola=>mundo!,what=>NULL'"),
|
||||
"'hello=>world!,hola=>mundo!,what=>NULL'"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_params() {
|
||||
test_type("integer[]", &[(Some(vec!(1i32, 2i32)), "ARRAY[1,2]"),
|
||||
(Some(vec!(1i32)), "ARRAY[1]"),
|
||||
(Some(vec!()), "ARRAY[]"),
|
||||
(None, "NULL")]);
|
||||
test_type("integer[]",
|
||||
&[(Some(vec![1i32, 2i32]), "ARRAY[1,2]"),
|
||||
(Some(vec![1i32]), "ARRAY[1]"),
|
||||
(Some(vec![]), "ARRAY[]"),
|
||||
(None, "NULL")]);
|
||||
}
|
||||
|
||||
fn test_nan_param<T: PartialEq+ToSql+FromSql>(sql_type: &str) {
|
||||
fn test_nan_param<T: PartialEq + ToSql + FromSql>(sql_type: &str) {
|
||||
let conn = or_panic!(Connection::connect("postgres://postgres@localhost", TlsMode::None));
|
||||
let stmt = or_panic!(conn.prepare(&*format!("SELECT 'NaN'::{}", sql_type)));
|
||||
let result = or_panic!(stmt.query(&[]));
|
||||
@@ -215,20 +236,27 @@ fn test_pg_database_datname() {
|
||||
fn test_slice() {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY, f VARCHAR);
|
||||
INSERT INTO foo (f) VALUES ('a'), ('b'), ('c'), ('d');").unwrap();
|
||||
INSERT INTO foo (f) VALUES ('a'), ('b'), ('c'), ('d');")
|
||||
.unwrap();
|
||||
|
||||
let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)").unwrap();
|
||||
let stmt = conn.prepare("SELECT f FROM foo WHERE id = ANY($1)")
|
||||
.unwrap();
|
||||
let result = stmt.query(&[&&[1i32, 3, 4][..]]).unwrap();
|
||||
assert_eq!(vec!["a".to_owned(), "c".to_owned(), "d".to_owned()],
|
||||
result.iter().map(|r| r.get::<_, String>(0)).collect::<Vec<_>>());
|
||||
result
|
||||
.iter()
|
||||
.map(|r| r.get::<_, String>(0))
|
||||
.collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_wrong_type() {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY)").unwrap();
|
||||
conn.batch_execute("CREATE TEMPORARY TABLE foo (id SERIAL PRIMARY KEY)")
|
||||
.unwrap();
|
||||
|
||||
let stmt = conn.prepare("SELECT * FROM foo WHERE id = ANY($1)").unwrap();
|
||||
let stmt = conn.prepare("SELECT * FROM foo WHERE id = ANY($1)")
|
||||
.unwrap();
|
||||
match stmt.query(&[&&["hi"][..]]) {
|
||||
Ok(_) => panic!("Unexpected success"),
|
||||
Err(Error::Conversion(ref e)) if e.is::<WrongType>() => {}
|
||||
@@ -254,7 +282,10 @@ fn domain() {
|
||||
struct SessionId(Vec<u8>);
|
||||
|
||||
impl ToSql for SessionId {
|
||||
fn to_sql(&self, ty: &Type, out: &mut Vec<u8>) -> result::Result<IsNull, Box<error::Error + Sync + Send>> {
|
||||
fn to_sql(&self,
|
||||
ty: &Type,
|
||||
out: &mut Vec<u8>)
|
||||
-> result::Result<IsNull, Box<error::Error + Sync + Send>> {
|
||||
let inner = match *ty.kind() {
|
||||
Kind::Domain(ref inner) => inner,
|
||||
_ => unreachable!(),
|
||||
@@ -263,14 +294,20 @@ fn domain() {
|
||||
}
|
||||
|
||||
fn accepts(ty: &Type) -> bool {
|
||||
ty.name() == "session_id" && match *ty.kind() { Kind::Domain(_) => true, _ => false }
|
||||
ty.name() == "session_id" &&
|
||||
match *ty.kind() {
|
||||
Kind::Domain(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
to_sql_checked!();
|
||||
}
|
||||
|
||||
impl FromSql for SessionId {
|
||||
fn from_sql(ty: &Type, raw: &[u8]) -> result::Result<Self, Box<error::Error + Sync + Send>> {
|
||||
fn from_sql(ty: &Type,
|
||||
raw: &[u8])
|
||||
-> result::Result<Self, Box<error::Error + Sync + Send>> {
|
||||
Vec::<u8>::from_sql(ty, raw).map(SessionId)
|
||||
}
|
||||
|
||||
@@ -286,7 +323,8 @@ fn domain() {
|
||||
.unwrap();
|
||||
|
||||
let id = SessionId(b"0123456789abcdef".to_vec());
|
||||
conn.execute("INSERT INTO pg_temp.foo (id) VALUES ($1)", &[&id]).unwrap();
|
||||
conn.execute("INSERT INTO pg_temp.foo (id) VALUES ($1)", &[&id])
|
||||
.unwrap();
|
||||
let rows = conn.query("SELECT id FROM pg_temp.foo", &[]).unwrap();
|
||||
assert_eq!(id, rows.get(0).get(0));
|
||||
}
|
||||
@@ -320,15 +358,28 @@ fn composite() {
|
||||
#[test]
|
||||
fn enum_() {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
conn.batch_execute("CREATE TYPE pg_temp.mood AS ENUM ('sad', 'ok', 'happy');").unwrap();
|
||||
conn.batch_execute("CREATE TYPE pg_temp.mood AS ENUM ('sad', 'ok', 'happy');")
|
||||
.unwrap();
|
||||
|
||||
let stmt = conn.prepare("SELECT $1::mood").unwrap();
|
||||
let type_ = &stmt.param_types()[0];
|
||||
assert_eq!(type_.name(), "mood");
|
||||
match *type_.kind() {
|
||||
Kind::Enum(ref variants) => {
|
||||
assert_eq!(variants, &["sad".to_owned(), "ok".to_owned(), "happy".to_owned()]);
|
||||
assert_eq!(variants,
|
||||
&["sad".to_owned(), "ok".to_owned(), "happy".to_owned()]);
|
||||
}
|
||||
_ => panic!("bad type"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown() {
|
||||
let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
|
||||
let rows = conn.query("SELECT 'hello world'", &[]).unwrap();
|
||||
match *rows.columns()[0].type_() {
|
||||
Type::Unknown => {}
|
||||
_ => panic!("bad type"),
|
||||
}
|
||||
assert_eq!("hello world", rows.get(0).get::<_, String>(0));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user