use crate::{
db::{
direction::Direction,
executor::{aggregate::AggregateKind, route::AggregateRouteShape},
numeric::field_kind_supports_aggregate_numeric,
query::plan::AccessPlannedQuery,
},
model::{field::FieldKind, index::IndexModel},
};
#[must_use]
pub(in crate::db::executor) const fn field_kind_supports_aggregate_ordering(
kind: &FieldKind,
) -> bool {
match kind {
FieldKind::Account
| FieldKind::Bool
| FieldKind::Date
| FieldKind::Decimal { .. }
| FieldKind::Duration
| FieldKind::Enum { .. }
| FieldKind::Float32
| FieldKind::Float64
| FieldKind::Int
| FieldKind::Int128
| FieldKind::IntBig
| FieldKind::Principal
| FieldKind::Subaccount
| FieldKind::Text
| FieldKind::Timestamp
| FieldKind::Uint
| FieldKind::Uint128
| FieldKind::UintBig
| FieldKind::Ulid
| FieldKind::Unit => true,
FieldKind::Relation { key_kind, .. } => field_kind_supports_aggregate_ordering(key_kind),
FieldKind::Blob
| FieldKind::List(_)
| FieldKind::Set(_)
| FieldKind::Map { .. }
| FieldKind::Structured { .. } => false,
}
}
#[must_use]
pub(in crate::db::executor) const fn field_kind_supports_numeric_aggregation(
kind: &FieldKind,
) -> bool {
field_kind_supports_aggregate_numeric(kind)
}
#[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 {
has_residual_filter: bool,
requires_post_access_sort: bool,
}
impl AggregateExecutionPolicyInputs {
#[must_use]
pub(in crate::db::executor) const fn new(
has_residual_filter: bool,
requires_post_access_sort: bool,
) -> Self {
Self {
has_residual_filter,
requires_post_access_sort,
}
}
#[must_use]
const fn has_residual_filter(self) -> bool {
self.has_residual_filter
}
#[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_class = plan.access_strategy().class();
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_class.single_path_supports_count_pushdown_shape(),
composite_aggregate_fast_path_eligible: access_class.composite()
&& !inputs.has_residual_filter()
&& !inputs.requires_post_access_sort(),
field_min_fast_path,
field_max_fast_path,
}
}
pub(in crate::db::executor) 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_class = plan.access_strategy().class();
if access_class.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_class.reverse_supported() {
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_class = plan.access_strategy().class();
if !access_class.single_path() {
return false;
}
if aggregate.target_field_is_primary_key() {
return access_class.single_path_supports_pk_stream_access();
}
let Some(target_field) = aggregate.target_field() else {
return false;
};
access_class
.single_path_index_prefix_details()
.or_else(|| access_class.single_path_index_range_details())
.is_some_and(|(index, _)| {
index
.fields()
.first()
.is_some_and(|field| field == &target_field)
})
}
#[must_use]
pub(in crate::db::executor) 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)
})
}