diff --git a/crates/proof-of-sql/benches/bench_append_rows.rs b/crates/proof-of-sql/benches/bench_append_rows.rs index 8d7484d5f..b6553c3f9 100644 --- a/crates/proof-of-sql/benches/bench_append_rows.rs +++ b/crates/proof-of-sql/benches/bench_append_rows.rs @@ -13,7 +13,7 @@ use proof_of_sql::{ database::{ owned_table_utility::{ bigint, boolean, decimal75, int, int128, owned_table, scalar, smallint, - timestamptz, varchar, + timestamptz, tinyint, varchar, }, OwnedTable, }, @@ -78,6 +78,7 @@ pub fn generate_random_owned_table( "scalar", "varchar", "decimal75", + "tinyint", "smallint", "int", "timestamptz", @@ -110,6 +111,7 @@ pub fn generate_random_owned_table( 2, vec![generate_random_u64_array(); num_rows], )), + "tinyint" => columns.push(tinyint(identifier.deref(), vec![rng.gen::(); num_rows])), "smallint" => columns.push(smallint( identifier.deref(), vec![rng.gen::(); num_rows], diff --git a/crates/proof-of-sql/src/base/database/arrow_array_to_column_conversion.rs b/crates/proof-of-sql/src/base/database/arrow_array_to_column_conversion.rs index 196c24258..71022f622 100644 --- a/crates/proof-of-sql/src/base/database/arrow_array_to_column_conversion.rs +++ b/crates/proof-of-sql/src/base/database/arrow_array_to_column_conversion.rs @@ -932,6 +932,16 @@ mod tests { assert_eq!(result, Column::Boolean(&[])); } + #[test] + fn we_can_build_an_empty_column_from_an_empty_range_int8() { + let alloc = Bump::new(); + let array: ArrayRef = Arc::new(arrow::array::Int8Array::from(vec![1, -3])); + let result = array + .to_column::(&alloc, &(2..2), None) + .unwrap(); + assert_eq!(result, Column::TinyInt(&[])); + } + #[test] fn we_can_build_an_empty_column_from_an_empty_range_int16() { let alloc = Bump::new(); diff --git a/crates/proof-of-sql/src/base/database/column_operation.rs b/crates/proof-of-sql/src/base/database/column_operation.rs index 2144a6c76..acd9167d7 100644 --- a/crates/proof-of-sql/src/base/database/column_operation.rs +++ b/crates/proof-of-sql/src/base/database/column_operation.rs @@ -1531,6 +1531,17 @@ mod test { #[test] fn we_can_eq_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [1_i8, -2, 3]; + let rhs = [100_i8, 5, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), 2); + let actual = eq_decimal_columns(&lhs, &rhs, left_column_type, right_column_type); + let expected = vec![true, false, false]; + assert_eq!(expected, actual); + let lhs = [1_i16, -2, 3]; let rhs = [100_i16, 5, -2] .into_iter() @@ -1652,6 +1663,17 @@ mod test { #[test] fn we_can_le_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [1_i8, -2, 3]; + let rhs = [100_i8, 5, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), 2); + let actual = le_decimal_columns(&lhs, &rhs, left_column_type, right_column_type); + let expected = vec![true, true, false]; + assert_eq!(expected, actual); + let lhs = [1_i16, -2, 3]; let rhs = [100_i16, 5, -2] .into_iter() @@ -1773,6 +1795,17 @@ mod test { #[test] fn we_can_ge_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [1_i8, -2, 3]; + let rhs = [100_i8, 5, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), 2); + let actual = ge_decimal_columns(&lhs, &rhs, left_column_type, right_column_type); + let expected = vec![true, false, true]; + assert_eq!(expected, actual); + let lhs = [1_i16, -2, 3]; let rhs = [100_i16, 5, -2] .into_iter() @@ -1914,6 +1947,23 @@ mod test { #[test] fn we_can_try_add_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [1_i8, -2, 3]; + let rhs = [4_i8, 5, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), 2); + let actual: (Precision, i8, Vec) = + try_add_decimal_columns(&lhs, &rhs, left_column_type, right_column_type).unwrap(); + let expected_scalars = vec![ + Curve25519Scalar::from(104), + Curve25519Scalar::from(-195), + Curve25519Scalar::from(298), + ]; + let expected = (Precision::new(11).unwrap(), 2, expected_scalars); + assert_eq!(expected, actual); + let lhs = [1_i16, -2, 3]; let rhs = [4_i16, 5, -2] .into_iter() @@ -2076,6 +2126,23 @@ mod test { #[test] fn we_can_try_subtract_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [1_i8, -2, 3]; + let rhs = [4_i8, 5, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), 2); + let actual: (Precision, i8, Vec) = + try_subtract_decimal_columns(&lhs, &rhs, left_column_type, right_column_type).unwrap(); + let expected_scalars = vec![ + Curve25519Scalar::from(96), + Curve25519Scalar::from(-205), + Curve25519Scalar::from(302), + ]; + let expected = (Precision::new(11).unwrap(), 2, expected_scalars); + assert_eq!(expected, actual); + let lhs = [1_i16, -2, 3]; let rhs = [4_i16, 5, -2] .into_iter() @@ -2219,6 +2286,23 @@ mod test { #[test] fn we_can_try_multiply_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [1_i8, -2, 3]; + let rhs = [4_i8, 5, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), 2); + let actual: (Precision, i8, Vec) = + try_multiply_decimal_columns(&lhs, &rhs, left_column_type, right_column_type).unwrap(); + let expected_scalars = vec![ + Curve25519Scalar::from(4), + Curve25519Scalar::from(-10), + Curve25519Scalar::from(-6), + ]; + let expected = (Precision::new(14).unwrap(), 2, expected_scalars); + assert_eq!(expected, actual); + let lhs = [1_i16, -2, 3]; let rhs = [4_i16, 5, -2] .into_iter() @@ -2382,6 +2466,23 @@ mod test { #[test] fn we_can_try_divide_decimal_columns() { // lhs is integer and rhs is decimal with nonnegative scale + let lhs = [0_i8, 2, 3]; + let rhs = [4_i8, 5, 2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let left_column_type = ColumnType::TinyInt; + let right_column_type = ColumnType::Decimal75(Precision::new(3).unwrap(), 2); + let actual: (Precision, i8, Vec) = + try_divide_decimal_columns(&lhs, &rhs, left_column_type, right_column_type).unwrap(); + let expected_scalars = vec![ + Curve25519Scalar::from(0_i64), + Curve25519Scalar::from(40000000_i64), + Curve25519Scalar::from(150000000_i64), + ]; + let expected = (Precision::new(11).unwrap(), 6, expected_scalars); + assert_eq!(expected, actual); + let lhs = [0_i16, 2, 3]; let rhs = [4_i16, 5, 2] .into_iter() @@ -2400,6 +2501,23 @@ mod test { assert_eq!(expected, actual); // lhs is decimal with negative scale and rhs is integer + let lhs = [4_i8, 15, -2] + .into_iter() + .map(Curve25519Scalar::from) + .collect::>(); + let rhs = [71_i64, -82, 23]; + let left_column_type = ColumnType::Decimal75(Precision::new(10).unwrap(), -2); + let right_column_type = ColumnType::TinyInt; + let actual: (Precision, i8, Vec) = + try_divide_decimal_columns(&lhs, &rhs, left_column_type, right_column_type).unwrap(); + let expected_scalars = vec![ + Curve25519Scalar::from(5633802), + Curve25519Scalar::from(-18292682), + Curve25519Scalar::from(-8695652), + ]; + let expected = (Precision::new(18).unwrap(), 6, expected_scalars); + assert_eq!(expected, actual); + let lhs = [4_i16, 15, -2] .into_iter() .map(Curve25519Scalar::from) diff --git a/crates/proof-of-sql/src/base/database/owned_column_operation.rs b/crates/proof-of-sql/src/base/database/owned_column_operation.rs index b143caf49..fdc2b9fa0 100644 --- a/crates/proof-of-sql/src/base/database/owned_column_operation.rs +++ b/crates/proof-of-sql/src/base/database/owned_column_operation.rs @@ -1442,6 +1442,26 @@ mod test { #[test] fn we_cannot_do_logical_operation_on_nonboolean_columns() { + let lhs = OwnedColumn::::TinyInt(vec![1, 2, 3]); + let rhs = OwnedColumn::::TinyInt(vec![1, 2, 3]); + let result = lhs.element_wise_and(&rhs); + assert!(matches!( + result, + Err(ColumnOperationError::BinaryOperationInvalidColumnType { .. }) + )); + + let result = lhs.element_wise_or(&rhs); + assert!(matches!( + result, + Err(ColumnOperationError::BinaryOperationInvalidColumnType { .. }) + )); + + let result = lhs.element_wise_not(); + assert!(matches!( + result, + Err(ColumnOperationError::UnaryOperationInvalidColumnType { .. }) + )); + let lhs = OwnedColumn::::Int(vec![1, 2, 3]); let rhs = OwnedColumn::::Int(vec![1, 2, 3]); let result = lhs.element_wise_and(&rhs); @@ -1563,6 +1583,18 @@ mod test { ); // Decimals and integers + let lhs_scalars = [10, 2, 30].iter().map(Curve25519Scalar::from).collect(); + let rhs = OwnedColumn::::TinyInt(vec![1, -2, 3]); + let lhs = + OwnedColumn::::Decimal75(Precision::new(5).unwrap(), 1, lhs_scalars); + let result = lhs.element_wise_eq(&rhs); + assert_eq!( + result, + Ok(OwnedColumn::::Boolean(vec![ + true, false, true + ])) + ); + let lhs_scalars = [10, 2, 30].iter().map(Curve25519Scalar::from).collect(); let rhs = OwnedColumn::::Int(vec![1, -2, 3]); let lhs = @@ -1626,6 +1658,18 @@ mod test { ); // Decimals and integers + let lhs_scalars = [10, -2, -30].iter().map(Curve25519Scalar::from).collect(); + let rhs = OwnedColumn::::TinyInt(vec![1, -20, 3]); + let lhs = + OwnedColumn::::Decimal75(Precision::new(5).unwrap(), -1, lhs_scalars); + let result = lhs.element_wise_le(&rhs); + assert_eq!( + result, + Ok(OwnedColumn::::Boolean(vec![ + false, true, true + ])) + ); + let lhs_scalars = [10, -2, -30].iter().map(Curve25519Scalar::from).collect(); let rhs = OwnedColumn::::Int(vec![1, -20, 3]); let lhs = @@ -1689,6 +1733,18 @@ mod test { ); // Decimals and integers + let lhs_scalars = [10, -2, -30].iter().map(Curve25519Scalar::from).collect(); + let rhs = OwnedColumn::::TinyInt(vec![1_i8, -20, 3]); + let lhs = + OwnedColumn::::Decimal75(Precision::new(5).unwrap(), -1, lhs_scalars); + let result = lhs.element_wise_ge(&rhs); + assert_eq!( + result, + Ok(OwnedColumn::::Boolean(vec![ + true, true, false + ])) + ); + let lhs_scalars = [10, -2, -30].iter().map(Curve25519Scalar::from).collect(); let rhs = OwnedColumn::::BigInt(vec![1_i64, -20, 3]); let lhs = @@ -1705,6 +1761,19 @@ mod test { #[test] fn we_cannot_do_comparison_on_columns_with_incompatible_types() { // Strings can't be compared with other types + let lhs = OwnedColumn::::TinyInt(vec![1, 2, 3]); + let rhs = OwnedColumn::::VarChar( + ["Space", "and", "Time"] + .iter() + .map(|s| s.to_string()) + .collect(), + ); + let result = lhs.element_wise_le(&rhs); + assert!(matches!( + result, + Err(ColumnOperationError::BinaryOperationInvalidColumnType { .. }) + )); + let lhs = OwnedColumn::::Int(vec![1, 2, 3]); let rhs = OwnedColumn::::VarChar( ["Space", "and", "Time"] @@ -1731,6 +1800,14 @@ mod test { )); // Booleans can't be compared with other types + let lhs = OwnedColumn::::Boolean(vec![true, false, true]); + let rhs = OwnedColumn::::TinyInt(vec![1, 2, 3]); + let result = lhs.element_wise_le(&rhs); + assert!(matches!( + result, + Err(ColumnOperationError::BinaryOperationInvalidColumnType { .. }) + )); + let lhs = OwnedColumn::::Boolean(vec![true, false, true]); let rhs = OwnedColumn::::Int(vec![1, 2, 3]); let result = lhs.element_wise_le(&rhs); @@ -1823,6 +1900,14 @@ mod test { ); // lhs and rhs have different precisions + let lhs = OwnedColumn::::TinyInt(vec![1_i8, 2, 3]); + let rhs = OwnedColumn::::Int(vec![1_i32, 2, 3]); + let result = lhs + rhs; + assert_eq!( + result, + Ok(OwnedColumn::::Int(vec![2_i32, 4, 6])) + ); + let lhs = OwnedColumn::::Int128(vec![1_i128, 2, 3]); let rhs = OwnedColumn::::Int(vec![1_i32, 2, 3]); let result = lhs + rhs; @@ -1871,6 +1956,21 @@ mod test { ); // lhs is integer and rhs is decimal + let lhs = OwnedColumn::::TinyInt(vec![1, 2, 3]); + let rhs_scalars = [1, 2, 3].iter().map(Curve25519Scalar::from).collect(); + let rhs = + OwnedColumn::::Decimal75(Precision::new(5).unwrap(), 2, rhs_scalars); + let result = (lhs + rhs).unwrap(); + let expected_scalars = [101, 202, 303].iter().map(Curve25519Scalar::from).collect(); + assert_eq!( + result, + OwnedColumn::::Decimal75( + Precision::new(6).unwrap(), + 2, + expected_scalars + ) + ); + let lhs = OwnedColumn::::Int(vec![1, 2, 3]); let rhs_scalars = [1, 2, 3].iter().map(Curve25519Scalar::from).collect(); let rhs = @@ -1890,6 +1990,14 @@ mod test { #[test] fn we_can_try_subtract_integer_columns() { // lhs and rhs have the same precision + let lhs = OwnedColumn::::TinyInt(vec![4_i8, 5, 2]); + let rhs = OwnedColumn::::TinyInt(vec![1_i8, 2, 3]); + let result = lhs - rhs; + assert_eq!( + result, + Ok(OwnedColumn::::TinyInt(vec![3_i8, 3, -1])) + ); + let lhs = OwnedColumn::::Int(vec![4_i32, 5, 2]); let rhs = OwnedColumn::::Int(vec![1_i32, 2, 3]); let result = lhs - rhs; @@ -1899,6 +2007,14 @@ mod test { ); // lhs and rhs have different precisions + let lhs = OwnedColumn::::TinyInt(vec![4_i8, 5, 2]); + let rhs = OwnedColumn::::BigInt(vec![1_i64, 2, 5]); + let result = lhs - rhs; + assert_eq!( + result, + Ok(OwnedColumn::::BigInt(vec![3_i64, 3, -3])) + ); + let lhs = OwnedColumn::::Int(vec![3_i32, 2, 3]); let rhs = OwnedColumn::::BigInt(vec![1_i64, 2, 5]); let result = lhs - rhs; @@ -1947,6 +2063,21 @@ mod test { ); // lhs is integer and rhs is decimal + let lhs = OwnedColumn::::TinyInt(vec![4, 5, 2]); + let rhs_scalars = [1, 2, 3].iter().map(Curve25519Scalar::from).collect(); + let rhs = + OwnedColumn::::Decimal75(Precision::new(5).unwrap(), 2, rhs_scalars); + let result = (lhs - rhs).unwrap(); + let expected_scalars = [399, 498, 197].iter().map(Curve25519Scalar::from).collect(); + assert_eq!( + result, + OwnedColumn::::Decimal75( + Precision::new(6).unwrap(), + 2, + expected_scalars + ) + ); + let lhs = OwnedColumn::::Int(vec![4, 5, 2]); let rhs_scalars = [1, 2, 3].iter().map(Curve25519Scalar::from).collect(); let rhs = @@ -1966,6 +2097,14 @@ mod test { #[test] fn we_can_try_multiply_integer_columns() { // lhs and rhs have the same precision + let lhs = OwnedColumn::::TinyInt(vec![4_i8, 5, -2]); + let rhs = OwnedColumn::::TinyInt(vec![1_i8, 2, 3]); + let result = lhs * rhs; + assert_eq!( + result, + Ok(OwnedColumn::::TinyInt(vec![4_i8, 10, -6])) + ); + let lhs = OwnedColumn::::BigInt(vec![4_i64, 5, -2]); let rhs = OwnedColumn::::BigInt(vec![1_i64, 2, 3]); let result = lhs * rhs; @@ -1975,6 +2114,14 @@ mod test { ); // lhs and rhs have different precisions + let lhs = OwnedColumn::::TinyInt(vec![3_i8, 2, 3]); + let rhs = OwnedColumn::::Int128(vec![1_i128, 2, 5]); + let result = lhs * rhs; + assert_eq!( + result, + Ok(OwnedColumn::::Int128(vec![3_i128, 4, 15])) + ); + let lhs = OwnedColumn::::Int(vec![3_i32, 2, 3]); let rhs = OwnedColumn::::Int128(vec![1_i128, 2, 5]); let result = lhs * rhs; @@ -2005,6 +2152,21 @@ mod test { ); // lhs is integer and rhs is decimal + let lhs = OwnedColumn::::TinyInt(vec![4, 5, 2]); + let rhs_scalars = [1, 2, 3].iter().map(Curve25519Scalar::from).collect(); + let rhs = + OwnedColumn::::Decimal75(Precision::new(5).unwrap(), 2, rhs_scalars); + let result = (lhs * rhs).unwrap(); + let expected_scalars = [4, 10, 6].iter().map(Curve25519Scalar::from).collect(); + assert_eq!( + result, + OwnedColumn::::Decimal75( + Precision::new(9).unwrap(), + 2, + expected_scalars + ) + ); + let lhs = OwnedColumn::::Int(vec![4, 5, 2]); let rhs_scalars = [1, 2, 3].iter().map(Curve25519Scalar::from).collect(); let rhs = @@ -2024,6 +2186,14 @@ mod test { #[test] fn we_can_try_divide_integer_columns() { // lhs and rhs have the same precision + let lhs = OwnedColumn::::TinyInt(vec![4_i8, 5, -2]); + let rhs = OwnedColumn::::TinyInt(vec![1_i8, 2, 3]); + let result = lhs / rhs; + assert_eq!( + result, + Ok(OwnedColumn::::TinyInt(vec![4_i8, 2, 0])) + ); + let lhs = OwnedColumn::::BigInt(vec![4_i64, 5, -2]); let rhs = OwnedColumn::::BigInt(vec![1_i64, 2, 3]); let result = lhs / rhs; @@ -2033,6 +2203,14 @@ mod test { ); // lhs and rhs have different precisions + let lhs = OwnedColumn::::TinyInt(vec![3_i8, 2, 3]); + let rhs = OwnedColumn::::Int128(vec![1_i128, 2, 5]); + let result = lhs / rhs; + assert_eq!( + result, + Ok(OwnedColumn::::Int128(vec![3_i128, 1, 0])) + ); + let lhs = OwnedColumn::::Int(vec![3_i32, 2, 3]); let rhs = OwnedColumn::::Int128(vec![1_i128, 2, 5]); let result = lhs / rhs; diff --git a/crates/proof-of-sql/src/base/database/test_accessor_utility.rs b/crates/proof-of-sql/src/base/database/test_accessor_utility.rs index 0bd8ea38c..9942e7d2b 100644 --- a/crates/proof-of-sql/src/base/database/test_accessor_utility.rs +++ b/crates/proof-of-sql/src/base/database/test_accessor_utility.rs @@ -2,7 +2,7 @@ use crate::base::database::ColumnType; use arrow::{ array::{ Array, BooleanArray, Decimal128Array, Decimal256Array, Int16Array, Int32Array, Int64Array, - StringArray, TimestampMicrosecondArray, TimestampMillisecondArray, + Int8Array, StringArray, TimestampMicrosecondArray, TimestampMillisecondArray, TimestampNanosecondArray, TimestampSecondArray, }, datatypes::{i256, DataType, Field, Schema, TimeUnit}, @@ -66,7 +66,7 @@ pub fn make_random_test_accessor_data( .iter() .map(|x| ((*x >> 56) as i8)) // Shift right to align the lower 8 bits .collect(); - columns.push(Arc::new(Int16Array::from(values))); + columns.push(Arc::new(Int8Array::from(values))); } ColumnType::SmallInt => { column_fields.push(Field::new(*col_name, DataType::Int16, false));