use super::{PlannerError, PlannerResult};
use crate::expr_to_proof_expr;
use datafusion::{
logical_expr::{
expr::{AggregateFunction, AggregateFunctionDefinition},
Expr,
},
physical_plan,
};
use proof_of_sql::{
base::database::{ColumnType, LiteralValue},
sql::proof_exprs::DynProofExpr,
};
use sqlparser::ast::Ident;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum AggregateFunc {
Sum,
Count,
}
pub(crate) fn aggregate_function_to_proof_expr(
function: &AggregateFunction,
schema: &[(Ident, ColumnType)],
) -> PlannerResult<(AggregateFunc, DynProofExpr)> {
match function {
AggregateFunction {
distinct: false,
filter: None,
order_by: None,
args,
func_def: AggregateFunctionDefinition::BuiltIn(op),
..
} if args.len() == 1 => {
let arg = &args[0];
match (op, arg) {
(physical_plan::aggregates::AggregateFunction::Count, &Expr::Wildcard { .. }) => {
let proof_expr = DynProofExpr::new_literal(LiteralValue::BigInt(1));
Ok((AggregateFunc::Count, proof_expr))
}
(physical_plan::aggregates::AggregateFunction::Sum, _) => {
Ok((AggregateFunc::Sum, expr_to_proof_expr(arg, schema)?))
}
(physical_plan::aggregates::AggregateFunction::Count, _) => {
Ok((AggregateFunc::Count, expr_to_proof_expr(arg, schema)?))
}
_ => Err(PlannerError::UnsupportedAggregateOperation { op: op.clone() }),
}
}
_ => Err(PlannerError::UnsupportedAggregateFunction {
function: function.clone(),
})?,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::df_util::*;
use proof_of_sql::base::database::{ColumnRef, ColumnType, TableRef};
#[test]
fn we_can_convert_an_aggregate_function_to_proof_expr() {
let expr = df_column("table", "a");
let schema: Vec<(Ident, ColumnType)> = vec![("a".into(), ColumnType::BigInt)];
for (function, operator) in &[
(
physical_plan::aggregates::AggregateFunction::Sum,
AggregateFunc::Sum,
),
(
physical_plan::aggregates::AggregateFunction::Count,
AggregateFunc::Count,
),
] {
let function = AggregateFunction::new(
function.clone(),
vec![expr.clone()],
false,
None,
None,
None,
);
assert_eq!(
aggregate_function_to_proof_expr(&function, &schema).unwrap(),
(
*operator,
DynProofExpr::new_column(ColumnRef::new(
TableRef::from_names(None, "table"),
"a".into(),
ColumnType::BigInt
))
)
);
}
}
#[test]
fn we_can_convert_count_star_to_count_one() {
use proof_of_sql::base::database::LiteralValue;
let wildcard_expr = Expr::Wildcard { qualifier: None };
let schema: Vec<(Ident, ColumnType)> = vec![("a".into(), ColumnType::BigInt)];
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::Count,
vec![wildcard_expr],
false,
None,
None,
None,
);
assert_eq!(
aggregate_function_to_proof_expr(&function, &schema).unwrap(),
(
AggregateFunc::Count,
DynProofExpr::new_literal(LiteralValue::BigInt(1))
)
);
}
#[test]
fn we_cannot_convert_an_aggregate_function_to_pair_if_unsupported() {
let expr = df_column("table", "a");
let schema = vec![("a".into(), ColumnType::BigInt)];
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::RegrIntercept,
vec![expr.clone()],
false,
None,
None,
None,
);
assert!(matches!(
aggregate_function_to_proof_expr(&function, &schema),
Err(PlannerError::UnsupportedAggregateOperation { .. })
));
}
#[test]
fn we_cannot_convert_an_aggregate_function_to_pair_if_too_many_or_no_exprs() {
let expr = df_column("table", "a");
let schema = vec![("a".into(), ColumnType::BigInt)];
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::Sum,
vec![expr.clone(); 2],
false,
None,
None,
None,
);
assert!(matches!(
aggregate_function_to_proof_expr(&function, &schema),
Err(PlannerError::UnsupportedAggregateFunction { .. })
));
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::Sum,
Vec::<_>::new(),
false,
None,
None,
None,
);
assert!(matches!(
aggregate_function_to_proof_expr(&function, &schema),
Err(PlannerError::UnsupportedAggregateFunction { .. })
));
}
#[test]
fn we_cannot_convert_an_aggregate_function_to_pair_if_unsupported_options() {
let expr = df_column("table", "a");
let schema = vec![("a".into(), ColumnType::BigInt)];
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::Count,
vec![expr.clone()],
true,
None,
None,
None,
);
assert!(matches!(
aggregate_function_to_proof_expr(&function, &schema),
Err(PlannerError::UnsupportedAggregateFunction { .. })
));
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::Count,
vec![expr.clone()],
false,
Some(Box::new(expr.clone())),
None,
None,
);
assert!(matches!(
aggregate_function_to_proof_expr(&function, &schema),
Err(PlannerError::UnsupportedAggregateFunction { .. })
));
let function = AggregateFunction::new(
physical_plan::aggregates::AggregateFunction::Count,
vec![expr.clone()],
false,
None,
Some(vec![expr.clone()]),
None,
);
assert!(matches!(
aggregate_function_to_proof_expr(&function, &schema),
Err(PlannerError::UnsupportedAggregateFunction { .. })
));
}
}