use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn one_row(r: QueryResult) -> Vec<Value> {
match r {
QueryResult::Rows { rows, .. } => {
assert_eq!(rows.len(), 1);
rows.into_iter().next().unwrap().values
}
_ => panic!(),
}
}
#[test]
fn nullif_equal_returns_null() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(5, 5)").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_unequal_returns_first_arg() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(5, 3)").unwrap());
match &row[0] {
Value::Int(n) => assert_eq!(*n, 5),
Value::BigInt(n) => assert_eq!(*n, 5),
other => panic!("got {other:?}"),
}
}
#[test]
fn nullif_text_equal_returns_null() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif('hello', 'hello')").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_text_unequal_returns_first() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif('hello', 'world')").unwrap());
assert_eq!(row[0], Value::Text("hello".into()));
}
#[test]
fn nullif_empty_string_pattern() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif('', '')").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_zero_pattern() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(0, 0)").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_null_a_returns_null() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(NULL, 5)").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_null_b_returns_a() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(5, NULL)").unwrap());
match &row[0] {
Value::Int(n) => assert_eq!(*n, 5),
Value::BigInt(n) => assert_eq!(*n, 5),
other => panic!("got {other:?}"),
}
}
#[test]
fn nullif_both_null_returns_null() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(NULL, NULL)").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_one_arg_errors() {
let mut e = Engine::new();
assert!(e.execute("SELECT nullif(5)").is_err());
}
#[test]
fn nullif_three_args_errors() {
let mut e = Engine::new();
assert!(e.execute("SELECT nullif(5, 6, 7)").is_err());
}
#[test]
fn nullif_zero_args_errors() {
let mut e = Engine::new();
assert!(e.execute("SELECT nullif()").is_err());
}
#[test]
fn nullif_for_divide_by_zero_protection() {
let mut e = Engine::new();
e.execute("CREATE TABLE rate (num INT NOT NULL, denom INT NOT NULL)")
.unwrap();
e.execute("INSERT INTO rate VALUES (10, 2), (5, 0)")
.unwrap();
let r = e
.execute("SELECT num::FLOAT / nullif(denom, 0) FROM rate ORDER BY num DESC")
.unwrap();
let QueryResult::Rows { rows, .. } = r else {
panic!()
};
assert_eq!(rows.len(), 2);
match &rows[0].values[0] {
Value::Float(x) => assert_eq!(*x, 5.0),
other => panic!("got {other:?}"),
}
assert_eq!(rows[1].values[0], Value::Null);
}
#[test]
fn nullif_empty_string_to_null() {
let mut e = Engine::new();
e.execute("CREATE TABLE form (id INT NOT NULL, name TEXT NOT NULL)")
.unwrap();
e.execute("INSERT INTO form VALUES (1, ''), (2, 'alice')")
.unwrap();
let r = e
.execute("SELECT id, nullif(name, '') FROM form ORDER BY id")
.unwrap();
let QueryResult::Rows { rows, .. } = r else {
panic!()
};
assert_eq!(rows.len(), 2);
assert_eq!(rows[0].values[1], Value::Null);
assert_eq!(rows[1].values[1], Value::Text("alice".into()));
}
#[test]
fn nullif_inside_where() {
let mut e = Engine::new();
e.execute("CREATE TABLE u (id INT NOT NULL, status TEXT NOT NULL)")
.unwrap();
e.execute("INSERT INTO u VALUES (1, 'active'), (2, 'inactive'), (3, 'deleted')")
.unwrap();
let r = e
.execute("SELECT id FROM u WHERE nullif(status, 'deleted') IS NOT NULL ORDER BY id")
.unwrap();
let QueryResult::Rows { rows, .. } = r else {
panic!()
};
assert_eq!(rows.len(), 2);
assert_eq!(rows[0].values[0], Value::Int(1));
assert_eq!(rows[1].values[0], Value::Int(2));
}
#[test]
fn nullif_with_negative_numbers() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(-5, -5)").unwrap());
assert_eq!(row[0], Value::Null);
}
#[test]
fn nullif_with_floats() {
let mut e = Engine::new();
let row = one_row(e.execute("SELECT nullif(1.5, 1.5)").unwrap());
assert_eq!(row[0], Value::Null);
let row = one_row(e.execute("SELECT nullif(1.5, 2.5)").unwrap());
match &row[0] {
Value::Float(x) => assert_eq!(*x, 1.5),
Value::Numeric { scaled, scale } => {
assert_eq!(*scaled, 15 * 10_i128.pow(u32::from(*scale) - 1));
}
other => panic!("got {other:?}"),
}
}