use crate::{
db::{
executor::projection::eval::ProjectionEvalError,
query::plan::{
FieldSlot, GroupedAggregateExecutionSpec, PlannedProjectionLayout,
expr::{CompiledExpr, CompiledExprValueReader, ProjectionSpec},
},
},
error::InternalError,
value::Value,
};
use std::borrow::Cow;
pub(in crate::db::executor) use crate::db::query::plan::expr::compile_grouped_projection_plan;
pub(in crate::db::executor) use crate::db::query::plan::expr::{
compile_grouped_projection_expr, evaluate_grouped_having_expr,
};
pub(in crate::db::executor) struct GroupedRowView<'a> {
pub(in crate::db::executor::projection) key_values: &'a [Value],
pub(in crate::db::executor::projection) aggregate_values: &'a [Value],
#[cfg(test)]
group_fields: &'a [FieldSlot],
#[cfg(test)]
pub(in crate::db::executor::projection) aggregate_execution_specs:
&'a [GroupedAggregateExecutionSpec],
}
impl<'a> GroupedRowView<'a> {
#[must_use]
pub(in crate::db::executor) const fn new(
key_values: &'a [Value],
aggregate_values: &'a [Value],
group_fields: &'a [FieldSlot],
aggregate_execution_specs: &'a [GroupedAggregateExecutionSpec],
) -> Self {
#[cfg(not(test))]
let _ = (group_fields, aggregate_execution_specs);
Self {
key_values,
aggregate_values,
#[cfg(test)]
group_fields,
#[cfg(test)]
aggregate_execution_specs,
}
}
#[must_use]
pub(in crate::db::executor) const fn key_values(&self) -> &'a [Value] {
self.key_values
}
#[must_use]
pub(in crate::db::executor) const fn aggregate_values(&self) -> &'a [Value] {
self.aggregate_values
}
#[cfg(test)]
#[must_use]
pub(in crate::db::executor) const fn group_fields(&self) -> &'a [FieldSlot] {
self.group_fields
}
}
impl CompiledExprValueReader for GroupedRowView<'_> {
fn read_slot(&self, _slot: usize) -> Option<Cow<'_, Value>> {
None
}
fn read_group_key(&self, offset: usize) -> Option<Cow<'_, Value>> {
self.key_values().get(offset).map(Cow::Borrowed)
}
fn read_aggregate(&self, index: usize) -> Option<Cow<'_, Value>> {
self.aggregate_values().get(index).map(Cow::Borrowed)
}
}
#[derive(Clone)]
pub(in crate::db::executor) struct CompiledGroupedProjectionPlan<'a> {
compiled_projection: Vec<CompiledExpr>,
projection_layout: &'a PlannedProjectionLayout,
group_fields: &'a [FieldSlot],
aggregate_execution_specs: &'a [GroupedAggregateExecutionSpec],
}
impl<'a> CompiledGroupedProjectionPlan<'a> {
#[cfg(test)]
#[must_use]
pub(in crate::db::executor) const fn from_parts_for_test(
compiled_projection: Vec<CompiledExpr>,
projection_layout: &'a PlannedProjectionLayout,
group_fields: &'a [FieldSlot],
aggregate_execution_specs: &'a [GroupedAggregateExecutionSpec],
) -> Self {
Self {
compiled_projection,
projection_layout,
group_fields,
aggregate_execution_specs,
}
}
#[must_use]
pub(in crate::db::executor) const fn compiled_projection(&self) -> &[CompiledExpr] {
self.compiled_projection.as_slice()
}
#[must_use]
pub(in crate::db::executor) const fn projection_layout(&self) -> &'a PlannedProjectionLayout {
self.projection_layout
}
#[must_use]
pub(in crate::db::executor) const fn group_fields(&self) -> &'a [FieldSlot] {
self.group_fields
}
#[must_use]
pub(in crate::db::executor) const fn aggregate_execution_specs(
&self,
) -> &'a [GroupedAggregateExecutionSpec] {
self.aggregate_execution_specs
}
}
pub(in crate::db::executor) fn compile_grouped_projection_plan_if_needed<'a>(
projection: &ProjectionSpec,
projection_is_identity: bool,
projection_layout: &'a PlannedProjectionLayout,
group_fields: &'a [FieldSlot],
aggregate_execution_specs: &'a [GroupedAggregateExecutionSpec],
) -> Result<Option<CompiledGroupedProjectionPlan<'a>>, InternalError> {
if projection_is_identity {
return Ok(None);
}
let compiled_projection =
compile_grouped_projection_plan(projection, group_fields, aggregate_execution_specs)
.map_err(ProjectionEvalError::into_grouped_projection_internal_error)?;
Ok(Some(CompiledGroupedProjectionPlan {
compiled_projection,
projection_layout,
group_fields,
aggregate_execution_specs,
}))
}
#[cfg(test)]
pub(in crate::db::executor) fn evaluate_grouped_projection_values(
compiled_projection: &[CompiledExpr],
grouped_row: &GroupedRowView<'_>,
) -> Result<Vec<Value>, ProjectionEvalError> {
let mut projected_values = Vec::with_capacity(compiled_projection.len());
for expr in compiled_projection {
projected_values.push(expr.evaluate(grouped_row)?.into_owned());
}
Ok(projected_values)
}