use crate::{
db::{
cursor::ContinuationSignature,
direction::Direction,
predicate::{MissingRowPolicy, Predicate},
query::{
builder::scalar_projection::render_scalar_projection_expr_plan_label,
plan::{
expr::{Expr, FieldId, normalize_bool_expr},
order_contract::DeterministicSecondaryOrderContract,
semantics::LogicalPushdownEligibility,
},
},
},
model::field::FieldKind,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum QueryMode {
Load(LoadSpec),
Delete(DeleteSpec),
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct LoadSpec {
pub(in crate::db) limit: Option<u32>,
pub(in crate::db) offset: u32,
}
impl LoadSpec {
#[must_use]
pub const fn limit(&self) -> Option<u32> {
self.limit
}
#[must_use]
pub const fn offset(&self) -> u32 {
self.offset
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct DeleteSpec {
pub(in crate::db) limit: Option<u32>,
pub(in crate::db) offset: u32,
}
impl DeleteSpec {
#[must_use]
pub const fn limit(&self) -> Option<u32> {
self.limit
}
#[must_use]
pub const fn offset(&self) -> u32 {
self.offset
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OrderDirection {
Asc,
Desc,
}
#[derive(Clone, Eq, PartialEq)]
pub(in crate::db) struct OrderTerm {
pub(in crate::db) expr: Expr,
pub(in crate::db) direction: OrderDirection,
}
impl OrderTerm {
#[must_use]
pub(in crate::db) const fn new(expr: Expr, direction: OrderDirection) -> Self {
Self { expr, direction }
}
#[must_use]
pub(in crate::db) fn field(field: impl Into<String>, direction: OrderDirection) -> Self {
Self::new(Expr::Field(FieldId::new(field.into())), direction)
}
#[must_use]
pub(in crate::db) const fn expr(&self) -> &Expr {
&self.expr
}
#[must_use]
pub(in crate::db) const fn direct_field(&self) -> Option<&str> {
let Expr::Field(field) = &self.expr else {
return None;
};
Some(field.as_str())
}
#[must_use]
pub(in crate::db) fn rendered_label(&self) -> String {
render_scalar_projection_expr_plan_label(&self.expr)
}
#[must_use]
pub(in crate::db) const fn direction(&self) -> OrderDirection {
self.direction
}
}
impl std::fmt::Debug for OrderTerm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OrderTerm")
.field("label", &self.rendered_label())
.field("expr", &self.expr)
.field("direction", &self.direction)
.finish()
}
}
impl PartialEq<(String, OrderDirection)> for OrderTerm {
fn eq(&self, other: &(String, OrderDirection)) -> bool {
self.rendered_label() == other.0 && self.direction == other.1
}
}
impl PartialEq<OrderTerm> for (String, OrderDirection) {
fn eq(&self, other: &OrderTerm) -> bool {
self.0 == other.rendered_label() && self.1 == other.direction
}
}
#[must_use]
pub(in crate::db) fn render_scalar_filter_expr_plan_label(expr: &Expr) -> String {
render_scalar_projection_expr_plan_label(&normalize_bool_expr(expr.clone()))
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct OrderSpec {
pub(in crate::db) fields: Vec<OrderTerm>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct DeleteLimitSpec {
pub(in crate::db) limit: Option<u32>,
pub(in crate::db) offset: u32,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) enum DistinctExecutionStrategy {
None,
PreOrdered,
HashMaterialize,
}
impl DistinctExecutionStrategy {
#[must_use]
pub(in crate::db) const fn is_enabled(self) -> bool {
!matches!(self, Self::None)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct PlannerRouteProfile {
continuation_policy: ContinuationPolicy,
logical_pushdown_eligibility: LogicalPushdownEligibility,
secondary_order_contract: Option<DeterministicSecondaryOrderContract>,
}
impl PlannerRouteProfile {
#[must_use]
pub(in crate::db) const fn new(
continuation_policy: ContinuationPolicy,
logical_pushdown_eligibility: LogicalPushdownEligibility,
secondary_order_contract: Option<DeterministicSecondaryOrderContract>,
) -> Self {
Self {
continuation_policy,
logical_pushdown_eligibility,
secondary_order_contract,
}
}
#[must_use]
pub(in crate::db) const fn seeded_unfinalized(is_grouped: bool) -> Self {
Self {
continuation_policy: ContinuationPolicy::new(true, true, !is_grouped),
logical_pushdown_eligibility: LogicalPushdownEligibility::new(false, is_grouped, false),
secondary_order_contract: None,
}
}
#[must_use]
pub(in crate::db) const fn continuation_policy(&self) -> &ContinuationPolicy {
&self.continuation_policy
}
#[must_use]
pub(in crate::db) const fn logical_pushdown_eligibility(&self) -> LogicalPushdownEligibility {
self.logical_pushdown_eligibility
}
#[must_use]
pub(in crate::db) const fn secondary_order_contract(
&self,
) -> Option<&DeterministicSecondaryOrderContract> {
self.secondary_order_contract.as_ref()
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct ContinuationPolicy {
requires_anchor: bool,
requires_strict_advance: bool,
is_grouped_safe: bool,
}
impl ContinuationPolicy {
#[must_use]
pub(in crate::db) const fn new(
requires_anchor: bool,
requires_strict_advance: bool,
is_grouped_safe: bool,
) -> Self {
Self {
requires_anchor,
requires_strict_advance,
is_grouped_safe,
}
}
#[must_use]
pub(in crate::db) const fn requires_anchor(self) -> bool {
self.requires_anchor
}
#[must_use]
pub(in crate::db) const fn requires_strict_advance(self) -> bool {
self.requires_strict_advance
}
#[must_use]
pub(in crate::db) const fn is_grouped_safe(self) -> bool {
self.is_grouped_safe
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct ExecutionShapeSignature {
continuation_signature: ContinuationSignature,
}
impl ExecutionShapeSignature {
#[must_use]
pub(in crate::db) const fn new(continuation_signature: ContinuationSignature) -> Self {
Self {
continuation_signature,
}
}
#[must_use]
pub(in crate::db) const fn continuation_signature(self) -> ContinuationSignature {
self.continuation_signature
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct PageSpec {
pub(in crate::db) limit: Option<u32>,
pub(in crate::db) offset: u32,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AggregateKind {
Count,
Sum,
Avg,
Exists,
Min,
Max,
First,
Last,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) enum GlobalDistinctAggregateKind {
Count,
Sum,
Avg,
}
impl GlobalDistinctAggregateKind {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) enum GroupedPlanAggregateFamily {
CountRowsOnly,
FieldTargetRows,
GenericRows,
}
impl GroupedPlanAggregateFamily {
#[must_use]
pub(in crate::db) const fn code(self) -> &'static str {
match self {
Self::CountRowsOnly => "count_rows_only",
Self::FieldTargetRows => "field_target_rows",
Self::GenericRows => "generic_rows",
}
}
}
impl AggregateKind {
#[must_use]
pub(in crate::db) const fn canonical_label(self) -> &'static str {
match self {
Self::Count => "COUNT",
Self::Sum => "SUM",
Self::Avg => "AVG",
Self::Exists => "EXISTS",
Self::First => "FIRST",
Self::Last => "LAST",
Self::Min => "MIN",
Self::Max => "MAX",
}
}
#[must_use]
pub(in crate::db) const fn is_count(self) -> bool {
matches!(self, Self::Count)
}
#[must_use]
pub(in crate::db) const fn is_sum(self) -> bool {
matches!(self, Self::Sum | Self::Avg)
}
#[must_use]
pub(in crate::db) const fn is_extrema(self) -> bool {
matches!(self, Self::Min | Self::Max)
}
#[must_use]
pub(in crate::db) const fn supports_field_target_v1(self) -> bool {
matches!(
self,
Self::Count | Self::Sum | Self::Avg | Self::Min | Self::Max
)
}
#[must_use]
pub(in crate::db) const fn requires_decoded_id(self) -> bool {
!matches!(self, Self::Count | Self::Sum | Self::Avg | Self::Exists)
}
#[must_use]
pub(in crate::db) const fn supports_grouped_distinct_v1(self) -> bool {
matches!(self, Self::Count | Self::Sum | Self::Avg)
}
#[must_use]
pub(in crate::db::query) const fn fingerprint_tag(self) -> u8 {
match self {
Self::Count => 0x01,
Self::Sum => 0x02,
Self::Exists => 0x03,
Self::Min => 0x04,
Self::Max => 0x05,
Self::First => 0x06,
Self::Last => 0x07,
Self::Avg => 0x08,
}
}
#[must_use]
pub(in crate::db) const fn global_distinct_kind(self) -> Option<GlobalDistinctAggregateKind> {
match self {
Self::Count => Some(GlobalDistinctAggregateKind::Count),
Self::Sum => Some(GlobalDistinctAggregateKind::Sum),
Self::Avg => Some(GlobalDistinctAggregateKind::Avg),
Self::Exists | Self::Min | Self::Max | Self::First | Self::Last => None,
}
}
#[must_use]
pub(in crate::db) const fn supports_global_distinct_without_group_keys(self) -> bool {
self.global_distinct_kind().is_some()
}
#[must_use]
pub(in crate::db) const fn grouped_plan_family(
self,
has_target_field: bool,
) -> GroupedPlanAggregateFamily {
if has_target_field && self.supports_field_target_v1() {
GroupedPlanAggregateFamily::FieldTargetRows
} else {
GroupedPlanAggregateFamily::GenericRows
}
}
#[must_use]
pub(in crate::db) const fn supports_grouped_streaming_v1(
self,
has_target_field: bool,
distinct: bool,
) -> bool {
if self.supports_field_target_v1() {
return !distinct && (self.is_count() || has_target_field);
}
!has_target_field && (!distinct || self.supports_grouped_distinct_v1())
}
#[must_use]
pub(in crate::db) const fn extrema_direction(self) -> Option<Direction> {
match self {
Self::Min => Some(Direction::Asc),
Self::Max => Some(Direction::Desc),
Self::Count | Self::Sum | Self::Avg | Self::Exists | Self::First | Self::Last => None,
}
}
#[must_use]
pub(in crate::db) const fn materialized_fold_direction(self) -> Direction {
match self {
Self::Min => Direction::Desc,
Self::Count
| Self::Sum
| Self::Avg
| Self::Exists
| Self::Max
| Self::First
| Self::Last => Direction::Asc,
}
}
#[must_use]
pub(in crate::db) const fn supports_bounded_probe_hint(self) -> bool {
!self.is_count() && !self.is_sum()
}
#[must_use]
pub(in crate::db) fn bounded_probe_fetch_hint(
self,
direction: Direction,
offset: usize,
page_limit: Option<usize>,
) -> Option<usize> {
match self {
Self::Exists | Self::First => Some(offset.saturating_add(1)),
Self::Min if direction == Direction::Asc => Some(offset.saturating_add(1)),
Self::Max if direction == Direction::Desc => Some(offset.saturating_add(1)),
Self::Last => page_limit.map(|limit| offset.saturating_add(limit)),
Self::Count | Self::Sum | Self::Avg | Self::Min | Self::Max => None,
}
}
#[must_use]
pub(in crate::db) const fn explain_projection_mode_label(
self,
has_projected_field: bool,
covering_projection: bool,
) -> &'static str {
if has_projected_field {
if covering_projection {
"field_idx"
} else {
"field_mat"
}
} else if matches!(self, Self::Min | Self::Max | Self::First | Self::Last) {
"entity_term"
} else {
"scalar_agg"
}
}
#[must_use]
pub(in crate::db) const fn supports_covering_existing_rows_terminal(self) -> bool {
matches!(self, Self::Count | Self::Exists)
}
}
#[derive(Clone, Debug)]
pub(in crate::db) struct GroupAggregateSpec {
pub(in crate::db) kind: AggregateKind,
pub(in crate::db) input_expr: Option<Box<Expr>>,
pub(in crate::db) filter_expr: Option<Box<Expr>>,
pub(in crate::db) distinct: bool,
}
impl PartialEq for GroupAggregateSpec {
fn eq(&self, other: &Self) -> bool {
self.semantic_key() == other.semantic_key()
}
}
impl Eq for GroupAggregateSpec {}
impl GroupedPlanAggregateFamily {
#[must_use]
pub(in crate::db) fn from_grouped_aggregates(aggregates: &[GroupAggregateSpec]) -> Self {
if matches!(aggregates, [aggregate] if aggregate.identity().is_count_rows_only()) {
return Self::CountRowsOnly;
}
if aggregates.iter().all(|aggregate| {
aggregate
.kind()
.grouped_plan_family(aggregate.target_field().is_some())
== Self::FieldTargetRows
}) {
return Self::FieldTargetRows;
}
Self::GenericRows
}
}
#[derive(Clone, Debug)]
pub(crate) struct FieldSlot {
pub(in crate::db) index: usize,
pub(in crate::db) field: String,
pub(in crate::db) kind: Option<FieldKind>,
}
impl PartialEq for FieldSlot {
fn eq(&self, other: &Self) -> bool {
self.index == other.index && self.field == other.field
}
}
impl Eq for FieldSlot {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct GroupedExecutionConfig {
pub(in crate::db) max_groups: u64,
pub(in crate::db) max_group_bytes: u64,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct GroupSpec {
pub(in crate::db) group_fields: Vec<FieldSlot>,
pub(in crate::db) aggregates: Vec<GroupAggregateSpec>,
pub(in crate::db) execution: GroupedExecutionConfig,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct ScalarPlan {
pub(in crate::db) mode: QueryMode,
pub(in crate::db) filter_expr: Option<Expr>,
pub(in crate::db) predicate_covers_filter_expr: bool,
pub(in crate::db) predicate: Option<Predicate>,
pub(in crate::db) order: Option<OrderSpec>,
pub(in crate::db) distinct: bool,
pub(in crate::db) delete_limit: Option<DeleteLimitSpec>,
pub(in crate::db) page: Option<PageSpec>,
pub(in crate::db) consistency: MissingRowPolicy,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct GroupPlan {
pub(in crate::db) scalar: ScalarPlan,
pub(in crate::db) group: GroupSpec,
pub(in crate::db) having_expr: Option<Expr>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) enum LogicalPlan {
Scalar(ScalarPlan),
Grouped(GroupPlan),
}