Skip to content

Commit

Permalink
feat: add compare_indexes_of_tables_by_columns
Browse files Browse the repository at this point in the history
  • Loading branch information
iajoiner committed Dec 3, 2024
1 parent ba1ebbd commit 775724a
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 3 deletions.
61 changes: 60 additions & 1 deletion crates/proof-of-sql/src/base/database/order_by_util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Contains the utility functions for ordering.
use crate::base::{
database::{Column, OwnedColumn},
database::{Column, OwnedColumn, TableOperationError, TableOperationResult},
scalar::{Scalar, ScalarExt},
};
use alloc::vec::Vec;
Expand Down Expand Up @@ -31,6 +31,65 @@ pub(crate) fn compare_indexes_by_columns<S: Scalar>(
.unwrap_or(Ordering::Equal)
}

/// Compares the tuples `(left[0][i], left[1][i], ...)` and
/// `(right[0][j], right[1][j], ...)` in lexicographic order.
///
/// Requires that columns in `left` and `right` have the same column types for now
///
/// # Panics
/// Panics if `left` and `right` have different number of columns
/// which should never happen since this function should only be called
/// for joins.
#[allow(dead_code)]
pub(crate) fn compare_indexes_of_tables_by_columns<S: Scalar>(
left: &[Column<S>],
right: &[Column<S>],
i: usize,
j: usize,
) -> TableOperationResult<Ordering> {
// Should never happen
assert_eq!(left.len(), right.len());
for col in 0..left.len() {
if left[col].column_type() != right[col].column_type() {
return Err(TableOperationError::JoinIncompatibleTypes {
left_type: left[col].column_type(),
right_type: right[col].column_type(),
});
}
}
Ok(left
.iter()
.zip(right.iter())
.map(|(left_col, right_col)| match (left_col, right_col) {
(Column::Boolean(left_col), Column::Boolean(right_col)) => {
left_col[i].cmp(&right_col[j])
}
(Column::TinyInt(left_col), Column::TinyInt(right_col)) => {
left_col[i].cmp(&right_col[j])
}
(Column::SmallInt(left_col), Column::SmallInt(right_col)) => {
left_col[i].cmp(&right_col[j])
}
(Column::Int(left_col), Column::Int(right_col)) => left_col[i].cmp(&right_col[j]),
(Column::BigInt(left_col), Column::BigInt(right_col))
| (Column::TimestampTZ(_, _, left_col), Column::TimestampTZ(_, _, right_col)) => {
left_col[i].cmp(&right_col[j])
}
(Column::Int128(left_col), Column::Int128(right_col)) => left_col[i].cmp(&right_col[j]),
(Column::Decimal75(_, _, left_col), Column::Decimal75(_, _, right_col)) => {
left_col[i].signed_cmp(&right_col[j])
}
(Column::Scalar(left_col), Column::Scalar(right_col)) => left_col[i].cmp(&right_col[j]),
(Column::VarChar((left_col, _)), Column::VarChar((right_col, _))) => {
left_col[i].cmp(right_col[j])
}
// Should never happen since we checked the column types
_ => unreachable!(),
})
.find(|&ord| ord != Ordering::Equal)
.unwrap_or(Ordering::Equal))
}

/// Compares the tuples `(order_by[0][i], order_by[1][i], ...)` and
/// `(order_by[0][j], order_by[1][j], ...)` in lexicographic order.
///
Expand Down
61 changes: 60 additions & 1 deletion crates/proof-of-sql/src/base/database/order_by_util_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
base::{
database::{order_by_util::*, Column, OwnedColumn},
database::{order_by_util::*, Column, ColumnType, OwnedColumn, TableOperationError},
math::decimal::Precision,
scalar::test_scalar::TestScalar,
},
Expand Down Expand Up @@ -78,6 +78,65 @@ fn we_can_compare_indexes_by_columns_for_mixed_columns() {
assert_eq!(compare_indexes_by_columns(columns, 6, 9), Ordering::Equal);
}

#[test]
fn we_can_compare_indexes_of_tables_by_columns() {
let left_slice_a = &[55, 44, 44, 66, 66, 77, 66, 66, 66, 66];
let left_slice_b = &[22, 44, 55, 44, 33, 22, 22, 11, 22, 22];
let left_slice_c = &[11, 55, 11, 44, 77, 11, 22, 55, 11, 22];
let left_column_a = Column::BigInt::<TestScalar>(left_slice_a);
let left_column_b = Column::BigInt::<TestScalar>(left_slice_b);
let left_column_c = Column::BigInt::<TestScalar>(left_slice_c);
let left = &[left_column_a, left_column_b, left_column_c];

let right_slice_a = &[77, 44, 66, 44, 77, 77, 66, 66, 55, 66];
let right_slice_b = &[22, 55, 11, 77, 33, 33, 22, 22, 22, 11];
let right_slice_c = &[11, 55, 22, 0, 77, 11, 33, 55, 11, 22];
let right_column_a = Column::BigInt::<TestScalar>(right_slice_a);
let right_column_b = Column::BigInt::<TestScalar>(right_slice_b);
let right_column_c = Column::BigInt::<TestScalar>(right_slice_c);
let right = &[right_column_a, right_column_b, right_column_c];

assert_eq!(
compare_indexes_of_tables_by_columns(left, right, 0, 1).unwrap(),
Ordering::Greater
);
assert_eq!(
compare_indexes_of_tables_by_columns(left, right, 1, 2).unwrap(),
Ordering::Less
);
assert_eq!(
compare_indexes_of_tables_by_columns(left, right, 2, 3).unwrap(),
Ordering::Less
);
assert_eq!(
compare_indexes_of_tables_by_columns(left, right, 2, 1).unwrap(),
Ordering::Less
);
assert_eq!(
compare_indexes_of_tables_by_columns(left, right, 5, 0).unwrap(),
Ordering::Equal
);
}

#[test]
fn we_cannot_compare_indexes_of_tables_by_columns_if_type_mismatch() {
let left_slice = &[55, 44, 66, 66, 66, 77, 66, 66, 66, 66];
let right_slice = &[
true, false, true, true, false, true, false, true, false, true,
];
let left_column = Column::BigInt::<TestScalar>(left_slice);
let right_column = Column::Boolean::<TestScalar>(right_slice);
let left = &[left_column];
let right = &[right_column];
assert_eq!(
compare_indexes_of_tables_by_columns(left, right, 0, 1),
Err(TableOperationError::JoinIncompatibleTypes {
left_type: ColumnType::BigInt,
right_type: ColumnType::Boolean
})
);
}

#[test]
fn we_can_compare_indexes_by_owned_columns_for_mixed_columns() {
let slice_a = ["55", "44", "66", "66", "66", "77", "66", "66", "66", "66"]
Expand Down
12 changes: 11 additions & 1 deletion crates/proof-of-sql/src/base/database/table_operation_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::base::database::ColumnField;
use crate::base::database::{ColumnField, ColumnType};
use alloc::vec::Vec;
use core::result::Result;
use snafu::Snafu;
Expand All @@ -16,6 +16,16 @@ pub enum TableOperationError {
/// The schema of the table that caused the error
actual_schema: Vec<ColumnField>,
},
/// Errors related to joining tables on columns with incompatible types.
#[snafu(display(
"Cannot join tables on columns with incompatible types: {left_type:?} and {right_type:?}"
))]
JoinIncompatibleTypes {
/// The left-hand side data type
left_type: ColumnType,
/// The right-hand side data type
right_type: ColumnType,
},
}

/// Result type for table operations
Expand Down

0 comments on commit 775724a

Please sign in to comment.