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 deep_decimal(zeros: usize) -> String {
let mut s = String::from("0.");
for _ in 0..zeros {
s.push('0');
}
s.push('1');
s
}
#[test]
fn a_literal_past_255_decimal_places_stays_numeric() {
let mut e = Engine::new();
assert_eq!(one(&mut e, "SELECT pg_typeof(1e-255)"), "numeric");
assert_eq!(one(&mut e, "SELECT pg_typeof(1e-256)"), "numeric");
assert_eq!(one(&mut e, "SELECT pg_typeof(1e-400)"), "numeric");
assert_eq!(one(&mut e, "SELECT scale(1e-256)"), "256");
}
#[test]
fn a_plain_256_place_decimal_no_longer_aborts_the_query() {
let mut e = Engine::new();
let lit = deep_decimal(255);
assert_eq!(one(&mut e, &format!("SELECT {lit}")), lit);
assert_eq!(one(&mut e, &format!("SELECT pg_typeof({lit})")), "numeric",);
}
#[test]
fn arithmetic_at_a_deep_scale_stays_exact() {
let mut e = Engine::new();
let want = {
let mut s = String::from("1.");
for _ in 0..255 {
s.push('0');
}
s.push('1');
s
};
assert_eq!(one(&mut e, "SELECT 1e-256 + 1"), want);
assert_eq!(one(&mut e, "SELECT pg_typeof(1e-256 + 1)"), "numeric");
}
#[test]
fn rounding_to_a_deep_scale_stays_numeric() {
let mut e = Engine::new();
let mut want = deep_decimal(255);
for _ in 0..44 {
want.push('0');
}
assert_eq!(one(&mut e, "SELECT round(1e-256, 300)"), want);
assert_eq!(one(&mut e, "SELECT scale(round(1e-256, 300))"), "300");
assert_eq!(
one(&mut e, "SELECT pg_typeof(round(1e-256, 300))"),
"numeric",
);
}
#[test]
fn converting_a_deep_numeric_to_float_is_correctly_rounded() {
let mut e = Engine::new();
assert_eq!(one(&mut e, "SELECT 1e-300::float8"), "1e-300");
assert_eq!(one(&mut e, "SELECT 1e-320::float8"), "1e-320");
assert_eq!(one(&mut e, "SELECT 1e-300::float8 - 1e-300"), "0");
assert_eq!(one(&mut e, "SELECT 1e-300::float8 + 1e-300"), "2e-300");
assert_eq!(
one(&mut e, "SELECT 0.1::float8 + 0.2"),
"0.30000000000000004",
);
}
#[test]
fn a_deep_numeric_survives_a_round_trip_through_a_column() {
let mut e = Engine::new();
e.execute("CREATE TABLE t (v numeric)").unwrap();
e.execute("INSERT INTO t VALUES (1e-256), (0.25), (1e-400)")
.unwrap();
assert_eq!(
one(&mut e, "SELECT scale(v) FROM t ORDER BY v LIMIT 1"),
"400"
);
assert_eq!(
one(&mut e, "SELECT count(*) FROM t WHERE scale(v) > 255"),
"2",
);
}