mod common;
use common::TestConnection;
use hyperdb_api::{Numeric, SqlType};
#[test]
fn avg_integer_schema_has_precision_16_scale_6() {
let tc = TestConnection::new().expect("test connection");
tc.execute_command("CREATE TABLE t (v INT)").unwrap();
tc.execute_command("INSERT INTO t VALUES (1), (2), (3)")
.unwrap();
let mut result = tc
.connection
.execute_query("SELECT AVG(v) AS avg_v FROM t")
.unwrap();
let _ = result.next_chunk().unwrap();
let schema = result
.schema()
.expect("schema should be available after first chunk");
assert_eq!(schema.column_count(), 1);
let col = schema.column(0);
match col.sql_type() {
SqlType::Numeric { precision, scale } => {
assert_eq!(
precision, 16,
"AVG(INTEGER) precision should be 16 per Hyper's \
`dividingAggregateType(Integer)` — see \
hyper/cts/algebra/operator/AggregationLogic.cpp:805"
);
assert_eq!(
scale, 6,
"AVG(INTEGER) scale should be 6 per the same source"
);
}
other => panic!("expected Numeric, got {other:?}"),
}
}
#[test]
fn avg_bigint_schema_has_precision_25_scale_6() {
let tc = TestConnection::new().expect("test connection");
tc.execute_command("CREATE TABLE t (v BIGINT)").unwrap();
tc.execute_command("INSERT INTO t VALUES (1), (2), (3)")
.unwrap();
let mut result = tc
.connection
.execute_query("SELECT AVG(v) AS avg_v FROM t")
.unwrap();
let _ = result.next_chunk().unwrap();
let schema = result.schema().expect("schema after first chunk");
let col = schema.column(0);
match col.sql_type() {
SqlType::Numeric { precision, scale } => {
assert_eq!(precision, 25, "AVG(BIGINT) precision should be 25");
assert_eq!(scale, 6, "AVG(BIGINT) scale should be 6");
}
other => panic!("expected Numeric, got {other:?}"),
}
}
#[test]
fn avg_integer_via_row_get_numeric() {
let tc = TestConnection::new().expect("test connection");
tc.execute_command("CREATE TABLE t (v INT)").unwrap();
tc.execute_command("INSERT INTO t VALUES (1), (2), (3)")
.unwrap();
let mut result = tc
.connection
.execute_query("SELECT AVG(v) AS avg_v FROM t")
.unwrap();
let chunk = result.next_chunk().unwrap().expect("one row");
assert_eq!(chunk.len(), 1);
let row = &chunk[0];
let numeric: Numeric = row
.get::<Numeric>(0)
.expect("AVG(INT) decodes via row.get::<Numeric>");
assert_eq!(numeric.scale(), 6);
assert!(
(numeric.to_f64() - 2.0).abs() < 1e-12,
"expected 2.0, got {}",
numeric.to_f64()
);
let numeric2: Numeric = row
.try_get::<Numeric>(0, "avg_v")
.expect("AVG(INT) also decodes via row.try_get::<Numeric>");
assert_eq!(numeric, numeric2);
match row.sql_type(0) {
Some(SqlType::Numeric { precision, scale }) => {
assert_eq!(precision, 16);
assert_eq!(scale, 6);
}
other => panic!("expected Numeric via row.sql_type, got {other:?}"),
}
}
#[test]
fn avg_integer_bytes_decode_to_correct_numeric() {
let tc = TestConnection::new().expect("test connection");
tc.execute_command("CREATE TABLE t (v INT)").unwrap();
tc.execute_command("INSERT INTO t VALUES (1), (2), (3)")
.unwrap();
let mut result = tc
.connection
.execute_query("SELECT AVG(v) AS avg_v FROM t")
.unwrap();
let chunk = result.next_chunk().unwrap().expect("one row");
let schema = result.schema().expect("schema");
let scale = match schema.column(0).sql_type() {
SqlType::Numeric { scale, .. } => scale,
other => panic!("expected Numeric, got {other:?}"),
};
let row = &chunk[0];
let bytes = row.get_bytes(0).expect("non-null AVG value");
assert_eq!(
bytes.len(),
8,
"AVG(INT) should come back as the 8-byte HyperBinary Numeric form"
);
let scale_u8: u8 = u8::try_from(scale).expect("scale fits in u8");
let numeric = Numeric::from_binary_with_scale(&bytes, scale_u8)
.expect("decode AVG(INT) bytes as Numeric");
assert_eq!(numeric.scale(), 6);
assert!(
(numeric.to_f64() - 2.0).abs() < 1e-12,
"expected 2.0, got {}",
numeric.to_f64()
);
}
#[test]
fn explicit_numeric_column_preserves_precision_and_scale() {
let tc = TestConnection::new().expect("test connection");
tc.execute_command("CREATE TABLE prices (p NUMERIC(10, 2))")
.unwrap();
tc.execute_command("INSERT INTO prices VALUES (1.23), (4.56)")
.unwrap();
let mut result = tc
.connection
.execute_query("SELECT p FROM prices ORDER BY p")
.unwrap();
let _ = result.next_chunk().unwrap();
let schema = result.schema().expect("schema");
match schema.column(0).sql_type() {
SqlType::Numeric { precision, scale } => {
assert_eq!(precision, 10);
assert_eq!(scale, 2);
}
other => panic!("expected Numeric, got {other:?}"),
}
}