use spg_engine::{Engine, QueryResult};
fn one(e: &mut Engine, sql: &str) -> String {
let r = e
.execute(sql)
.unwrap_or_else(|err| panic!("{sql}: {err:?}"));
let QueryResult::Rows { rows, .. } = r else {
panic!("expected Rows from {sql}");
};
assert_eq!(rows.len(), 1, "{sql}");
spg_engine::eval::value_to_text(&rows[0].values[0])
}
fn err(e: &mut Engine, sql: &str) -> String {
match e.execute(sql) {
Ok(_) => panic!("{sql}: expected an error"),
Err(x) => format!("{x}").replace("eval: type mismatch: ", ""),
}
}
#[test]
fn a_value_on_a_half_ulp_boundary_takes_the_longer_form() {
let mut e = Engine::new();
assert_eq!(
one(&mut e, "SELECT '15000000512'::real::text"),
"1.5000001e+10"
);
assert_eq!(one(&mut e, "SELECT '1.5e10'::real::text"), "1.5000001e+10");
assert_eq!(
one(&mut e, "SELECT '1.5e10'::real = 15000000512::real"),
"true"
);
}
#[test]
fn ordinary_values_keep_their_short_form() {
let mut e = Engine::new();
for (sql, want) in [
("SELECT '0.1'::real::text", "0.1"),
("SELECT '0.5'::real::text", "0.5"),
("SELECT '1e6'::real::text", "1e+06"),
("SELECT '16777216'::real::text", "1.6777216e+07"),
("SELECT '123456792'::real::text", "1.2345679e+08"),
("SELECT '3.4028235e38'::real::text", "3.4028235e+38"),
("SELECT '1.1754944e-38'::real::text", "1.1754944e-38"),
("SELECT '1.4e-45'::real::text", "1e-45"),
("SELECT '0.0001'::real::text", "0.0001"),
("SELECT '99999'::real::text", "99999"),
("SELECT '-1234.5'::real::text", "-1234.5"),
("SELECT '1e15'::real::text", "1e+15"),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
#[test]
fn underflowing_to_zero_is_an_error_not_a_silent_zero() {
let mut e = Engine::new();
assert_eq!(one(&mut e, "SELECT '7.1e-46'::real::text"), "1e-45");
assert_eq!(
err(&mut e, "SELECT '7.0e-46'::real"),
"\"7.0e-46\" is out of range for type real",
);
assert_eq!(
err(&mut e, "SELECT '1e-50'::real"),
"\"1e-50\" is out of range for type real",
);
assert_eq!(
err(&mut e, "SELECT '-1e-50'::real"),
"\"-1e-50\" is out of range for type real",
);
assert_eq!(one(&mut e, "SELECT '0'::real::text"), "0");
assert_eq!(one(&mut e, "SELECT '0.0e-50'::real::text"), "0");
}
#[test]
fn narrowing_a_double_names_which_end_it_left() {
let mut e = Engine::new();
assert_eq!(
err(&mut e, "SELECT 1e40::float8::real"),
"value out of range: overflow",
);
assert_eq!(
err(&mut e, "SELECT 1e-50::float8::real"),
"value out of range: underflow",
);
assert_eq!(one(&mut e, "SELECT '1e-45'::float8::real::text"), "1e-45");
}
#[test]
fn a_numeric_literal_out_of_real_range_quotes_its_expansion() {
let mut e = Engine::new();
assert_eq!(
err(&mut e, "SELECT 1e-50::real"),
"\"0.00000000000000000000000000000000000000000000000001\" is out of range for type real",
);
assert_eq!(
err(&mut e, "SELECT 1.0e40::real"),
"\"10000000000000000000000000000000000000000\" is out of range for type real",
);
}
#[test]
fn double_precision_range_text_is_out_of_range_not_bad_syntax() {
let mut e = Engine::new();
assert_eq!(
err(&mut e, "SELECT '1e400'::float8"),
"\"1e400\" is out of range for type double precision",
);
assert_eq!(
err(&mut e, "SELECT '1e-400'::float8"),
"\"1e-400\" is out of range for type double precision",
);
assert!(
err(&mut e, "SELECT 'abc'::float8").contains("invalid input syntax"),
"{}",
err(&mut e, "SELECT 'abc'::float8"),
);
assert_eq!(one(&mut e, "SELECT '1e-320'::float8::text"), "1e-320");
}