1use crate::db::predicate::MissingRowPolicy;
7use crate::{
8 db::{
9 access::{AccessPlan, ExecutableAccessPlan, SemanticIndexKeyItemRef},
10 predicate::{IndexCompileTarget, IndexCompileTargetKind, Predicate, PredicateProgram},
11 query::plan::{
12 AccessPlannedQuery, ContinuationPolicy, DistinctExecutionStrategy,
13 EffectiveRuntimeFilterProgram, ExecutionShapeSignature, GroupPlan,
14 GroupedAggregateExecutionSpec, GroupedDistinctExecutionStrategy, GroupedPlanStrategy,
15 LogicalPlan, PlannerRouteProfile, PredicatePushdownDiagnostics, QueryMode,
16 ResidualFilterContract, ResidualFilterShape, ResolvedOrder, ResolvedOrderField,
17 ResolvedOrderValueSource, ScalarPlan, StaticExecutionPlanningContract,
18 derive_logical_pushdown_eligibility,
19 expr::{
20 CompiledExpr, Expr, ProjectionSpec, compile_scalar_projection_expr_with_schema,
21 compile_scalar_projection_plan_with_schema,
22 },
23 extend_unique_grouped_aggregate_specs_from_expr, grouped_aggregate_execution_specs,
24 grouped_aggregate_specs_from_projection_spec, grouped_cursor_policy_violation,
25 grouped_plan_strategy, lower_data_row_direct_projection_slots_with_schema,
26 lower_direct_projection_slots_with_schema, lower_projection_identity,
27 lower_projection_intent_with_schema, residual_query_predicate_after_access_path_bounds,
28 residual_query_predicate_after_filtered_access_contract,
29 resolved_grouped_distinct_execution_strategy_with_schema_info,
30 },
31 schema::SchemaInfo,
32 },
33 error::InternalError,
34};
35
36impl QueryMode {
37 #[must_use]
39 pub const fn is_load(&self) -> bool {
40 match self {
41 Self::Load(_) => true,
42 Self::Delete(_) => false,
43 }
44 }
45
46 #[must_use]
48 pub const fn is_delete(&self) -> bool {
49 match self {
50 Self::Delete(_) => true,
51 Self::Load(_) => false,
52 }
53 }
54}
55
56impl LogicalPlan {
57 #[must_use]
59 pub(in crate::db) const fn scalar_semantics(&self) -> &ScalarPlan {
60 match self {
61 Self::Scalar(plan) => plan,
62 Self::Grouped(plan) => &plan.scalar,
63 }
64 }
65}
66
67impl AccessPlannedQuery {
68 #[must_use]
70 pub(in crate::db) const fn scalar_plan(&self) -> &ScalarPlan {
71 self.logical.scalar_semantics()
72 }
73
74 #[must_use]
77 pub(in crate::db) fn scalar_consistency(&self) -> MissingRowPolicy {
78 if self.access.has_selected_index_access_path() {
79 MissingRowPolicy::Error
84 } else {
85 self.scalar_plan().consistency
86 }
87 }
88
89 #[must_use]
91 pub(in crate::db) const fn grouped_plan(&self) -> Option<&GroupPlan> {
92 match &self.logical {
93 LogicalPlan::Scalar(_) => None,
94 LogicalPlan::Grouped(plan) => Some(plan),
95 }
96 }
97
98 #[must_use]
100 pub(in crate::db) fn projection_spec_with_schema(&self, schema: &SchemaInfo) -> ProjectionSpec {
101 if let Some(static_contract) = &self.static_execution_planning_contract {
102 return static_contract.projection_spec.clone();
103 }
104
105 lower_projection_intent_with_schema(schema, &self.logical, &self.projection_selection)
106 }
107
108 #[must_use]
110 pub(in crate::db::query) fn projection_spec_for_identity(&self) -> ProjectionSpec {
111 lower_projection_identity(&self.logical, &self.projection_selection)
112 }
113
114 #[must_use]
120 pub(in crate::db) fn execution_preparation_predicate(&self) -> Option<Predicate> {
121 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
122 return static_contract.execution_preparation_predicate.clone();
123 }
124
125 derive_execution_preparation_predicate(self)
126 }
127
128 #[must_use]
132 pub(in crate::db) fn effective_execution_predicate(&self) -> Option<Predicate> {
133 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
134 return static_contract
135 .residual_filter_contract
136 .residual_filter_predicate()
137 .cloned();
138 }
139
140 derive_residual_filter_predicate(self)
141 }
142
143 #[must_use]
146 pub(in crate::db) fn has_residual_filter_predicate(&self) -> bool {
147 self.effective_execution_predicate().is_some()
148 }
149
150 #[must_use]
153 pub(in crate::db) fn residual_filter_expr(&self) -> Option<&Expr> {
154 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
155 return static_contract
156 .residual_filter_contract
157 .residual_filter_expr();
158 }
159
160 if !derive_has_residual_filter(self) {
161 return None;
162 }
163
164 self.scalar_plan().filter_expr.as_ref()
165 }
166
167 #[must_use]
170 pub(in crate::db) fn has_residual_filter_expr(&self) -> bool {
171 self.residual_filter_expr().is_some()
172 }
173
174 #[must_use]
176 pub(in crate::db) fn residual_filter_shape(&self) -> ResidualFilterShape {
177 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
178 return static_contract.residual_filter_contract.shape();
179 }
180
181 let expression_required = self.scalar_plan().filter_expr.is_some()
186 && !derive_semantic_filter_fully_satisfied_by_access_contract(self);
187 ResidualFilterShape::from_presence(
188 expression_required,
189 self.effective_execution_predicate().is_some(),
190 )
191 }
192
193 #[must_use]
196 #[cfg(feature = "sql")]
197 pub(in crate::db) fn predicate_pushdown_label(&self) -> String {
198 self.predicate_pushdown_diagnostics().label()
199 }
200
201 #[must_use]
203 #[cfg(feature = "sql")]
204 pub(in crate::db) fn predicate_pushdown_diagnostics(&self) -> PredicatePushdownDiagnostics {
205 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
206 return static_contract.predicate_pushdown_diagnostics;
207 }
208
209 derive_predicate_pushdown_diagnostics(self, self.residual_filter_shape())
210 }
211
212 #[must_use]
214 #[cfg(feature = "sql")]
215 pub(in crate::db) fn predicate_pushdown_outcome_label(&self) -> &'static str {
216 self.predicate_pushdown_diagnostics().outcome_label()
217 }
218
219 #[must_use]
221 #[cfg(feature = "sql")]
222 pub(in crate::db) fn predicate_pushdown_reason_label(&self) -> &'static str {
223 self.predicate_pushdown_diagnostics().reason_label()
224 }
225
226 #[must_use]
228 pub(in crate::db) fn execution_preparation_compiled_predicate(
229 &self,
230 ) -> Option<&PredicateProgram> {
231 self.static_execution_planning_contract()?
232 .execution_preparation_compiled_predicate
233 .as_ref()
234 }
235
236 #[must_use]
238 pub(in crate::db) fn effective_runtime_compiled_predicate(&self) -> Option<&PredicateProgram> {
239 match self
240 .static_execution_planning_contract()?
241 .residual_filter_contract
242 .effective_runtime_filter_program()
243 {
244 Some(program) => program.predicate_program(),
245 None => None,
246 }
247 }
248
249 #[must_use]
251 pub(in crate::db) fn effective_runtime_filter_program(
252 &self,
253 ) -> Option<&EffectiveRuntimeFilterProgram> {
254 self.static_execution_planning_contract()?
255 .residual_filter_contract
256 .effective_runtime_filter_program()
257 }
258
259 #[must_use]
261 pub(in crate::db) fn distinct_execution_strategy(&self) -> DistinctExecutionStrategy {
262 if !self.scalar_plan().distinct {
263 return DistinctExecutionStrategy::None;
264 }
265
266 match distinct_runtime_dedup_strategy(&self.access) {
270 Some(strategy) => strategy,
271 None => DistinctExecutionStrategy::None,
272 }
273 }
274
275 pub(in crate::db) fn finalize_planner_route_profile_for_model_with_schema(
277 &mut self,
278 schema_info: &SchemaInfo,
279 ) {
280 self.set_planner_route_profile(project_planner_route_profile_for_schema(schema_info, self));
281 }
282
283 pub(in crate::db) fn finalize_static_execution_planning_contract_with_schema(
285 &mut self,
286 schema_info: &SchemaInfo,
287 ) -> Result<(), InternalError> {
288 self.bind_group_field_slots_to_schema(schema_info)?;
289 self.static_execution_planning_contract = Some(
290 project_static_execution_planning_contract_with_schema(schema_info, self)?,
291 );
292
293 Ok(())
294 }
295
296 fn bind_group_field_slots_to_schema(
299 &mut self,
300 schema_info: &SchemaInfo,
301 ) -> Result<(), InternalError> {
302 let LogicalPlan::Grouped(grouped) = &mut self.logical else {
303 return Ok(());
304 };
305
306 let accepted_fields = grouped
307 .group
308 .group_fields
309 .resolve_with_schema(schema_info)
310 .ok_or_else(InternalError::planner_executor_invariant)?;
311 grouped.group.group_fields = accepted_fields;
312
313 Ok(())
314 }
315
316 #[must_use]
318 pub(in crate::db) fn execution_shape_signature(
319 &self,
320 entity_path: &str,
321 ) -> ExecutionShapeSignature {
322 ExecutionShapeSignature::new(self.continuation_signature(entity_path))
323 }
324
325 #[must_use]
328 pub(in crate::db) fn predicate_fully_satisfied_by_access_contract(&self) -> bool {
329 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
330 return self.scalar_plan().predicate.is_some()
331 && !static_contract
332 .residual_filter_contract
333 .has_residual_filter();
334 }
335
336 derive_predicate_fully_satisfied_by_access_contract(self)
337 }
338
339 #[must_use]
341 pub(in crate::db) fn scalar_projection_plan(&self) -> Option<&[CompiledExpr]> {
342 self.static_execution_planning_contract()?
343 .scalar_projection_plan
344 .as_deref()
345 }
346
347 #[must_use]
349 pub(in crate::db) const fn has_static_execution_planning_contract(&self) -> bool {
350 self.static_execution_planning_contract.is_some()
351 }
352
353 pub(in crate::db) fn primary_key_names(&self) -> Result<Vec<&str>, InternalError> {
355 Ok(self
356 .require_static_execution_planning_contract()?
357 .primary_key_names
358 .iter()
359 .map(String::as_str)
360 .collect())
361 }
362
363 pub(in crate::db) fn projection_referenced_slots(&self) -> Result<&[usize], InternalError> {
365 Ok(self
366 .require_static_execution_planning_contract()?
367 .projection_referenced_slots
368 .as_slice())
369 }
370
371 #[cfg(any(test, feature = "diagnostics"))]
373 pub(in crate::db) fn projected_slot_mask(&self) -> Result<&[bool], InternalError> {
374 Ok(self
375 .require_static_execution_planning_contract()?
376 .projected_slot_mask
377 .as_slice())
378 }
379
380 pub(in crate::db) fn projection_is_model_identity(&self) -> Result<bool, InternalError> {
382 Ok(self
383 .require_static_execution_planning_contract()?
384 .projection_is_model_identity)
385 }
386
387 #[must_use]
389 pub(in crate::db) fn order_referenced_slots(&self) -> Option<&[usize]> {
390 self.static_execution_planning_contract()?
391 .order_referenced_slots
392 .as_deref()
393 }
394
395 #[must_use]
397 pub(in crate::db) fn resolved_order(&self) -> Option<&ResolvedOrder> {
398 self.static_execution_planning_contract()?
399 .resolved_order
400 .as_ref()
401 }
402
403 #[must_use]
405 pub(in crate::db) fn slot_map(&self) -> Option<&[usize]> {
406 self.static_execution_planning_contract()?
407 .slot_map
408 .as_deref()
409 }
410
411 #[must_use]
413 pub(in crate::db) fn grouped_aggregate_execution_specs(
414 &self,
415 ) -> Option<&[GroupedAggregateExecutionSpec]> {
416 self.static_execution_planning_contract()?
417 .grouped_aggregate_execution_specs
418 .as_deref()
419 }
420
421 #[must_use]
423 pub(in crate::db) fn grouped_distinct_execution_strategy(
424 &self,
425 ) -> Option<&GroupedDistinctExecutionStrategy> {
426 self.static_execution_planning_contract()?
427 .grouped_distinct_execution_strategy
428 .as_ref()
429 }
430
431 pub(in crate::db) fn frozen_projection_spec(&self) -> Result<&ProjectionSpec, InternalError> {
433 Ok(&self
434 .require_static_execution_planning_contract()?
435 .projection_spec)
436 }
437
438 #[must_use]
440 pub(in crate::db) fn frozen_direct_projection_slots(&self) -> Option<&[usize]> {
441 self.static_execution_planning_contract()?
442 .projection_direct_slots
443 .as_deref()
444 }
445
446 #[must_use]
448 pub(in crate::db) fn frozen_data_row_direct_projection_slots(&self) -> Option<&[usize]> {
449 self.static_execution_planning_contract()?
450 .projection_data_row_direct_slots
451 .as_deref()
452 }
453
454 #[must_use]
456 pub(in crate::db) fn index_compile_targets(&self) -> Option<&[IndexCompileTarget]> {
457 self.static_execution_planning_contract()?
458 .index_compile_targets
459 .as_deref()
460 }
461
462 const fn static_execution_planning_contract(&self) -> Option<&StaticExecutionPlanningContract> {
463 self.static_execution_planning_contract.as_ref()
464 }
465
466 fn require_static_execution_planning_contract(
467 &self,
468 ) -> Result<&StaticExecutionPlanningContract, InternalError> {
469 self.static_execution_planning_contract
470 .as_ref()
471 .ok_or_else(InternalError::query_executor_invariant)
472 }
473}
474
475fn distinct_runtime_dedup_strategy<K>(access: &AccessPlan<K>) -> Option<DistinctExecutionStrategy> {
476 match access {
477 AccessPlan::Union(_) | AccessPlan::Intersection(_) => {
478 Some(DistinctExecutionStrategy::PreOrdered)
479 }
480 AccessPlan::Path(path) if path.as_ref().is_index_multi_lookup() => {
481 Some(DistinctExecutionStrategy::HashMaterialize)
482 }
483 AccessPlan::Path(_) => None,
484 }
485}
486
487fn derive_continuation_policy_validated(plan: &AccessPlannedQuery) -> ContinuationPolicy {
488 let is_grouped_safe = plan
489 .grouped_plan()
490 .is_none_or(|grouped| grouped_cursor_policy_violation(grouped, true).is_none());
491
492 ContinuationPolicy::new(
493 true, true, is_grouped_safe,
496 )
497}
498
499#[must_use]
501pub(in crate::db) fn project_planner_route_profile_for_schema(
502 schema_info: &SchemaInfo,
503 plan: &AccessPlannedQuery,
504) -> PlannerRouteProfile {
505 let primary_key_names = primary_key_names_from_schema(schema_info);
506 let secondary_order_contract = plan.scalar_plan().order.as_ref().and_then(|order| {
507 order.deterministic_secondary_order_contract_fields(primary_key_names.as_slice())
508 });
509
510 PlannerRouteProfile::new(
511 derive_continuation_policy_validated(plan),
512 derive_logical_pushdown_eligibility(plan, secondary_order_contract.as_ref()),
513 secondary_order_contract,
514 )
515}
516
517fn project_static_execution_planning_contract_with_schema(
518 schema_info: &SchemaInfo,
519 plan: &AccessPlannedQuery,
520) -> Result<StaticExecutionPlanningContract, InternalError> {
521 let projection_spec =
522 lower_projection_intent_with_schema(schema_info, &plan.logical, &plan.projection_selection);
523 let execution_preparation_predicate = plan.execution_preparation_predicate();
524 let residual_filter_predicate = derive_residual_filter_predicate_from_preparation(
525 plan,
526 execution_preparation_predicate.as_ref(),
527 );
528 let residual_filter_expr = derive_residual_filter_expr(plan);
529 let effective_runtime_filter_program = compile_effective_runtime_filter_program(
530 schema_info,
531 residual_filter_expr.as_ref(),
532 residual_filter_predicate.as_ref(),
533 )?;
534 let residual_filter_contract = ResidualFilterContract::new(
535 residual_filter_expr,
536 residual_filter_predicate,
537 effective_runtime_filter_program,
538 );
539 let residual_filter_shape = residual_filter_contract.shape();
540 let execution_preparation_compiled_predicate =
541 (should_compile_execution_preparation_predicate(residual_filter_shape)
542 && !planner_predicate_requires_expression_runtime(plan))
543 .then(|| compile_optional_predicate(schema_info, execution_preparation_predicate.as_ref()))
544 .flatten();
545 let predicate_pushdown_diagnostics =
546 derive_predicate_pushdown_diagnostics(plan, residual_filter_shape);
547 let scalar_projection_plan = if plan.grouped_plan().is_none() {
548 Some(
549 compile_scalar_projection_plan_with_schema(schema_info, &projection_spec)
550 .ok_or_else(InternalError::query_executor_invariant)?
551 .iter()
552 .map(CompiledExpr::compile)
553 .collect(),
554 )
555 } else {
556 None
557 };
558 let (grouped_aggregate_execution_specs, grouped_distinct_execution_strategy) =
559 resolve_grouped_static_planning_semantics(schema_info, plan, &projection_spec)?;
560 let projection_direct_slots = lower_direct_projection_slots_with_schema(
561 schema_info,
562 &plan.logical,
563 &plan.projection_selection,
564 );
565 let projection_data_row_direct_slots = lower_data_row_direct_projection_slots_with_schema(
566 schema_info,
567 &plan.logical,
568 &plan.projection_selection,
569 );
570 let projection_referenced_slots = projection_spec.referenced_slots_for_schema(schema_info)?;
571 let projected_slot_mask =
572 projected_slot_mask_for_spec(schema_info, projection_direct_slots.as_deref());
573 let projection_is_model_identity = projection_spec.is_schema_identity_for(schema_info);
574 let resolved_order = resolved_order_for_plan(schema_info, plan)?;
575 let order_referenced_slots = order_referenced_slots_for_resolved_order(resolved_order.as_ref());
576 let slot_map = slot_map_for_schema_plan(schema_info, plan);
577 let index_compile_targets = index_compile_targets_for_schema_plan(schema_info, plan);
578
579 Ok(StaticExecutionPlanningContract {
580 primary_key_names: schema_info.primary_key_names().to_vec(),
581 projection_spec,
582 execution_preparation_predicate,
583 execution_preparation_compiled_predicate,
584 residual_filter_contract,
585 predicate_pushdown_diagnostics,
586 scalar_projection_plan,
587 grouped_aggregate_execution_specs,
588 grouped_distinct_execution_strategy,
589 projection_direct_slots,
590 projection_data_row_direct_slots,
591 projection_referenced_slots,
592 projected_slot_mask,
593 projection_is_model_identity,
594 resolved_order,
595 order_referenced_slots,
596 slot_map,
597 index_compile_targets,
598 })
599}
600
601fn primary_key_names_from_schema(schema_info: &SchemaInfo) -> Vec<&str> {
602 schema_info
603 .primary_key_names()
604 .iter()
605 .map(String::as_str)
606 .collect()
607}
608
609fn compile_effective_runtime_filter_program(
613 schema_info: &SchemaInfo,
614 residual_filter_expr: Option<&Expr>,
615 residual_filter_predicate: Option<&Predicate>,
616) -> Result<Option<EffectiveRuntimeFilterProgram>, InternalError> {
617 if let Some(predicate) = residual_filter_predicate {
622 return Ok(Some(EffectiveRuntimeFilterProgram::predicate(
623 PredicateProgram::compile_with_schema_info(schema_info, predicate),
624 )));
625 }
626
627 if let Some(filter_expr) = residual_filter_expr {
628 let compiled = compile_scalar_projection_expr_with_schema(schema_info, filter_expr)
629 .ok_or_else(InternalError::query_invalid_logical_plan)?;
630
631 return Ok(Some(EffectiveRuntimeFilterProgram::expression(
632 CompiledExpr::compile(&compiled),
633 )));
634 }
635
636 Ok(None)
637}
638
639fn derive_execution_preparation_predicate(plan: &AccessPlannedQuery) -> Option<Predicate> {
643 let query_predicate = plan.scalar_plan().predicate.as_ref()?;
644
645 match plan.access.selected_index_contract() {
646 Some(index) => {
647 residual_query_predicate_after_filtered_access_contract(index, query_predicate)
648 }
649 None => Some(query_predicate.clone()),
650 }
651}
652
653fn derive_residual_filter_predicate(plan: &AccessPlannedQuery) -> Option<Predicate> {
657 let filtered_residual = derive_execution_preparation_predicate(plan);
658
659 derive_residual_filter_predicate_from_preparation(plan, filtered_residual.as_ref())
660}
661
662fn derive_residual_filter_predicate_from_preparation(
663 plan: &AccessPlannedQuery,
664 execution_preparation_predicate: Option<&Predicate>,
665) -> Option<Predicate> {
666 let execution_preparation_predicate = execution_preparation_predicate?;
667
668 let residual = residual_query_predicate_after_access_path_bounds(
669 plan.access.as_path(),
670 execution_preparation_predicate,
671 );
672 if residual.is_some() && planner_predicate_requires_expression_runtime(plan) {
673 return None;
674 }
675
676 residual
677}
678
679fn derive_residual_filter_expr(plan: &AccessPlannedQuery) -> Option<Expr> {
683 let filter_expr = plan.scalar_plan().filter_expr.as_ref()?;
684 if derive_semantic_filter_fully_satisfied_by_access_contract(plan)
685 && (!planner_predicate_requires_expression_runtime(plan)
686 || planner_predicate_is_fully_satisfied_by_access_contract(plan))
687 {
688 return None;
689 }
690
691 Some(filter_expr.clone())
692}
693
694fn planner_predicate_requires_expression_runtime(plan: &AccessPlannedQuery) -> bool {
699 plan.scalar_plan().predicate_covers_filter_expr
700 && plan
701 .scalar_plan()
702 .filter_expr
703 .as_ref()
704 .is_some_and(Expr::contains_field_path)
705}
706
707fn planner_predicate_is_fully_satisfied_by_access_contract(plan: &AccessPlannedQuery) -> bool {
708 let Some(predicate) = derive_execution_preparation_predicate(plan) else {
709 return false;
710 };
711
712 residual_query_predicate_after_access_path_bounds(plan.access.as_path(), &predicate).is_none()
713}
714
715fn derive_has_residual_filter(plan: &AccessPlannedQuery) -> bool {
719 match (
720 plan.scalar_plan().filter_expr.as_ref(),
721 plan.scalar_plan().predicate.as_ref(),
722 ) {
723 (None, None) => false,
724 (Some(_), None) => true,
725 (Some(_) | None, Some(_)) => !plan.predicate_fully_satisfied_by_access_contract(),
726 }
727}
728
729fn derive_predicate_pushdown_diagnostics(
733 plan: &AccessPlannedQuery,
734 residual_filter_shape: ResidualFilterShape,
735) -> PredicatePushdownDiagnostics {
736 PredicatePushdownDiagnostics::from_plan(
737 plan.scalar_plan().filter_expr.is_some(),
738 plan.scalar_plan().predicate_covers_filter_expr,
739 plan.scalar_plan().predicate.as_ref(),
740 &plan.access,
741 residual_filter_shape,
742 )
743}
744
745fn derive_predicate_fully_satisfied_by_access_contract(plan: &AccessPlannedQuery) -> bool {
748 plan.scalar_plan().predicate.is_some()
749 && derive_residual_filter_predicate(plan).is_none()
750 && derive_residual_filter_expr(plan).is_none()
751}
752
753const fn derive_semantic_filter_fully_satisfied_by_access_contract(
757 plan: &AccessPlannedQuery,
758) -> bool {
759 plan.scalar_plan().filter_expr.is_some()
760 && plan.scalar_plan().predicate.is_some()
761 && plan.scalar_plan().predicate_covers_filter_expr
762}
763
764fn compile_optional_predicate(
767 schema_info: &SchemaInfo,
768 predicate: Option<&Predicate>,
769) -> Option<PredicateProgram> {
770 predicate.map(|predicate| PredicateProgram::compile_with_schema_info(schema_info, predicate))
771}
772
773const fn should_compile_execution_preparation_predicate(
778 residual_filter_shape: ResidualFilterShape,
779) -> bool {
780 !residual_filter_shape.is_absent()
781}
782
783fn resolve_grouped_static_planning_semantics(
787 schema_info: &SchemaInfo,
788 plan: &AccessPlannedQuery,
789 projection_spec: &ProjectionSpec,
790) -> Result<
791 (
792 Option<Vec<GroupedAggregateExecutionSpec>>,
793 Option<GroupedDistinctExecutionStrategy>,
794 ),
795 InternalError,
796> {
797 let Some(grouped) = plan.grouped_plan() else {
798 return Ok((None, None));
799 };
800
801 let mut aggregate_specs = grouped_aggregate_specs_from_projection_spec(
802 projection_spec,
803 &grouped.group.group_fields,
804 grouped.group.aggregates.as_slice(),
805 )?;
806 extend_grouped_having_aggregate_specs(&mut aggregate_specs, grouped)?;
807
808 let grouped_aggregate_execution_specs = Some(grouped_aggregate_execution_specs(
809 schema_info,
810 aggregate_specs.as_slice(),
811 )?);
812 let grouped_distinct_execution_strategy = Some(
813 resolved_grouped_distinct_execution_strategy_with_schema_info(
814 schema_info,
815 &grouped.group.group_fields,
816 grouped.group.aggregates.as_slice(),
817 grouped.having_expr.as_ref(),
818 )?,
819 );
820
821 Ok((
822 grouped_aggregate_execution_specs,
823 grouped_distinct_execution_strategy,
824 ))
825}
826
827fn extend_grouped_having_aggregate_specs(
828 aggregate_specs: &mut Vec<GroupedAggregateExecutionSpec>,
829 grouped: &GroupPlan,
830) -> Result<(), InternalError> {
831 if let Some(having_expr) = grouped.having_expr.as_ref() {
832 extend_unique_grouped_aggregate_specs_from_expr(aggregate_specs, having_expr)?;
833 }
834
835 Ok(())
836}
837
838fn projected_slot_mask_for_spec(
839 schema_info: &SchemaInfo,
840 direct_projection_slots: Option<&[usize]>,
841) -> Vec<bool> {
842 let schema_slot_len = direct_projection_slots
843 .and_then(|slots| slots.iter().copied().max())
844 .map_or(0, |slot| slot.saturating_add(1));
845 let mut projected_slots = vec![
846 false;
847 schema_info
848 .field_names_in_slot_order()
849 .len()
850 .max(schema_slot_len)
851 ];
852
853 let Some(direct_projection_slots) = direct_projection_slots else {
854 return projected_slots;
855 };
856
857 for slot in direct_projection_slots.iter().copied() {
858 if let Some(projected) = projected_slots.get_mut(slot) {
859 *projected = true;
860 }
861 }
862
863 projected_slots
864}
865
866fn resolved_order_for_plan(
867 schema_info: &SchemaInfo,
868 plan: &AccessPlannedQuery,
869) -> Result<Option<ResolvedOrder>, InternalError> {
870 if grouped_plan_strategy(plan).is_some_and(GroupedPlanStrategy::is_top_k_group) {
871 return Ok(None);
872 }
873
874 let Some(order) = plan.scalar_plan().order.as_ref() else {
875 return Ok(None);
876 };
877
878 let mut fields = Vec::with_capacity(order.fields.len());
879 for term in &order.fields {
880 fields.push(ResolvedOrderField::new(
881 resolved_order_value_source_for_term(schema_info, term)?,
882 term.direction(),
883 ));
884 }
885
886 Ok(Some(ResolvedOrder::new(fields)))
887}
888
889fn resolved_order_value_source_for_term(
890 schema_info: &SchemaInfo,
891 term: &crate::db::query::plan::OrderTerm,
892) -> Result<ResolvedOrderValueSource, InternalError> {
893 if term.direct_field().is_none() {
894 let rendered = term.rendered_label();
895 validate_resolved_order_expr_fields(schema_info, term.expr(), rendered.as_str())?;
896 let compiled = compile_scalar_projection_expr_with_schema(schema_info, term.expr())
897 .ok_or_else(|| order_expression_scalar_seam_error(rendered.as_str()))?;
898
899 return Ok(ResolvedOrderValueSource::expression(CompiledExpr::compile(
900 &compiled,
901 )));
902 }
903
904 let Some(field) = term.direct_field() else {
905 return Err(InternalError::query_invalid_logical_plan());
906 };
907 let slot = resolve_required_schema_slot(
908 schema_info,
909 field,
910 InternalError::query_invalid_logical_plan,
911 )?;
912
913 Ok(ResolvedOrderValueSource::direct_field(slot))
914}
915
916fn validate_resolved_order_expr_fields(
917 schema_info: &SchemaInfo,
918 expr: &Expr,
919 rendered: &str,
920) -> Result<(), InternalError> {
921 expr.try_for_each_tree_expr(&mut |node| match node {
922 Expr::Field(field_id) => resolve_required_schema_slot(
923 schema_info,
924 field_id.as_str(),
925 InternalError::query_invalid_logical_plan,
926 )
927 .map(|_| ()),
928 Expr::Aggregate(_) => Err(order_expression_scalar_seam_error(rendered)),
929 #[cfg(test)]
930 Expr::Alias { .. } => Err(order_expression_scalar_seam_error(rendered)),
931 Expr::Unary { .. } => Err(order_expression_scalar_seam_error(rendered)),
932 _ => Ok(()),
933 })
934}
935
936fn resolve_required_schema_slot<F>(
940 schema_info: &SchemaInfo,
941 field: &str,
942 invalid_plan_error: F,
943) -> Result<usize, InternalError>
944where
945 F: FnOnce() -> InternalError,
946{
947 schema_info
948 .field_slot_index(field)
949 .ok_or_else(invalid_plan_error)
950}
951
952fn order_expression_scalar_seam_error(_rendered: &str) -> InternalError {
955 InternalError::query_invalid_logical_plan()
956}
957
958fn order_referenced_slots_for_resolved_order(
963 resolved_order: Option<&ResolvedOrder>,
964) -> Option<Vec<usize>> {
965 Some(resolved_order?.referenced_slots())
966}
967
968fn slot_map_for_schema_plan(
969 schema_info: &SchemaInfo,
970 plan: &AccessPlannedQuery,
971) -> Option<Vec<usize>> {
972 let executable = plan.access.executable_contract();
973
974 resolved_index_slots_for_access_path(schema_info, &executable)
975}
976
977fn resolved_index_slots_for_access_path(
978 schema_info: &SchemaInfo,
979 access: &ExecutableAccessPlan<'_, crate::value::Value>,
980) -> Option<Vec<usize>> {
981 let path = access.as_path()?;
982 let path_facts = path.shape_facts();
983 let key_items = path_facts.index_key_items_for_slot_map()?;
984 let mut slots = Vec::with_capacity(key_items.key_arity());
985 for key_item in key_items.key_items() {
986 let field = key_item.as_ref().field();
987 let root = field.split_once('.').map_or(field, |(root, _)| root);
988 let slot = schema_info.field_slot_index(root)?;
989 slots.push(slot);
990 }
991
992 Some(slots)
993}
994
995fn index_compile_targets_for_schema_plan(
996 schema_info: &SchemaInfo,
997 plan: &AccessPlannedQuery,
998) -> Option<Vec<IndexCompileTarget>> {
999 let executable = plan.access.executable_contract();
1000 let path = executable.as_path()?;
1001 let key_items = path.shape_facts().index_key_items_for_slot_map()?;
1002 let mut targets = Vec::new();
1003
1004 for (component_index, key_item) in key_items.key_items().iter().enumerate() {
1005 let key_item = key_item.as_ref();
1006 let field = key_item.field();
1007 let root = field.split_once('.').map_or(field, |(root, _)| root);
1008 let field_slot = schema_info.field_slot_index(root)?;
1009 targets.push(IndexCompileTarget {
1010 component_index,
1011 field_slot,
1012 kind: match key_item {
1013 SemanticIndexKeyItemRef::Field(_) => IndexCompileTargetKind::Field,
1014 SemanticIndexKeyItemRef::AcceptedExpression(expression) => {
1015 IndexCompileTargetKind::Expression(expression.op())
1016 }
1017 },
1018 });
1019 }
1020
1021 Some(targets)
1022}