1use crate::db::{
7 cursor::ContinuationSignature,
8 direction::Direction,
9 predicate::{MissingRowPolicy, Predicate},
10 query::{
11 builder::scalar_projection::render_scalar_projection_expr_plan_label,
12 plan::{
13 aggregate_shape::AggregateShape,
14 expr::{Expr, FieldId},
15 order_contract::DeterministicSecondaryOrderContract,
16 semantics::LogicalPushdownEligibility,
17 },
18 },
19 schema::AcceptedFieldKind,
20};
21use std::sync::Arc;
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum QueryMode {
33 Load(LoadSpec),
34 Delete(DeleteSpec),
35}
36
37#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
44pub struct LoadSpec {
45 pub(in crate::db) limit: Option<u32>,
46 pub(in crate::db) offset: u32,
47}
48
49impl LoadSpec {
50 #[must_use]
52 pub const fn limit(&self) -> Option<u32> {
53 self.limit
54 }
55
56 #[must_use]
58 pub const fn offset(&self) -> u32 {
59 self.offset
60 }
61}
62
63#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
71pub struct DeleteSpec {
72 pub(in crate::db) limit: Option<u32>,
73 pub(in crate::db) offset: u32,
74}
75
76impl DeleteSpec {
77 #[must_use]
79 pub const fn limit(&self) -> Option<u32> {
80 self.limit
81 }
82
83 #[must_use]
85 pub const fn offset(&self) -> u32 {
86 self.offset
87 }
88}
89
90#[derive(Clone, Copy, Debug, Eq, PartialEq)]
95pub enum OrderDirection {
96 Asc,
97 Desc,
98}
99
100#[derive(Clone, Eq, PartialEq)]
110pub(in crate::db) struct OrderTerm {
111 pub(in crate::db) expr: Expr,
112 pub(in crate::db) direction: OrderDirection,
113}
114
115impl OrderTerm {
116 #[must_use]
118 pub(in crate::db) const fn new(expr: Expr, direction: OrderDirection) -> Self {
119 Self { expr, direction }
120 }
121
122 #[must_use]
124 pub(in crate::db) fn field(field: impl Into<String>, direction: OrderDirection) -> Self {
125 Self::new(Expr::Field(FieldId::new(field.into())), direction)
126 }
127
128 #[must_use]
130 pub(in crate::db) const fn expr(&self) -> &Expr {
131 &self.expr
132 }
133
134 #[must_use]
136 pub(in crate::db) const fn direct_field(&self) -> Option<&str> {
137 let Expr::Field(field) = &self.expr else {
138 return None;
139 };
140
141 Some(field.as_str())
142 }
143
144 #[must_use]
146 pub(in crate::db) fn rendered_label(&self) -> String {
147 render_scalar_projection_expr_plan_label(&self.expr)
148 }
149
150 #[must_use]
152 pub(in crate::db) const fn direction(&self) -> OrderDirection {
153 self.direction
154 }
155}
156
157impl std::fmt::Debug for OrderTerm {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 f.debug_struct("OrderTerm")
160 .field("label", &self.rendered_label())
161 .field("expr", &self.expr)
162 .field("direction", &self.direction)
163 .finish()
164 }
165}
166
167impl PartialEq<(String, OrderDirection)> for OrderTerm {
168 fn eq(&self, other: &(String, OrderDirection)) -> bool {
169 self.rendered_label() == other.0 && self.direction == other.1
170 }
171}
172
173impl PartialEq<OrderTerm> for (String, OrderDirection) {
174 fn eq(&self, other: &OrderTerm) -> bool {
175 self.0 == other.rendered_label() && self.1 == other.direction
176 }
177}
178
179#[cfg(any(feature = "sql", test))]
182#[must_use]
183pub(in crate::db) fn render_scalar_filter_expr_plan_label(expr: &Expr) -> String {
184 render_scalar_projection_expr_plan_label(expr)
187}
188
189#[derive(Clone, Debug, Eq, PartialEq)]
196pub(in crate::db) struct OrderSpec {
197 pub(in crate::db) fields: Vec<OrderTerm>,
198}
199
200#[derive(Clone, Copy, Debug, Eq, PartialEq)]
206pub(in crate::db) struct DeleteLimitSpec {
207 pub(in crate::db) limit: Option<u32>,
208 pub(in crate::db) offset: u32,
209}
210
211#[derive(Clone, Copy, Debug, Eq, PartialEq)]
220pub(in crate::db) enum DistinctExecutionStrategy {
221 None,
222 PreOrdered,
223 HashMaterialize,
224}
225
226#[derive(Clone, Debug, Eq, PartialEq)]
235pub(in crate::db) struct PlannerRouteProfile {
236 continuation_policy: ContinuationPolicy,
237 logical_pushdown_eligibility: LogicalPushdownEligibility,
238 secondary_order_contract: Option<DeterministicSecondaryOrderContract>,
239}
240
241impl PlannerRouteProfile {
242 #[must_use]
244 pub(in crate::db) const fn new(
245 continuation_policy: ContinuationPolicy,
246 logical_pushdown_eligibility: LogicalPushdownEligibility,
247 secondary_order_contract: Option<DeterministicSecondaryOrderContract>,
248 ) -> Self {
249 Self {
250 continuation_policy,
251 logical_pushdown_eligibility,
252 secondary_order_contract,
253 }
254 }
255
256 #[must_use]
259 pub(in crate::db) const fn seeded_unfinalized(is_grouped: bool) -> Self {
260 Self {
261 continuation_policy: ContinuationPolicy::new(true, true, !is_grouped),
262 logical_pushdown_eligibility: LogicalPushdownEligibility::new(false, is_grouped, false),
263 secondary_order_contract: None,
264 }
265 }
266
267 #[must_use]
269 pub(in crate::db) const fn continuation_policy(&self) -> &ContinuationPolicy {
270 &self.continuation_policy
271 }
272
273 #[must_use]
275 pub(in crate::db) const fn logical_pushdown_eligibility(&self) -> LogicalPushdownEligibility {
276 self.logical_pushdown_eligibility
277 }
278
279 #[must_use]
281 pub(in crate::db) const fn secondary_order_contract(
282 &self,
283 ) -> Option<&DeterministicSecondaryOrderContract> {
284 self.secondary_order_contract.as_ref()
285 }
286}
287
288#[derive(Clone, Copy, Debug, Eq, PartialEq)]
297pub(in crate::db) struct ContinuationPolicy {
298 requires_anchor: bool,
299 requires_strict_advance: bool,
300 is_grouped_safe: bool,
301}
302
303impl ContinuationPolicy {
304 #[must_use]
306 pub(in crate::db) const fn new(
307 requires_anchor: bool,
308 requires_strict_advance: bool,
309 is_grouped_safe: bool,
310 ) -> Self {
311 Self {
312 requires_anchor,
313 requires_strict_advance,
314 is_grouped_safe,
315 }
316 }
317
318 #[must_use]
320 pub(in crate::db) const fn requires_anchor(self) -> bool {
321 self.requires_anchor
322 }
323
324 #[must_use]
326 pub(in crate::db) const fn requires_strict_advance(self) -> bool {
327 self.requires_strict_advance
328 }
329
330 #[must_use]
332 pub(in crate::db) const fn is_grouped_safe(self) -> bool {
333 self.is_grouped_safe
334 }
335}
336
337#[derive(Clone, Copy, Debug, Eq, PartialEq)]
346pub(in crate::db) struct ExecutionShapeSignature {
347 continuation_signature: ContinuationSignature,
348}
349
350impl ExecutionShapeSignature {
351 #[must_use]
353 pub(in crate::db) const fn new(continuation_signature: ContinuationSignature) -> Self {
354 Self {
355 continuation_signature,
356 }
357 }
358
359 #[must_use]
361 pub(in crate::db) const fn continuation_signature(self) -> ContinuationSignature {
362 self.continuation_signature
363 }
364}
365
366#[derive(Clone, Debug, Eq, PartialEq)]
372pub(in crate::db) struct PageSpec {
373 pub(in crate::db) limit: Option<u32>,
374 pub(in crate::db) offset: u32,
375}
376
377#[derive(Clone, Copy, Debug, Eq, PartialEq)]
387pub enum AggregateKind {
388 Count,
389 Sum,
390 Avg,
391 Exists,
392 Min,
393 Max,
394 First,
395 Last,
396}
397
398#[derive(Clone, Copy, Debug, Eq, PartialEq)]
408pub(in crate::db) enum GlobalDistinctAggregateKind {
409 Count,
410 Sum,
411 Avg,
412}
413
414#[derive(Clone, Copy, Debug, Eq, PartialEq)]
425pub(in crate::db) enum GroupedPlanAggregateFamily {
426 CountRowsOnly,
427 FieldTargetRows,
428 GenericRows,
429}
430
431impl GroupedPlanAggregateFamily {
432 #[must_use]
434 pub(in crate::db) const fn code(self) -> &'static str {
435 match self {
436 Self::CountRowsOnly => "count_rows_only",
437 Self::FieldTargetRows => "field_target_rows",
438 Self::GenericRows => "generic_rows",
439 }
440 }
441}
442
443impl AggregateKind {
444 #[must_use]
446 pub(in crate::db) const fn canonical_label(self) -> &'static str {
447 match self {
448 Self::Count => "COUNT",
449 Self::Sum => "SUM",
450 Self::Avg => "AVG",
451 Self::Exists => "EXISTS",
452 Self::First => "FIRST",
453 Self::Last => "LAST",
454 Self::Min => "MIN",
455 Self::Max => "MAX",
456 }
457 }
458
459 #[must_use]
461 pub(in crate::db) const fn is_count(self) -> bool {
462 matches!(self, Self::Count)
463 }
464
465 #[must_use]
467 pub(in crate::db) const fn is_sum(self) -> bool {
468 matches!(self, Self::Sum | Self::Avg)
469 }
470
471 #[must_use]
473 pub(in crate::db) const fn is_extrema(self) -> bool {
474 matches!(self, Self::Min | Self::Max)
475 }
476
477 #[must_use]
479 pub(in crate::db) const fn supports_field_target(self) -> bool {
480 matches!(
481 self,
482 Self::Count | Self::Sum | Self::Avg | Self::Min | Self::Max
483 )
484 }
485
486 #[must_use]
488 pub(in crate::db) const fn requires_decoded_id(self) -> bool {
489 !matches!(self, Self::Count | Self::Sum | Self::Avg | Self::Exists)
490 }
491
492 #[must_use]
494 pub(in crate::db) const fn supports_grouped_distinct(self) -> bool {
495 matches!(self, Self::Count | Self::Sum | Self::Avg)
496 }
497
498 #[must_use]
501 pub(in crate::db::query) const fn fingerprint_tag(self) -> u8 {
502 match self {
503 Self::Count => 0x01,
504 Self::Sum => 0x02,
505 Self::Exists => 0x03,
506 Self::Min => 0x04,
507 Self::Max => 0x05,
508 Self::First => 0x06,
509 Self::Last => 0x07,
510 Self::Avg => 0x08,
511 }
512 }
513
514 #[must_use]
516 pub(in crate::db) const fn global_distinct_kind(self) -> Option<GlobalDistinctAggregateKind> {
517 match self {
518 Self::Count => Some(GlobalDistinctAggregateKind::Count),
519 Self::Sum => Some(GlobalDistinctAggregateKind::Sum),
520 Self::Avg => Some(GlobalDistinctAggregateKind::Avg),
521 Self::Exists | Self::Min | Self::Max | Self::First | Self::Last => None,
522 }
523 }
524
525 #[must_use]
527 pub(in crate::db) const fn supports_global_distinct_without_group_keys(self) -> bool {
528 self.global_distinct_kind().is_some()
529 }
530
531 #[must_use]
533 pub(in crate::db) const fn grouped_plan_family(
534 self,
535 has_target_field: bool,
536 ) -> GroupedPlanAggregateFamily {
537 if has_target_field && self.supports_field_target() {
538 GroupedPlanAggregateFamily::FieldTargetRows
539 } else {
540 GroupedPlanAggregateFamily::GenericRows
541 }
542 }
543
544 #[must_use]
546 pub(in crate::db) const fn supports_grouped_streaming(
547 self,
548 has_target_field: bool,
549 distinct: bool,
550 ) -> bool {
551 if self.supports_field_target() {
552 return !distinct && (self.is_count() || has_target_field);
553 }
554
555 !has_target_field && (!distinct || self.supports_grouped_distinct())
556 }
557
558 #[must_use]
560 pub(in crate::db) const fn extrema_direction(self) -> Option<Direction> {
561 match self {
562 Self::Min => Some(Direction::Asc),
563 Self::Max => Some(Direction::Desc),
564 Self::Count | Self::Sum | Self::Avg | Self::Exists | Self::First | Self::Last => None,
565 }
566 }
567
568 #[must_use]
570 pub(in crate::db) const fn materialized_fold_direction(self) -> Direction {
571 match self {
572 Self::Min => Direction::Desc,
573 Self::Count
574 | Self::Sum
575 | Self::Avg
576 | Self::Exists
577 | Self::Max
578 | Self::First
579 | Self::Last => Direction::Asc,
580 }
581 }
582
583 #[must_use]
585 pub(in crate::db) const fn supports_bounded_probe_hint(self) -> bool {
586 !self.is_count() && !self.is_sum()
587 }
588
589 #[must_use]
591 pub(in crate::db) fn bounded_probe_fetch_hint(
592 self,
593 direction: Direction,
594 offset: usize,
595 page_limit: Option<usize>,
596 ) -> Option<usize> {
597 match self {
598 Self::Exists | Self::First => Some(offset.saturating_add(1)),
599 Self::Min if direction == Direction::Asc => Some(offset.saturating_add(1)),
600 Self::Max if direction == Direction::Desc => Some(offset.saturating_add(1)),
601 Self::Last => page_limit.map(|limit| offset.saturating_add(limit)),
602 Self::Count | Self::Sum | Self::Avg | Self::Min | Self::Max => None,
603 }
604 }
605
606 #[must_use]
608 #[cfg(feature = "sql")]
609 pub(in crate::db) const fn explain_projection_mode_label(
610 self,
611 has_projected_field: bool,
612 covering_projection: bool,
613 ) -> &'static str {
614 if has_projected_field {
615 if covering_projection {
616 "field_idx"
617 } else {
618 "field_mat"
619 }
620 } else if matches!(self, Self::Min | Self::Max | Self::First | Self::Last) {
621 "entity_term"
622 } else {
623 "scalar_agg"
624 }
625 }
626
627 #[must_use]
629 #[cfg(feature = "sql")]
630 pub(in crate::db) const fn supports_covering_existing_rows_terminal(self) -> bool {
631 matches!(self, Self::Count | Self::Exists)
632 }
633}
634
635#[derive(Clone, Debug)]
646pub(in crate::db) struct GroupAggregateSpec {
647 shape: AggregateShape,
648}
649
650impl GroupAggregateSpec {
651 #[must_use]
653 pub(in crate::db) const fn from_shape(shape: AggregateShape) -> Self {
654 Self { shape }
655 }
656
657 #[must_use]
659 pub(in crate::db) const fn shape(&self) -> &AggregateShape {
660 &self.shape
661 }
662}
663
664impl PartialEq for GroupAggregateSpec {
665 fn eq(&self, other: &Self) -> bool {
666 self.semantic_key() == other.semantic_key()
667 }
668}
669
670impl Eq for GroupAggregateSpec {}
671
672impl GroupedPlanAggregateFamily {
673 pub(in crate::db) fn try_from_grouped_aggregates<E>(
675 aggregates: &[GroupAggregateSpec],
676 observe: &mut impl FnMut(u64) -> Result<(), E>,
677 ) -> Result<Self, E> {
678 observe(1)?;
679 if matches!(aggregates, [aggregate] if aggregate.is_count_rows_only()) {
680 return Ok(Self::CountRowsOnly);
681 }
682
683 for aggregate in aggregates {
684 observe(1)?;
685 if aggregate
686 .kind()
687 .grouped_plan_family(aggregate.target_field().is_some())
688 != Self::FieldTargetRows
689 {
690 return Ok(Self::GenericRows);
691 }
692 }
693
694 Ok(Self::FieldTargetRows)
695 }
696}
697
698#[derive(Clone, Debug)]
709pub(in crate::db::query::plan) enum FieldSlotAuthority {
710 Unresolved,
711 Accepted(Arc<AcceptedFieldKind>),
712}
713
714#[derive(Clone, Debug)]
715pub(crate) struct FieldSlot {
716 pub(in crate::db) index: usize,
717 pub(in crate::db) field: Arc<str>,
718 pub(in crate::db::query::plan) authority: FieldSlotAuthority,
719}
720
721impl PartialEq for FieldSlot {
722 fn eq(&self, other: &Self) -> bool {
723 self.index == other.index && self.field == other.field
724 }
725}
726
727impl Eq for FieldSlot {}
728
729#[derive(Clone, Copy, Debug, Eq, PartialEq)]
738pub(in crate::db) struct GroupedExecutionConfig {
739 pub(in crate::db) max_groups: u64,
740 pub(in crate::db) max_group_bytes: u64,
741}
742
743#[derive(Clone, Debug, Eq, PartialEq)]
752pub(in crate::db) struct GroupSpec {
753 pub(in crate::db) group_fields: crate::db::query::plan::GroupFieldSet,
754 pub(in crate::db) aggregates: Vec<GroupAggregateSpec>,
755 pub(in crate::db) execution: GroupedExecutionConfig,
756}
757
758#[derive(Clone, Debug, Eq, PartialEq)]
779pub(in crate::db) struct ScalarPlan {
780 pub(in crate::db) mode: QueryMode,
782
783 pub(in crate::db) filter_expr: Option<Expr>,
785
786 pub(in crate::db) predicate_covers_filter_expr: bool,
788
789 pub(in crate::db) predicate: Option<Predicate>,
791
792 pub(in crate::db) order: Option<OrderSpec>,
794
795 pub(in crate::db) distinct: bool,
797
798 pub(in crate::db) delete_limit: Option<DeleteLimitSpec>,
800
801 pub(in crate::db) page: Option<PageSpec>,
803
804 pub(in crate::db) consistency: MissingRowPolicy,
806}
807
808#[derive(Clone, Debug, Eq, PartialEq)]
816pub(in crate::db) struct GroupPlan {
817 pub(in crate::db) scalar: ScalarPlan,
818 pub(in crate::db) group: GroupSpec,
819 pub(in crate::db) having_expr: Option<Expr>,
820}
821
822#[derive(Clone, Debug, Eq, PartialEq)]
832pub(in crate::db) enum LogicalPlan {
833 Scalar(ScalarPlan),
834 Grouped(GroupPlan),
835}
836
837crate::retained::retained_copy!(AggregateKind);
839crate::retained::retained_copy!(ContinuationPolicy);
840crate::retained::retained_copy!(DeleteLimitSpec);
841crate::retained::retained_copy!(ExecutionShapeSignature);
842crate::retained::retained_fields!(FieldSlot {
843Self{index,field,authority} => [index,field,authority],
844});
845crate::retained::retained_fields!(FieldSlotAuthority {
846Self::Unresolved => [],
847Self::Accepted(field_0) => [field_0],
848});
849crate::retained::retained_fields!(GroupAggregateSpec {
850Self{shape} => [shape],
851});
852crate::retained::retained_fields!(GroupPlan {
853Self{scalar,group,having_expr} => [scalar,group,having_expr],
854});
855crate::retained::retained_fields!(GroupSpec {
856Self{group_fields,aggregates,execution} => [group_fields,aggregates,execution],
857});
858crate::retained::retained_copy!(GroupedExecutionConfig);
859crate::retained::retained_fields!(LogicalPlan {
860Self::Scalar(field_0) => [field_0],
861Self::Grouped(field_0) => [field_0],
862});
863crate::retained::retained_copy!(OrderDirection);
864crate::retained::retained_fields!(OrderSpec {
865Self{fields} => [fields],
866});
867crate::retained::retained_fields!(OrderTerm {
868Self{expr,direction} => [expr,direction],
869});
870crate::retained::retained_fields!(PageSpec {
871Self{limit,offset} => [limit,offset],
872});
873crate::retained::retained_fields!(PlannerRouteProfile {
874Self{continuation_policy,logical_pushdown_eligibility,secondary_order_contract} => [continuation_policy,logical_pushdown_eligibility,secondary_order_contract],
875});
876crate::retained::retained_copy!(QueryMode);
877crate::retained::retained_fields!(ScalarPlan {
878Self{mode,filter_expr,predicate_covers_filter_expr,predicate,order,distinct,delete_limit,page,consistency} => [mode,filter_expr,predicate_covers_filter_expr,predicate,order,distinct,delete_limit,page,consistency],
879});