1use crate::{
7 db::{
8 cursor::ContinuationSignature,
9 direction::Direction,
10 predicate::{MissingRowPolicy, Predicate},
11 query::{
12 builder::scalar_projection::render_scalar_projection_expr_plan_label,
13 plan::{
14 expr::{Expr, FieldId, normalize_bool_expr},
15 order_contract::DeterministicSecondaryOrderContract,
16 semantics::LogicalPushdownEligibility,
17 },
18 },
19 schema::AcceptedFieldKind,
20 },
21 model::field::FieldKind,
22};
23
24#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub enum QueryMode {
34 Load(LoadSpec),
35 Delete(DeleteSpec),
36}
37
38#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
45pub struct LoadSpec {
46 pub(in crate::db) limit: Option<u32>,
47 pub(in crate::db) offset: u32,
48}
49
50impl LoadSpec {
51 #[must_use]
53 pub const fn limit(&self) -> Option<u32> {
54 self.limit
55 }
56
57 #[must_use]
59 pub const fn offset(&self) -> u32 {
60 self.offset
61 }
62}
63
64#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
72pub struct DeleteSpec {
73 pub(in crate::db) limit: Option<u32>,
74 pub(in crate::db) offset: u32,
75}
76
77impl DeleteSpec {
78 #[must_use]
80 pub const fn limit(&self) -> Option<u32> {
81 self.limit
82 }
83
84 #[must_use]
86 pub const fn offset(&self) -> u32 {
87 self.offset
88 }
89}
90
91#[derive(Clone, Copy, Debug, Eq, PartialEq)]
96pub enum OrderDirection {
97 Asc,
98 Desc,
99}
100
101#[derive(Clone, Eq, PartialEq)]
111pub(in crate::db) struct OrderTerm {
112 pub(in crate::db) expr: Expr,
113 pub(in crate::db) direction: OrderDirection,
114}
115
116impl OrderTerm {
117 #[must_use]
119 pub(in crate::db) const fn new(expr: Expr, direction: OrderDirection) -> Self {
120 Self { expr, direction }
121 }
122
123 #[must_use]
125 pub(in crate::db) fn field(field: impl Into<String>, direction: OrderDirection) -> Self {
126 Self::new(Expr::Field(FieldId::new(field.into())), direction)
127 }
128
129 #[must_use]
131 pub(in crate::db) const fn expr(&self) -> &Expr {
132 &self.expr
133 }
134
135 #[must_use]
137 pub(in crate::db) const fn direct_field(&self) -> Option<&str> {
138 let Expr::Field(field) = &self.expr else {
139 return None;
140 };
141
142 Some(field.as_str())
143 }
144
145 #[must_use]
147 pub(in crate::db) fn rendered_label(&self) -> String {
148 render_scalar_projection_expr_plan_label(&self.expr)
149 }
150
151 #[must_use]
153 pub(in crate::db) const fn direction(&self) -> OrderDirection {
154 self.direction
155 }
156}
157
158impl std::fmt::Debug for OrderTerm {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 f.debug_struct("OrderTerm")
161 .field("label", &self.rendered_label())
162 .field("expr", &self.expr)
163 .field("direction", &self.direction)
164 .finish()
165 }
166}
167
168impl PartialEq<(String, OrderDirection)> for OrderTerm {
169 fn eq(&self, other: &(String, OrderDirection)) -> bool {
170 self.rendered_label() == other.0 && self.direction == other.1
171 }
172}
173
174impl PartialEq<OrderTerm> for (String, OrderDirection) {
175 fn eq(&self, other: &OrderTerm) -> bool {
176 self.0 == other.rendered_label() && self.1 == other.direction
177 }
178}
179
180#[must_use]
183pub(in crate::db) fn render_scalar_filter_expr_plan_label(expr: &Expr) -> String {
184 render_scalar_projection_expr_plan_label(&normalize_bool_expr(expr.clone()))
185}
186
187#[derive(Clone, Debug, Eq, PartialEq)]
194pub(in crate::db) struct OrderSpec {
195 pub(in crate::db) fields: Vec<OrderTerm>,
196}
197
198#[derive(Clone, Copy, Debug, Eq, PartialEq)]
204pub(in crate::db) struct DeleteLimitSpec {
205 pub(in crate::db) limit: Option<u32>,
206 pub(in crate::db) offset: u32,
207}
208
209#[derive(Clone, Copy, Debug, Eq, PartialEq)]
218pub(in crate::db) enum DistinctExecutionStrategy {
219 None,
220 PreOrdered,
221 HashMaterialize,
222}
223
224impl DistinctExecutionStrategy {
225 #[must_use]
227 pub(in crate::db) const fn is_enabled(self) -> bool {
228 !matches!(self, Self::None)
229 }
230}
231
232#[derive(Clone, Debug, Eq, PartialEq)]
241pub(in crate::db) struct PlannerRouteProfile {
242 continuation_policy: ContinuationPolicy,
243 logical_pushdown_eligibility: LogicalPushdownEligibility,
244 secondary_order_contract: Option<DeterministicSecondaryOrderContract>,
245}
246
247impl PlannerRouteProfile {
248 #[must_use]
250 pub(in crate::db) const fn new(
251 continuation_policy: ContinuationPolicy,
252 logical_pushdown_eligibility: LogicalPushdownEligibility,
253 secondary_order_contract: Option<DeterministicSecondaryOrderContract>,
254 ) -> Self {
255 Self {
256 continuation_policy,
257 logical_pushdown_eligibility,
258 secondary_order_contract,
259 }
260 }
261
262 #[must_use]
265 pub(in crate::db) const fn seeded_unfinalized(is_grouped: bool) -> Self {
266 Self {
267 continuation_policy: ContinuationPolicy::new(true, true, !is_grouped),
268 logical_pushdown_eligibility: LogicalPushdownEligibility::new(false, is_grouped, false),
269 secondary_order_contract: None,
270 }
271 }
272
273 #[must_use]
275 pub(in crate::db) const fn continuation_policy(&self) -> &ContinuationPolicy {
276 &self.continuation_policy
277 }
278
279 #[must_use]
281 pub(in crate::db) const fn logical_pushdown_eligibility(&self) -> LogicalPushdownEligibility {
282 self.logical_pushdown_eligibility
283 }
284
285 #[must_use]
287 pub(in crate::db) const fn secondary_order_contract(
288 &self,
289 ) -> Option<&DeterministicSecondaryOrderContract> {
290 self.secondary_order_contract.as_ref()
291 }
292}
293
294#[derive(Clone, Copy, Debug, Eq, PartialEq)]
303pub(in crate::db) struct ContinuationPolicy {
304 requires_anchor: bool,
305 requires_strict_advance: bool,
306 is_grouped_safe: bool,
307}
308
309impl ContinuationPolicy {
310 #[must_use]
312 pub(in crate::db) const fn new(
313 requires_anchor: bool,
314 requires_strict_advance: bool,
315 is_grouped_safe: bool,
316 ) -> Self {
317 Self {
318 requires_anchor,
319 requires_strict_advance,
320 is_grouped_safe,
321 }
322 }
323
324 #[must_use]
326 pub(in crate::db) const fn requires_anchor(self) -> bool {
327 self.requires_anchor
328 }
329
330 #[must_use]
332 pub(in crate::db) const fn requires_strict_advance(self) -> bool {
333 self.requires_strict_advance
334 }
335
336 #[must_use]
338 pub(in crate::db) const fn is_grouped_safe(self) -> bool {
339 self.is_grouped_safe
340 }
341}
342
343#[derive(Clone, Copy, Debug, Eq, PartialEq)]
352pub(in crate::db) struct ExecutionShapeSignature {
353 continuation_signature: ContinuationSignature,
354}
355
356impl ExecutionShapeSignature {
357 #[must_use]
359 pub(in crate::db) const fn new(continuation_signature: ContinuationSignature) -> Self {
360 Self {
361 continuation_signature,
362 }
363 }
364
365 #[must_use]
367 pub(in crate::db) const fn continuation_signature(self) -> ContinuationSignature {
368 self.continuation_signature
369 }
370}
371
372#[derive(Clone, Debug, Eq, PartialEq)]
378pub(in crate::db) struct PageSpec {
379 pub(in crate::db) limit: Option<u32>,
380 pub(in crate::db) offset: u32,
381}
382
383#[derive(Clone, Copy, Debug, Eq, PartialEq)]
393pub enum AggregateKind {
394 Count,
395 Sum,
396 Avg,
397 Exists,
398 Min,
399 Max,
400 First,
401 Last,
402}
403
404#[derive(Clone, Copy, Debug, Eq, PartialEq)]
414pub(in crate::db) enum GlobalDistinctAggregateKind {
415 Count,
416 Sum,
417 Avg,
418}
419
420impl GlobalDistinctAggregateKind {}
421
422#[derive(Clone, Copy, Debug, Eq, PartialEq)]
433pub(in crate::db) enum GroupedPlanAggregateFamily {
434 CountRowsOnly,
435 FieldTargetRows,
436 GenericRows,
437}
438
439impl GroupedPlanAggregateFamily {
440 #[must_use]
442 pub(in crate::db) const fn code(self) -> &'static str {
443 match self {
444 Self::CountRowsOnly => "count_rows_only",
445 Self::FieldTargetRows => "field_target_rows",
446 Self::GenericRows => "generic_rows",
447 }
448 }
449}
450
451impl AggregateKind {
452 #[must_use]
454 pub(in crate::db) const fn canonical_label(self) -> &'static str {
455 match self {
456 Self::Count => "COUNT",
457 Self::Sum => "SUM",
458 Self::Avg => "AVG",
459 Self::Exists => "EXISTS",
460 Self::First => "FIRST",
461 Self::Last => "LAST",
462 Self::Min => "MIN",
463 Self::Max => "MAX",
464 }
465 }
466
467 #[must_use]
469 pub(in crate::db) const fn is_count(self) -> bool {
470 matches!(self, Self::Count)
471 }
472
473 #[must_use]
475 pub(in crate::db) const fn is_sum(self) -> bool {
476 matches!(self, Self::Sum | Self::Avg)
477 }
478
479 #[must_use]
481 pub(in crate::db) const fn is_extrema(self) -> bool {
482 matches!(self, Self::Min | Self::Max)
483 }
484
485 #[must_use]
487 pub(in crate::db) const fn supports_field_target_v1(self) -> bool {
488 matches!(
489 self,
490 Self::Count | Self::Sum | Self::Avg | Self::Min | Self::Max
491 )
492 }
493
494 #[must_use]
496 pub(in crate::db) const fn requires_decoded_id(self) -> bool {
497 !matches!(self, Self::Count | Self::Sum | Self::Avg | Self::Exists)
498 }
499
500 #[must_use]
502 pub(in crate::db) const fn supports_grouped_distinct_v1(self) -> bool {
503 matches!(self, Self::Count | Self::Sum | Self::Avg)
504 }
505
506 #[must_use]
509 pub(in crate::db::query) const fn fingerprint_tag(self) -> u8 {
510 match self {
511 Self::Count => 0x01,
512 Self::Sum => 0x02,
513 Self::Exists => 0x03,
514 Self::Min => 0x04,
515 Self::Max => 0x05,
516 Self::First => 0x06,
517 Self::Last => 0x07,
518 Self::Avg => 0x08,
519 }
520 }
521
522 #[must_use]
524 pub(in crate::db) const fn global_distinct_kind(self) -> Option<GlobalDistinctAggregateKind> {
525 match self {
526 Self::Count => Some(GlobalDistinctAggregateKind::Count),
527 Self::Sum => Some(GlobalDistinctAggregateKind::Sum),
528 Self::Avg => Some(GlobalDistinctAggregateKind::Avg),
529 Self::Exists | Self::Min | Self::Max | Self::First | Self::Last => None,
530 }
531 }
532
533 #[must_use]
535 pub(in crate::db) const fn supports_global_distinct_without_group_keys(self) -> bool {
536 self.global_distinct_kind().is_some()
537 }
538
539 #[must_use]
541 pub(in crate::db) const fn grouped_plan_family(
542 self,
543 has_target_field: bool,
544 ) -> GroupedPlanAggregateFamily {
545 if has_target_field && self.supports_field_target_v1() {
546 GroupedPlanAggregateFamily::FieldTargetRows
547 } else {
548 GroupedPlanAggregateFamily::GenericRows
549 }
550 }
551
552 #[must_use]
554 pub(in crate::db) const fn supports_grouped_streaming_v1(
555 self,
556 has_target_field: bool,
557 distinct: bool,
558 ) -> bool {
559 if self.supports_field_target_v1() {
560 return !distinct && (self.is_count() || has_target_field);
561 }
562
563 !has_target_field && (!distinct || self.supports_grouped_distinct_v1())
564 }
565
566 #[must_use]
568 pub(in crate::db) const fn extrema_direction(self) -> Option<Direction> {
569 match self {
570 Self::Min => Some(Direction::Asc),
571 Self::Max => Some(Direction::Desc),
572 Self::Count | Self::Sum | Self::Avg | Self::Exists | Self::First | Self::Last => None,
573 }
574 }
575
576 #[must_use]
578 pub(in crate::db) const fn materialized_fold_direction(self) -> Direction {
579 match self {
580 Self::Min => Direction::Desc,
581 Self::Count
582 | Self::Sum
583 | Self::Avg
584 | Self::Exists
585 | Self::Max
586 | Self::First
587 | Self::Last => Direction::Asc,
588 }
589 }
590
591 #[must_use]
593 pub(in crate::db) const fn supports_bounded_probe_hint(self) -> bool {
594 !self.is_count() && !self.is_sum()
595 }
596
597 #[must_use]
599 pub(in crate::db) fn bounded_probe_fetch_hint(
600 self,
601 direction: Direction,
602 offset: usize,
603 page_limit: Option<usize>,
604 ) -> Option<usize> {
605 match self {
606 Self::Exists | Self::First => Some(offset.saturating_add(1)),
607 Self::Min if direction == Direction::Asc => Some(offset.saturating_add(1)),
608 Self::Max if direction == Direction::Desc => Some(offset.saturating_add(1)),
609 Self::Last => page_limit.map(|limit| offset.saturating_add(limit)),
610 Self::Count | Self::Sum | Self::Avg | Self::Min | Self::Max => None,
611 }
612 }
613
614 #[must_use]
616 pub(in crate::db) const fn explain_projection_mode_label(
617 self,
618 has_projected_field: bool,
619 covering_projection: bool,
620 ) -> &'static str {
621 if has_projected_field {
622 if covering_projection {
623 "field_idx"
624 } else {
625 "field_mat"
626 }
627 } else if matches!(self, Self::Min | Self::Max | Self::First | Self::Last) {
628 "entity_term"
629 } else {
630 "scalar_agg"
631 }
632 }
633
634 #[must_use]
636 pub(in crate::db) const fn supports_covering_existing_rows_terminal(self) -> bool {
637 matches!(self, Self::Count | Self::Exists)
638 }
639}
640
641#[derive(Clone, Debug)]
652pub(in crate::db) struct GroupAggregateSpec {
653 pub(in crate::db) kind: AggregateKind,
654 pub(in crate::db) input_expr: Option<Box<Expr>>,
655 pub(in crate::db) filter_expr: Option<Box<Expr>>,
656 pub(in crate::db) distinct: bool,
657}
658
659impl PartialEq for GroupAggregateSpec {
660 fn eq(&self, other: &Self) -> bool {
661 self.semantic_key() == other.semantic_key()
662 }
663}
664
665impl Eq for GroupAggregateSpec {}
666
667impl GroupedPlanAggregateFamily {
668 #[must_use]
670 pub(in crate::db) fn from_grouped_aggregates(aggregates: &[GroupAggregateSpec]) -> Self {
671 if matches!(aggregates, [aggregate] if aggregate.identity().is_count_rows_only()) {
672 return Self::CountRowsOnly;
673 }
674
675 if aggregates.iter().all(|aggregate| {
676 aggregate
677 .kind()
678 .grouped_plan_family(aggregate.target_field().is_some())
679 == Self::FieldTargetRows
680 }) {
681 return Self::FieldTargetRows;
682 }
683
684 Self::GenericRows
685 }
686}
687
688#[derive(Clone, Debug)]
699pub(in crate::db::query::plan) enum FieldSlotAuthority {
700 Unresolved,
701 ModelOnly(FieldKind),
702 Accepted(AcceptedFieldKind),
703}
704
705#[derive(Clone, Debug)]
706pub(crate) struct FieldSlot {
707 pub(in crate::db) index: usize,
708 pub(in crate::db) field: String,
709 pub(in crate::db::query::plan) authority: FieldSlotAuthority,
710}
711
712impl PartialEq for FieldSlot {
713 fn eq(&self, other: &Self) -> bool {
714 self.index == other.index && self.field == other.field
715 }
716}
717
718impl Eq for FieldSlot {}
719
720#[derive(Clone, Copy, Debug, Eq, PartialEq)]
729pub(in crate::db) struct GroupedExecutionConfig {
730 pub(in crate::db) max_groups: u64,
731 pub(in crate::db) max_group_bytes: u64,
732}
733
734#[derive(Clone, Debug, Eq, PartialEq)]
743pub(in crate::db) struct GroupSpec {
744 pub(in crate::db) group_fields: Vec<FieldSlot>,
745 pub(in crate::db) aggregates: Vec<GroupAggregateSpec>,
746 pub(in crate::db) execution: GroupedExecutionConfig,
747}
748
749#[derive(Clone, Debug, Eq, PartialEq)]
770pub(in crate::db) struct ScalarPlan {
771 pub(in crate::db) mode: QueryMode,
773
774 pub(in crate::db) filter_expr: Option<Expr>,
776
777 pub(in crate::db) predicate_covers_filter_expr: bool,
779
780 pub(in crate::db) predicate: Option<Predicate>,
782
783 pub(in crate::db) order: Option<OrderSpec>,
785
786 pub(in crate::db) distinct: bool,
788
789 pub(in crate::db) delete_limit: Option<DeleteLimitSpec>,
791
792 pub(in crate::db) page: Option<PageSpec>,
794
795 pub(in crate::db) consistency: MissingRowPolicy,
797}
798
799#[derive(Clone, Debug, Eq, PartialEq)]
807pub(in crate::db) struct GroupPlan {
808 pub(in crate::db) scalar: ScalarPlan,
809 pub(in crate::db) group: GroupSpec,
810 pub(in crate::db) having_expr: Option<Expr>,
811}
812
813#[derive(Clone, Debug, Eq, PartialEq)]
823pub(in crate::db) enum LogicalPlan {
824 Scalar(ScalarPlan),
825 Grouped(GroupPlan),
826}