use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn mysql() -> Engine {
let mut e = Engine::new();
e.execute("SET sql_mode='STRICT_TRANS_TABLES'").unwrap();
e
}
fn one(e: &mut Engine, sql: &str) -> Value<'static> {
match e.execute(sql).unwrap_or_else(|err| panic!("{sql}: {err}")) {
QueryResult::Rows { rows, .. } => rows
.first()
.and_then(|r| r.values.first())
.cloned()
.map(Value::into_owned)
.unwrap_or(Value::Null),
other => panic!("`{sql}` did not return rows: {other:?}"),
}
}
#[test]
fn binary_keeps_the_value() {
let mut e = mysql();
assert_eq!(one(&mut e, "SELECT BINARY 'abc'"), Value::text("abc"));
assert_eq!(
one(&mut e, "SELECT HEX(BINARY 'abc')"),
Value::text("616263")
);
assert_eq!(one(&mut e, "SELECT LENGTH(BINARY 'héllo')"), Value::Int(6));
assert_eq!(one(&mut e, "SELECT BINARY NULL"), Value::Null);
}
#[test]
fn it_binds_like_a_unary_operator() {
let mut e = mysql();
assert_eq!(one(&mut e, "SELECT BINARY 1 + 1"), Value::BigInt(2));
}
#[test]
fn a_length_truncates() {
let mut e = mysql();
assert_eq!(
one(&mut e, "SELECT CAST('abc' AS BINARY(2))"),
Value::text("ab")
);
assert_eq!(
one(&mut e, "SELECT CAST('abc' AS BINARY(9))"),
Value::text("abc")
);
}
#[test]
fn it_refuses_case_folding() {
let mut e = mysql();
e.execute("CREATE TABLE ci (t TEXT COLLATE \"case_insensitive\")")
.unwrap();
e.execute("INSERT INTO ci VALUES ('Foo')").unwrap();
assert_eq!(
one(&mut e, "SELECT count(*) FROM ci WHERE t = 'foo'"),
Value::BigInt(1),
"the column folds case on its own"
);
assert_eq!(
one(&mut e, "SELECT count(*) FROM ci WHERE BINARY t = 'foo'"),
Value::BigInt(0),
"…and BINARY stops it"
);
assert_eq!(
one(&mut e, "SELECT count(*) FROM ci WHERE t = BINARY 'foo'"),
Value::BigInt(0),
"from either side"
);
assert_eq!(
one(&mut e, "SELECT count(*) FROM ci WHERE BINARY t = 'Foo'"),
Value::BigInt(1),
"an exact match still matches"
);
}
#[test]
fn pg_has_no_binary_prefix() {
let mut p = Engine::new();
assert!(p.execute("SELECT BINARY 'abc'").is_err());
}