use crate::{
db::{
direction::Direction,
executor::{
aggregate::AggregateKind,
route::{
AggregateRouteShape, count_pushdown_shape_supported,
primary_key_stream_window_shape_supported,
},
},
query::plan::AccessPlannedQuery,
},
model::{classify_field_kind, field::FieldKind, index::IndexModel},
};
#[must_use]
pub(in crate::db::executor) const fn field_kind_supports_aggregate_ordering(
kind: &FieldKind,
) -> bool {
classify_field_kind(kind).supports_aggregate_ordering()
}
#[must_use]
pub(in crate::db::executor) const fn field_kind_supports_numeric_aggregation(
kind: &FieldKind,
) -> bool {
classify_field_kind(kind).supports_aggregate_numeric()
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::executor) enum AggregateFieldExtremaIneligibilityReason {
SpecMissing,
AggregateKindMismatch,
TargetFieldMissing,
UnknownTargetField,
UnsupportedFieldType,
DistinctNotSupported,
PageLimitNotSupported,
OffsetNotSupported,
CompositePathNotSupported,
NoMatchingIndex,
DescReverseTraversalNotSupported,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::executor) struct AggregateFieldExtremaEligibility {
pub(in crate::db::executor) eligible: bool,
pub(in crate::db::executor) ineligibility_reason:
Option<AggregateFieldExtremaIneligibilityReason>,
}
impl AggregateFieldExtremaEligibility {
const fn ineligible(reason: AggregateFieldExtremaIneligibilityReason) -> Self {
Self {
eligible: false,
ineligibility_reason: Some(reason),
}
}
const fn eligible() -> Self {
Self {
eligible: true,
ineligibility_reason: None,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::executor) struct AggregateExecutionPolicyInputs {
residual_filter_present: bool,
requires_post_access_sort: bool,
}
impl AggregateExecutionPolicyInputs {
#[must_use]
pub(in crate::db::executor) const fn new(
residual_filter_present: bool,
requires_post_access_sort: bool,
) -> Self {
Self {
residual_filter_present,
requires_post_access_sort,
}
}
#[must_use]
const fn residual_filter_present(self) -> bool {
self.residual_filter_present
}
#[must_use]
const fn requires_post_access_sort(self) -> bool {
self.requires_post_access_sort
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db::executor) struct AggregateExecutionPolicy {
count_pushdown_shape_supported: bool,
composite_aggregate_fast_path_eligible: bool,
field_min_fast_path: AggregateFieldExtremaEligibility,
field_max_fast_path: AggregateFieldExtremaEligibility,
}
impl AggregateExecutionPolicy {
#[must_use]
pub(in crate::db::executor) const fn count_pushdown_shape_supported(self) -> bool {
self.count_pushdown_shape_supported
}
#[must_use]
pub(in crate::db::executor) const fn composite_aggregate_fast_path_eligible(self) -> bool {
self.composite_aggregate_fast_path_eligible
}
#[must_use]
pub(in crate::db::executor) const fn field_min_fast_path(
self,
) -> AggregateFieldExtremaEligibility {
self.field_min_fast_path
}
#[must_use]
pub(in crate::db::executor) const fn field_max_fast_path(
self,
) -> AggregateFieldExtremaEligibility {
self.field_max_fast_path
}
}
pub(in crate::db::executor) fn derive_aggregate_execution_policy(
plan: &AccessPlannedQuery,
direction: Direction,
aggregate_shape: Option<AggregateRouteShape<'_>>,
inputs: AggregateExecutionPolicyInputs,
) -> AggregateExecutionPolicy {
let access_capabilities = plan.access_capabilities();
let field_min_fast_path = assess_field_extrema_fast_path_eligibility(
plan,
direction,
aggregate_shape,
AggregateKind::Min,
);
let field_max_fast_path = assess_field_extrema_fast_path_eligibility(
plan,
direction,
aggregate_shape,
AggregateKind::Max,
);
AggregateExecutionPolicy {
count_pushdown_shape_supported: access_capabilities
.single_path_capabilities()
.is_some_and(count_pushdown_shape_supported),
composite_aggregate_fast_path_eligible: access_capabilities.is_composite()
&& !inputs.residual_filter_present()
&& !inputs.requires_post_access_sort(),
field_min_fast_path,
field_max_fast_path,
}
}
fn assess_field_extrema_fast_path_eligibility(
plan: &AccessPlannedQuery,
direction: Direction,
aggregate_shape: Option<AggregateRouteShape<'_>>,
extrema_kind: AggregateKind,
) -> AggregateFieldExtremaEligibility {
let Some(aggregate) = aggregate_shape else {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::SpecMissing,
);
};
if aggregate.kind() != extrema_kind {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::AggregateKindMismatch,
);
}
let Some(_target_field) = aggregate.target_field() else {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::TargetFieldMissing,
);
};
if !aggregate.target_field_known() {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::UnknownTargetField,
);
}
if !aggregate.target_field_orderable() {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::UnsupportedFieldType,
);
}
if plan.scalar_plan().distinct {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::DistinctNotSupported,
);
}
let offset = usize::try_from(crate::db::cursor::effective_page_offset_for_window(
plan, false,
))
.unwrap_or(usize::MAX);
if offset > 0 {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::OffsetNotSupported,
);
}
let access_capabilities = plan.access_capabilities();
if access_capabilities.is_composite() {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::CompositePathNotSupported,
);
}
if !field_extrema_target_has_matching_index(plan, aggregate) {
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::NoMatchingIndex,
);
}
if matches!(direction, Direction::Desc)
&& !access_capabilities.all_paths_support_reverse_traversal()
{
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::DescReverseTraversalNotSupported,
);
}
if plan
.scalar_plan()
.page
.as_ref()
.is_some_and(|page| page.limit.is_some())
{
return AggregateFieldExtremaEligibility::ineligible(
AggregateFieldExtremaIneligibilityReason::PageLimitNotSupported,
);
}
AggregateFieldExtremaEligibility::eligible()
}
fn field_extrema_target_has_matching_index(
plan: &AccessPlannedQuery,
aggregate: AggregateRouteShape<'_>,
) -> bool {
let access_capabilities = plan.access_capabilities();
let Some(path_capabilities) = access_capabilities.single_path_capabilities() else {
return false;
};
if aggregate.target_field_is_primary_key() {
return primary_key_stream_window_shape_supported(path_capabilities);
}
let Some(target_field) = aggregate.target_field() else {
return false;
};
access_capabilities
.single_path_index_prefix_details()
.or_else(|| access_capabilities.single_path_index_range_details())
.is_some_and(|details| {
details
.index()
.fields()
.first()
.is_some_and(|field| field == &target_field)
})
}
#[must_use]
const fn field_target_is_primary_key(aggregate: AggregateRouteShape<'_>) -> bool {
aggregate.target_field_is_primary_key()
}
#[must_use]
pub(in crate::db::executor) fn field_target_is_tie_free_probe_target(
aggregate: AggregateRouteShape<'_>,
index_model: Option<IndexModel>,
) -> bool {
field_target_is_primary_key(aggregate)
|| aggregate.target_field().is_some_and(|target_field| {
field_target_is_unique_single_field_index_head(target_field, index_model)
})
}
fn field_target_is_unique_single_field_index_head(
target_field: &str,
index_model: Option<IndexModel>,
) -> bool {
index_model.is_some_and(|index_model| {
index_model.is_unique()
&& index_model.fields().len() == 1
&& index_model
.fields()
.first()
.is_some_and(|field| *field == target_field)
})
}