Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: timestamp inequality support #52

Merged
merged 11 commits into from
Jul 18, 2024
2 changes: 1 addition & 1 deletion crates/proof-of-sql/src/sql/parse/query_context_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,11 @@ pub(crate) fn type_check_binary_operation(
return false;
}
}
// TODO: inequality support for timestamps
left_dtype.is_numeric() && right_dtype.is_numeric()
|| matches!(
(left_dtype, right_dtype),
(ColumnType::Boolean, ColumnType::Boolean)
| (ColumnType::TimestampTZ(_, _), ColumnType::TimestampTZ(_, _))
)
}
BinaryOperator::Add | BinaryOperator::Subtract => {
Expand Down
158 changes: 156 additions & 2 deletions crates/proof-of-sql/tests/timestamp_integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use proof_of_sql::base::commitment::InnerProductProof;
use proof_of_sql::{
base::database::{owned_table_utility::*, OwnedTableTestAccessor, TestAccessor},
proof_primitive::dory::{
test_rng, DoryEvaluationProof, DoryProverPublicSetup, DoryVerifierPublicSetup, ProverSetup,
PublicParameters, VerifierSetup,
test_rng, DoryCommitment, DoryEvaluationProof, DoryProverPublicSetup,
DoryVerifierPublicSetup, ProverSetup, PublicParameters, VerifierSetup,
},
sql::{
parse::QueryExpr,
Expand Down Expand Up @@ -134,6 +134,86 @@ mod tests {
);
}

#[test]
fn test_basic_timestamp_inequality_query() {
let test_timestamps = vec![i64::MIN, -1, 0, 1, i64::MAX];

run_timestamp_query_test(
"SELECT * FROM table WHERE times < timestamp '1970-01-01T00:00:00Z';",
Dustin-Ray marked this conversation as resolved.
Show resolved Hide resolved
test_timestamps.clone(),
vec![i64::MIN, -1],
);

run_timestamp_query_test(
"SELECT * FROM table WHERE times > timestamp '1970-01-01T00:00:00Z';",
test_timestamps.clone(),
vec![1, i64::MAX],
);

run_timestamp_query_test(
"SELECT * FROM table WHERE times >= timestamp '1970-01-01T00:00:00Z';",
test_timestamps.clone(),
vec![0, 1, i64::MAX],
);

run_timestamp_query_test(
"SELECT * FROM table WHERE times <= timestamp '1970-01-01T00:00:00Z';",
test_timestamps.clone(),
vec![i64::MIN, -1, 0],
);
}

#[test]
fn test_timestamp_inequality_queries_with_timezone_offsets() {
// Test with a range of timestamps around the Unix epoch
// 60 * 60 = 3600 * 8 (PST offset) = 28800
let test_timestamps = vec![i64::MIN, 28800, 28799, 0, 1, i64::MAX];

// Test timezone offset -08:00 (e.g., Pacific Standard Time)
run_timestamp_query_test(
"SELECT * FROM table WHERE times > timestamp '1970-01-01T00:00:00-08:00';",
test_timestamps.clone(),
vec![i64::MAX],
);
run_timestamp_query_test(
"SELECT * FROM table WHERE times < timestamp '1970-01-01T00:00:00-08:00';",
test_timestamps.clone(),
vec![i64::MIN, 28799, 0, 1],
);
run_timestamp_query_test(
"SELECT * FROM table WHERE times >= timestamp '1970-01-01T00:00:00-08:00';",
test_timestamps.clone(),
vec![28800, i64::MAX],
);
run_timestamp_query_test(
"SELECT * FROM table WHERE times <= timestamp '1970-01-01T00:00:00-08:00';",
test_timestamps.clone(),
vec![i64::MIN, 28800, 28799, 0, 1],
);

// Test timezone offset +00:00 (e.g., UTC)
run_timestamp_query_test(
"SELECT * FROM table WHERE times > timestamp '1970-01-01T00:00:00+00:00';",
test_timestamps.clone(),
vec![28800, 28799, 1, i64::MAX],
);
run_timestamp_query_test(
"SELECT * FROM table WHERE times < timestamp '1970-01-01T00:00:00+00:00';",
test_timestamps.clone(),
vec![i64::MIN],
);
run_timestamp_query_test(
"SELECT * FROM table WHERE times >= timestamp '1970-01-01T00:00:00+00:00';",
test_timestamps.clone(),
vec![28800, 28799, 0, 1, i64::MAX],
);
run_timestamp_query_test(
"SELECT * FROM table WHERE times <= timestamp '1970-01-01T00:00:00+00:00';",
test_timestamps.clone(),
vec![i64::MIN, 0],
);
}

// This test simulates the following query:
//
// 1. Creating a table:
Expand Down Expand Up @@ -342,3 +422,77 @@ mod tests {
);
}
}

#[test]
#[cfg(feature = "blitzar")]
fn we_can_prove_timestamp_inequality_queries_with_multiple_columns() {
let public_parameters = PublicParameters::rand(4, &mut test_rng());
let prover_setup = ProverSetup::from(&public_parameters);
let verifier_setup = VerifierSetup::from(&public_parameters);
let dory_prover_setup = DoryProverPublicSetup::new(&prover_setup, 3);
let dory_verifier_setup = DoryVerifierPublicSetup::new(&verifier_setup, 3);
let mut accessor =
OwnedTableTestAccessor::<DoryEvaluationProof>::new_empty_with_setup(dory_prover_setup);
accessor.add_table(
"sxt.table".parse().unwrap(),
owned_table([
timestamptz(
"a",
PoSQLTimeUnit::Nanosecond,
PoSQLTimeZone::Utc,
[
i64::MIN,
2,
-1,
0,
1,
-2,
1231006505000000000, // bitcoin genesis block time
i64::MAX,
],
),
timestamptz(
"b",
PoSQLTimeUnit::Nanosecond,
PoSQLTimeZone::Utc,
[i64::MAX, -2, -1, -1231006505000000000, 0, 1, 2, i64::MIN],
),
]),
0,
);
let query = QueryExpr::<DoryCommitment>::try_new(
"select *, a <= b as res from TABLE where a <= b"
.parse()
.unwrap(),
"sxt".parse().unwrap(),
&accessor,
)
.unwrap();
let (proof, serialized_result) =
QueryProof::<DoryEvaluationProof>::new(query.proof_expr(), &accessor, &dory_prover_setup);
let owned_table_result = proof
.verify(
query.proof_expr(),
&accessor,
&serialized_result,
&dory_verifier_setup,
)
.unwrap()
.table;
let expected_result = owned_table([
timestamptz(
"a",
PoSQLTimeUnit::Nanosecond,
PoSQLTimeZone::Utc,
[i64::MIN, -1, -2],
),
timestamptz(
"b",
PoSQLTimeUnit::Nanosecond,
PoSQLTimeZone::Utc,
[i64::MAX, -1, 1],
),
boolean("res", [true, true, true]),
]);
assert_eq!(owned_table_result, expected_result);
}
Loading