1use crate::db::{QueryError, query::preparation::PreparationWork};
7use icydb_diagnostic_code::DiagnosticExecutionBudgetResource as Resource;
8
9use crate::db::predicate::MissingRowPolicy;
10use crate::{
11 db::{
12 access::{AccessPlan, SemanticIndexKeyItemRef},
13 predicate::{IndexCompileTarget, IndexCompileTargetKind, Predicate, PredicateProgram},
14 query::plan::{
15 AccessPlannedQuery, ContinuationPolicy, DistinctExecutionStrategy,
16 EffectiveRuntimeFilterProgram, ExecutionShapeSignature, GroupPlan,
17 GroupedAggregateExecutionSpec, GroupedDistinctExecutionStrategy, GroupedPlanStrategy,
18 LogicalPlan, PlannerRouteProfile, PredicatePushdownDiagnostics, QueryMode,
19 ResidualFilterContract, ResidualFilterShape, ResolvedOrder, ResolvedOrderField,
20 ResolvedOrderValueSource, ScalarPlan, StaticExecutionPlanningContract,
21 derive_logical_pushdown_eligibility,
22 expr::{
23 CompiledExpr, Expr, ProjectionSpec, compile_scalar_projection_expr_with_schema,
24 compile_scalar_projection_plan_with_schema,
25 },
26 extend_unique_grouped_aggregate_specs_from_expr, grouped_aggregate_execution_specs,
27 grouped_aggregate_specs_from_projection_spec, grouped_cursor_policy_violation,
28 grouped_plan_strategy, lower_direct_projection_layouts_with_schema,
29 lower_projection_identity, lower_projection_intent_with_schema,
30 residual_query_predicate_after_access_path_bounds,
31 residual_query_predicate_after_filtered_access_contract,
32 resolved_grouped_distinct_execution_strategy_with_schema_info,
33 },
34 schema::SchemaInfo,
35 },
36 error::InternalError,
37 value::Value,
38};
39
40impl QueryMode {
41 #[must_use]
43 pub const fn is_load(&self) -> bool {
44 match self {
45 Self::Load(_) => true,
46 Self::Delete(_) => false,
47 }
48 }
49
50 #[must_use]
52 pub const fn is_delete(&self) -> bool {
53 match self {
54 Self::Delete(_) => true,
55 Self::Load(_) => false,
56 }
57 }
58}
59
60impl LogicalPlan {
61 #[must_use]
63 pub(in crate::db) const fn scalar_semantics(&self) -> &ScalarPlan {
64 match self {
65 Self::Scalar(plan) => plan,
66 Self::Grouped(plan) => &plan.scalar,
67 }
68 }
69}
70
71impl AccessPlannedQuery {
72 #[must_use]
74 pub(in crate::db) const fn scalar_plan(&self) -> &ScalarPlan {
75 self.logical.scalar_semantics()
76 }
77
78 #[must_use]
81 pub(in crate::db) fn scalar_consistency(&self) -> MissingRowPolicy {
82 if self.access.has_selected_index_access_path() {
83 MissingRowPolicy::Error
88 } else {
89 self.scalar_plan().consistency
90 }
91 }
92
93 #[must_use]
95 pub(in crate::db) const fn grouped_plan(&self) -> Option<&GroupPlan> {
96 match &self.logical {
97 LogicalPlan::Scalar(_) => None,
98 LogicalPlan::Grouped(plan) => Some(plan),
99 }
100 }
101
102 pub(in crate::db) fn projection_spec(&self) -> Result<&ProjectionSpec, QueryError> {
105 self.static_execution_planning_contract
106 .as_ref()
107 .map(|contract| &contract.projection_spec)
108 .ok_or_else(QueryError::invariant)
109 }
110
111 pub(in crate::db) fn prepare_projection(
113 &self,
114 schema: &SchemaInfo,
115 work: &PreparationWork<'_>,
116 ) -> Result<ProjectionSpec, QueryError> {
117 lower_projection_intent_with_schema(schema, &self.logical, &self.projection_selection, work)
118 }
119
120 #[must_use]
122 pub(in crate::db::query) fn projection_spec_for_identity(&self) -> ProjectionSpec {
123 lower_projection_identity(&self.logical, &self.projection_selection)
124 }
125
126 pub(in crate::db) fn execution_preparation_predicate(
133 &self,
134 work: &PreparationWork<'_>,
135 ) -> Result<Option<Predicate>, QueryError> {
136 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
137 return static_contract
138 .execution_preparation_predicate
139 .as_ref()
140 .map(|predicate| work.copy_predicate(predicate))
141 .transpose();
142 }
143
144 let predicate = self
145 .scalar_plan()
146 .predicate
147 .as_ref()
148 .map(|predicate| work.copy_predicate(predicate))
149 .transpose()?;
150 derive_execution_preparation_predicate(&self.access, predicate, work)
151 .map_err(QueryError::execute)
152 }
153
154 pub(in crate::db) fn residual_filter_contract(
156 &self,
157 ) -> Result<&ResidualFilterContract, InternalError> {
158 Ok(&self
159 .require_static_execution_planning_contract()?
160 .residual_filter_contract)
161 }
162
163 pub(in crate::db) fn effective_execution_predicate(
165 &self,
166 ) -> Result<Option<&Predicate>, InternalError> {
167 Ok(self.residual_filter_contract()?.residual_filter_predicate())
168 }
169
170 pub(in crate::db) fn has_residual_filter_predicate(&self) -> Result<bool, InternalError> {
172 Ok(self.effective_execution_predicate()?.is_some())
173 }
174
175 pub(in crate::db) fn residual_filter_expr(&self) -> Result<Option<&Expr>, InternalError> {
177 Ok(self.residual_filter_contract()?.residual_filter_expr())
178 }
179
180 pub(in crate::db) fn residual_filter_shape(
182 &self,
183 ) -> Result<ResidualFilterShape, InternalError> {
184 Ok(self.residual_filter_contract()?.shape())
185 }
186
187 pub(in crate::db) fn prepare_residual_filter_shape(
189 &self,
190 budget: &dyn crate::db::resource::construction::ConstructionBudget,
191 ) -> Result<ResidualFilterShape, InternalError> {
192 if self.has_static_execution_planning_contract() {
193 return self.residual_filter_shape();
194 }
195 let predicate = self
196 .scalar_plan()
197 .predicate
198 .as_ref()
199 .map(|predicate| budget.copy_predicate(predicate))
200 .transpose()?;
201 Ok(
202 residual_filter_facts_for_access(self.scalar_plan(), &self.access, predicate, budget)?
203 .0,
204 )
205 }
206
207 #[cfg(feature = "sql")]
209 pub(in crate::db) fn predicate_pushdown_diagnostics(
210 &self,
211 ) -> Result<PredicatePushdownDiagnostics, InternalError> {
212 Ok(self
213 .require_static_execution_planning_contract()?
214 .predicate_pushdown_diagnostics)
215 }
216
217 #[must_use]
219 pub(in crate::db) fn execution_preparation_compiled_predicate(
220 &self,
221 ) -> Option<&PredicateProgram> {
222 self.static_execution_planning_contract()?
223 .execution_preparation_compiled_predicate
224 .as_ref()
225 }
226
227 #[must_use]
229 pub(in crate::db) fn effective_runtime_compiled_predicate(&self) -> Option<&PredicateProgram> {
230 let program = self.effective_runtime_filter_program()?;
231 if program.expression_filter().is_some() {
232 return None;
233 }
234
235 program.predicate_program()
236 }
237
238 #[must_use]
240 pub(in crate::db) fn effective_runtime_filter_program(
241 &self,
242 ) -> Option<&EffectiveRuntimeFilterProgram> {
243 self.static_execution_planning_contract()?
244 .residual_filter_contract
245 .effective_runtime_filter_program()
246 }
247
248 #[must_use]
250 pub(in crate::db) const fn distinct_execution_strategy(&self) -> DistinctExecutionStrategy {
251 if !self.scalar_plan().distinct {
252 return DistinctExecutionStrategy::None;
253 }
254
255 distinct_runtime_dedup_strategy(&self.access)
260 }
261
262 pub(in crate::db) fn finalize_planner_route_profile_for_model_with_schema(
264 &mut self,
265 schema_info: &SchemaInfo,
266 work: &PreparationWork<'_>,
267 ) -> Result<(), InternalError> {
268 self.set_planner_route_profile(project_planner_route_profile_for_schema(
269 schema_info,
270 self,
271 work,
272 )?);
273 Ok(())
274 }
275
276 pub(in crate::db) fn finalize_static_execution_planning_contract_with_schema(
280 &mut self,
281 schema_info: &SchemaInfo,
282 projection: ProjectionSpec,
283 work: &PreparationWork<'_>,
284 ) -> Result<(), QueryError> {
285 self.bind_group_field_slots_to_schema(schema_info, work)?;
286 self.static_execution_planning_contract =
287 Some(project_static_execution_planning_contract_with_schema(
288 schema_info,
289 self,
290 projection,
291 work,
292 )?);
293
294 Ok(())
295 }
296
297 fn bind_group_field_slots_to_schema(
300 &mut self,
301 schema_info: &SchemaInfo,
302 work: &PreparationWork<'_>,
303 ) -> Result<(), QueryError> {
304 let LogicalPlan::Grouped(grouped) = &mut self.logical else {
305 return Ok(());
306 };
307
308 let accepted_fields = grouped
309 .group
310 .group_fields
311 .resolve_with_schema(schema_info, work)?
312 .ok_or_else(|| QueryError::execute(InternalError::planner_executor_invariant()))?;
313 grouped.group.group_fields = accepted_fields;
314
315 Ok(())
316 }
317
318 pub(in crate::db) fn execution_shape_signature(
320 &self,
321 entity_path: &str,
322 budget: &dyn crate::db::resource::construction::ConstructionBudget,
323 ) -> Result<ExecutionShapeSignature, InternalError> {
324 Ok(ExecutionShapeSignature::new(
325 self.continuation_signature(entity_path, budget)?,
326 ))
327 }
328
329 #[must_use]
331 pub(in crate::db) fn scalar_projection_plan(&self) -> Option<&[CompiledExpr]> {
332 self.static_execution_planning_contract()?
333 .scalar_projection_plan
334 .as_deref()
335 }
336
337 #[must_use]
339 pub(in crate::db) const fn has_static_execution_planning_contract(&self) -> bool {
340 self.static_execution_planning_contract.is_some()
341 }
342
343 pub(in crate::db) fn primary_key_names(&self) -> Result<&[String], InternalError> {
345 Ok(&self
346 .require_static_execution_planning_contract()?
347 .primary_key_names)
348 }
349
350 pub(in crate::db) fn projection_referenced_slots(&self) -> Result<&[usize], InternalError> {
352 Ok(self
353 .require_static_execution_planning_contract()?
354 .projection_referenced_slots
355 .as_slice())
356 }
357
358 pub(in crate::db) fn projection_is_model_identity(&self) -> Result<bool, InternalError> {
360 Ok(self
361 .require_static_execution_planning_contract()?
362 .projection_is_model_identity)
363 }
364
365 #[must_use]
367 pub(in crate::db) fn order_referenced_slots(&self) -> Option<&[usize]> {
368 self.static_execution_planning_contract()?
369 .order_referenced_slots
370 .as_deref()
371 }
372
373 #[must_use]
375 pub(in crate::db) fn resolved_order(&self) -> Option<&ResolvedOrder> {
376 self.static_execution_planning_contract()?
377 .resolved_order
378 .as_ref()
379 }
380
381 #[must_use]
383 pub(in crate::db) fn slot_map(&self) -> Option<&[usize]> {
384 self.static_execution_planning_contract()?
385 .slot_map
386 .as_deref()
387 }
388
389 #[must_use]
391 pub(in crate::db) fn grouped_aggregate_execution_specs(
392 &self,
393 ) -> Option<&[GroupedAggregateExecutionSpec]> {
394 self.static_execution_planning_contract()?
395 .grouped_aggregate_execution_specs
396 .as_deref()
397 }
398
399 #[must_use]
401 pub(in crate::db) fn grouped_distinct_execution_strategy(
402 &self,
403 ) -> Option<&GroupedDistinctExecutionStrategy> {
404 self.static_execution_planning_contract()?
405 .grouped_distinct_execution_strategy
406 .as_ref()
407 }
408
409 pub(in crate::db) fn frozen_projection_spec(&self) -> Result<&ProjectionSpec, InternalError> {
411 Ok(&self
412 .require_static_execution_planning_contract()?
413 .projection_spec)
414 }
415
416 #[must_use]
418 pub(in crate::db) fn frozen_direct_projection_slots(&self) -> Option<&[usize]> {
419 self.static_execution_planning_contract()?
420 .projection_direct_slots
421 .as_deref()
422 }
423
424 #[must_use]
426 pub(in crate::db) fn frozen_data_row_direct_projection_slots(&self) -> Option<&[usize]> {
427 self.static_execution_planning_contract()?
428 .projection_data_row_direct_slots
429 .as_deref()
430 }
431
432 #[must_use]
434 pub(in crate::db) fn index_compile_targets(&self) -> Option<&[IndexCompileTarget]> {
435 self.static_execution_planning_contract()?
436 .index_compile_targets
437 .as_deref()
438 }
439
440 const fn static_execution_planning_contract(&self) -> Option<&StaticExecutionPlanningContract> {
441 self.static_execution_planning_contract.as_ref()
442 }
443
444 fn require_static_execution_planning_contract(
445 &self,
446 ) -> Result<&StaticExecutionPlanningContract, InternalError> {
447 self.static_execution_planning_contract
448 .as_ref()
449 .ok_or_else(InternalError::query_executor_invariant)
450 }
451}
452
453const fn distinct_runtime_dedup_strategy<K>(access: &AccessPlan<K>) -> DistinctExecutionStrategy {
454 match access {
455 AccessPlan::Union(_) | AccessPlan::Intersection(_) => DistinctExecutionStrategy::PreOrdered,
456 AccessPlan::Path(_) => DistinctExecutionStrategy::None,
457 }
458}
459
460fn derive_continuation_policy_validated(plan: &AccessPlannedQuery) -> ContinuationPolicy {
461 let is_grouped_safe = plan
462 .grouped_plan()
463 .is_none_or(|grouped| grouped_cursor_policy_violation(grouped, true).is_none());
464
465 ContinuationPolicy::new(
466 true, true, is_grouped_safe,
469 )
470}
471
472pub(in crate::db) fn project_planner_route_profile_for_schema(
474 schema_info: &SchemaInfo,
475 plan: &AccessPlannedQuery,
476 work: &PreparationWork<'_>,
477) -> Result<PlannerRouteProfile, InternalError> {
478 let secondary_order_contract = plan
479 .scalar_plan()
480 .order
481 .as_ref()
482 .map(|order| {
483 order.deterministic_secondary_order_contract_fields(
484 schema_info.shared_primary_key_names(),
485 work,
486 )
487 })
488 .transpose()?
489 .flatten();
490
491 Ok(PlannerRouteProfile::new(
492 derive_continuation_policy_validated(plan),
493 derive_logical_pushdown_eligibility(plan, secondary_order_contract.as_ref()),
494 secondary_order_contract,
495 ))
496}
497
498fn project_static_execution_planning_contract_with_schema(
499 schema_info: &SchemaInfo,
500 plan: &AccessPlannedQuery,
501 projection_spec: ProjectionSpec,
502 work: &PreparationWork<'_>,
503) -> Result<StaticExecutionPlanningContract, QueryError> {
504 let execution_preparation_predicate = plan.execution_preparation_predicate(work)?;
505 let residual_input = execution_preparation_predicate
508 .as_ref()
509 .map(|predicate| work.copy_predicate(predicate))
510 .transpose()?;
511 let (residual_filter_predicate, access_satisfied) =
512 derive_residual_filter_predicate_from_preparation(
513 plan.scalar_plan(),
514 &plan.access,
515 residual_input,
516 work,
517 )
518 .map_err(QueryError::execute)?;
519 let residual_filter_expr = derive_residual_filter_expr(plan, access_satisfied);
520 let effective_runtime_filter_program = compile_effective_runtime_filter_program(
521 schema_info,
522 residual_filter_expr.as_ref(),
523 residual_filter_predicate.as_ref(),
524 plan.scalar_plan().predicate_covers_filter_expr,
525 work,
526 )
527 .map_err(QueryError::execute)?;
528 let residual_filter_contract = ResidualFilterContract::new(
529 residual_filter_expr,
530 residual_filter_predicate,
531 effective_runtime_filter_program,
532 );
533 let residual_filter_shape = residual_filter_contract.shape();
534 let execution_preparation_compiled_predicate =
535 (should_compile_execution_preparation_predicate(residual_filter_shape)
536 && !planner_predicate_requires_expression_runtime(plan.scalar_plan()))
537 .then(|| compile_optional_predicate(schema_info, execution_preparation_predicate.as_ref()))
538 .flatten();
539 let predicate_pushdown_diagnostics =
540 derive_predicate_pushdown_diagnostics(plan, residual_filter_shape);
541 let scalar_projection_plan = if plan.grouped_plan().is_none() {
542 Some(
543 compile_scalar_projection_plan_with_schema(schema_info, &projection_spec, work)
544 .map_err(QueryError::execute)?
545 .ok_or_else(|| QueryError::execute(InternalError::query_executor_invariant()))?,
546 )
547 } else {
548 None
549 };
550 let (grouped_aggregate_execution_specs, grouped_distinct_execution_strategy) =
551 resolve_grouped_static_planning_semantics(schema_info, plan, &projection_spec, work)
552 .map_err(QueryError::execute)?;
553 let (projection_direct_slots, projection_data_row_direct_slots) =
554 lower_direct_projection_layouts_with_schema(
555 schema_info,
556 &plan.logical,
557 &projection_spec,
558 work,
559 )?;
560 let projection_referenced_slots =
561 projection_spec.referenced_slots_for_schema(schema_info, work)?;
562 let projection_is_model_identity = projection_spec.is_schema_identity_for(schema_info, work)?;
563 let resolved_order = resolved_order_for_plan(schema_info, plan, work)?;
564 let order_referenced_slots = resolved_order
565 .as_ref()
566 .map(|order| order.referenced_slots(work))
567 .transpose()?;
568 let (slot_map, index_compile_targets) =
569 index_execution_metadata_for_schema_plan(schema_info, plan, work)?
570 .map_or((None, None), |(slots, targets)| {
571 (Some(slots), Some(targets))
572 });
573
574 Ok(StaticExecutionPlanningContract {
575 primary_key_names: schema_info.shared_primary_key_names(),
576 projection_spec,
577 execution_preparation_predicate,
578 execution_preparation_compiled_predicate,
579 residual_filter_contract,
580 predicate_pushdown_diagnostics,
581 scalar_projection_plan,
582 grouped_aggregate_execution_specs,
583 grouped_distinct_execution_strategy,
584 projection_direct_slots,
585 projection_data_row_direct_slots,
586 projection_referenced_slots,
587 projection_is_model_identity,
588 resolved_order,
589 order_referenced_slots,
590 slot_map,
591 index_compile_targets,
592 })
593}
594
595fn compile_effective_runtime_filter_program(
599 schema_info: &SchemaInfo,
600 residual_filter_expr: Option<&Expr>,
601 residual_filter_predicate: Option<&Predicate>,
602 predicate_covers_filter_expr: bool,
603 work: &PreparationWork<'_>,
604) -> Result<Option<EffectiveRuntimeFilterProgram>, InternalError> {
605 if let Some(predicate) = residual_filter_predicate
608 && (residual_filter_expr.is_none() || predicate_covers_filter_expr)
609 {
610 return Ok(Some(EffectiveRuntimeFilterProgram::predicate(
611 PredicateProgram::compile_with_schema_info(schema_info, predicate),
612 )));
613 }
614
615 if let Some(filter_expr) = residual_filter_expr {
616 let compiled = compile_scalar_projection_expr_with_schema(schema_info, filter_expr, work)?
617 .ok_or_else(InternalError::query_invalid_logical_plan)?;
618
619 return Ok(Some(EffectiveRuntimeFilterProgram::expression(
620 compiled,
621 compile_optional_predicate(schema_info, residual_filter_predicate),
622 )));
623 }
624
625 Ok(None)
626}
627
628fn derive_execution_preparation_predicate(
632 access: &AccessPlan<Value>,
633 query_predicate: Option<Predicate>,
634 budget: &dyn crate::db::resource::construction::ConstructionBudget,
635) -> Result<Option<Predicate>, InternalError> {
636 let Some(query_predicate) = query_predicate else {
637 return Ok(None);
638 };
639 match access.selected_index_contract() {
640 Some(index) => {
641 residual_query_predicate_after_filtered_access_contract(index, query_predicate, budget)
642 }
643 None => Ok(Some(query_predicate)),
644 }
645}
646
647fn derive_residual_filter_predicate(
651 scalar: &ScalarPlan,
652 access: &AccessPlan<Value>,
653 query_predicate: Option<Predicate>,
654 budget: &dyn crate::db::resource::construction::ConstructionBudget,
655) -> Result<Option<Predicate>, InternalError> {
656 let filtered = derive_execution_preparation_predicate(access, query_predicate, budget)?;
657 Ok(derive_residual_filter_predicate_from_preparation(scalar, access, filtered, budget)?.0)
658}
659
660fn derive_residual_filter_predicate_from_preparation(
661 scalar: &ScalarPlan,
662 access: &AccessPlan<Value>,
663 execution_preparation_predicate: Option<Predicate>,
664 budget: &dyn crate::db::resource::construction::ConstructionBudget,
665) -> Result<(Option<Predicate>, bool), InternalError> {
666 let Some(execution_preparation_predicate) = execution_preparation_predicate else {
667 return Ok((None, false));
668 };
669
670 let residual = residual_query_predicate_after_access_path_bounds(
671 access.as_path(),
672 execution_preparation_predicate,
673 budget,
674 )?;
675 if residual.is_some() && planner_predicate_requires_expression_runtime(scalar) {
676 return Ok((None, false));
677 }
678
679 let access_satisfied = residual.is_none();
680 Ok((residual, access_satisfied))
681}
682
683fn derive_residual_filter_expr(plan: &AccessPlannedQuery, access_satisfied: bool) -> Option<Expr> {
687 let filter_expr = plan.scalar_plan().filter_expr.as_ref()?;
688 if derive_semantic_filter_fully_satisfied_by_access_contract(plan.scalar_plan())
689 && (!planner_predicate_requires_expression_runtime(plan.scalar_plan()) || access_satisfied)
690 {
691 return None;
692 }
693
694 Some(filter_expr.clone())
695}
696
697fn planner_predicate_requires_expression_runtime(scalar: &ScalarPlan) -> bool {
702 scalar.predicate_covers_filter_expr
703 && scalar
704 .filter_expr
705 .as_ref()
706 .is_some_and(Expr::contains_field_path)
707}
708
709fn derive_predicate_pushdown_diagnostics(
712 plan: &AccessPlannedQuery,
713 residual_filter_shape: ResidualFilterShape,
714) -> PredicatePushdownDiagnostics {
715 PredicatePushdownDiagnostics::from_plan(
716 plan.scalar_plan().filter_expr.is_some(),
717 plan.scalar_plan().predicate_covers_filter_expr,
718 plan.scalar_plan().predicate.as_ref(),
719 &plan.access,
720 residual_filter_shape,
721 )
722}
723
724const fn derive_semantic_filter_fully_satisfied_by_access_contract(scalar: &ScalarPlan) -> bool {
728 scalar.filter_expr.is_some()
729 && scalar.predicate.is_some()
730 && scalar.predicate_covers_filter_expr
731}
732
733pub(in crate::db::query) fn residual_filter_facts_for_access(
737 scalar: &ScalarPlan,
738 access: &AccessPlan<Value>,
739 query_predicate: Option<Predicate>,
740 budget: &dyn crate::db::resource::construction::ConstructionBudget,
741) -> Result<(ResidualFilterShape, Option<Predicate>), InternalError> {
742 let predicate = derive_residual_filter_predicate(scalar, access, query_predicate, budget)?;
743 let expression_required = scalar.filter_expr.is_some()
746 && !derive_semantic_filter_fully_satisfied_by_access_contract(scalar);
747
748 Ok((
749 ResidualFilterShape::from_presence(expression_required, predicate.is_some()),
750 predicate,
751 ))
752}
753
754fn compile_optional_predicate(
757 schema_info: &SchemaInfo,
758 predicate: Option<&Predicate>,
759) -> Option<PredicateProgram> {
760 predicate.map(|predicate| PredicateProgram::compile_with_schema_info(schema_info, predicate))
761}
762
763const fn should_compile_execution_preparation_predicate(
768 residual_filter_shape: ResidualFilterShape,
769) -> bool {
770 !residual_filter_shape.is_absent()
771}
772
773fn resolve_grouped_static_planning_semantics(
777 schema_info: &SchemaInfo,
778 plan: &AccessPlannedQuery,
779 projection_spec: &ProjectionSpec,
780 work: &PreparationWork<'_>,
781) -> Result<
782 (
783 Option<Vec<GroupedAggregateExecutionSpec>>,
784 Option<GroupedDistinctExecutionStrategy>,
785 ),
786 InternalError,
787> {
788 let Some(grouped) = plan.grouped_plan() else {
789 return Ok((None, None));
790 };
791
792 let mut aggregate_specs = grouped_aggregate_specs_from_projection_spec(projection_spec)?;
793 extend_grouped_having_aggregate_specs(&mut aggregate_specs, grouped)?;
794
795 let grouped_aggregate_execution_specs = Some(grouped_aggregate_execution_specs(
796 schema_info,
797 aggregate_specs,
798 work,
799 )?);
800 let grouped_distinct_execution_strategy = Some(
801 resolved_grouped_distinct_execution_strategy_with_schema_info(
802 schema_info,
803 &grouped.group.group_fields,
804 grouped.group.aggregates.as_slice(),
805 grouped.having_expr.as_ref(),
806 )?,
807 );
808
809 Ok((
810 grouped_aggregate_execution_specs,
811 grouped_distinct_execution_strategy,
812 ))
813}
814
815fn extend_grouped_having_aggregate_specs(
816 aggregate_specs: &mut Vec<GroupedAggregateExecutionSpec>,
817 grouped: &GroupPlan,
818) -> Result<(), InternalError> {
819 if let Some(having_expr) = grouped.having_expr.as_ref() {
820 extend_unique_grouped_aggregate_specs_from_expr(aggregate_specs, having_expr)?;
821 }
822
823 Ok(())
824}
825
826fn resolved_order_for_plan(
827 schema_info: &SchemaInfo,
828 plan: &AccessPlannedQuery,
829 work: &PreparationWork<'_>,
830) -> Result<Option<ResolvedOrder>, QueryError> {
831 if grouped_plan_strategy(plan, || plan.prepare_residual_filter_shape(work))
832 .map_err(QueryError::execute)?
833 .is_some_and(GroupedPlanStrategy::is_top_k_group)
834 {
835 return Ok(None);
836 }
837
838 let Some(order) = plan.scalar_plan().order.as_ref() else {
839 return Ok(None);
840 };
841
842 let mut fields = work.vec_with_capacity(order.fields.len())?;
843 for term in &order.fields {
844 fields.push(ResolvedOrderField::new(
845 resolved_order_value_source_for_term(schema_info, term, work)?,
846 term.direction(),
847 ));
848 }
849
850 Ok(Some(ResolvedOrder::new(fields)))
851}
852
853fn resolved_order_value_source_for_term(
854 schema_info: &SchemaInfo,
855 term: &crate::db::query::plan::OrderTerm,
856 work: &PreparationWork<'_>,
857) -> Result<ResolvedOrderValueSource, QueryError> {
858 if let Some(field) = term.direct_field() {
859 work.charge(Resource::PredicateExpressionSteps, 1 + field.len() as u64)?;
860 let slot = schema_info
861 .field_slot_index(field)
862 .ok_or_else(|| QueryError::execute(InternalError::query_invalid_logical_plan()))?;
863
864 return Ok(ResolvedOrderValueSource::direct_field(slot));
865 }
866
867 validate_resolved_order_scalar_seam(term.expr(), work)?;
868 let compiled = compile_scalar_projection_expr_with_schema(schema_info, term.expr(), work)
871 .map_err(QueryError::execute)?
872 .ok_or_else(|| QueryError::execute(InternalError::query_invalid_logical_plan()))?;
873
874 Ok(ResolvedOrderValueSource::expression(compiled))
875}
876
877fn validate_resolved_order_scalar_seam(
880 expr: &Expr,
881 work: &PreparationWork<'_>,
882) -> Result<(), QueryError> {
883 expr.try_for_each_tree_expr(&mut |node| {
884 work.charge(Resource::PredicateExpressionSteps, 1)?;
885 match node {
886 Expr::Aggregate(_) | Expr::Unary { .. } => Err(QueryError::execute(
887 InternalError::query_invalid_logical_plan(),
888 )),
889 _ => Ok(()),
890 }
891 })
892}
893
894type IndexExecutionMetadata = (Vec<usize>, Vec<IndexCompileTarget>);
895
896fn index_execution_metadata_for_schema_plan(
900 schema_info: &SchemaInfo,
901 plan: &AccessPlannedQuery,
902 work: &PreparationWork<'_>,
903) -> Result<Option<IndexExecutionMetadata>, QueryError> {
904 let executable = plan.access.executable_contract();
905 let Some(path) = executable.as_path() else {
906 return Ok(None);
907 };
908 let Some(key_items) = path.shape_facts().index_key_items_for_slot_map() else {
909 return Ok(None);
910 };
911 let mut slots = work.vec_with_capacity(key_items.key_arity())?;
912 let mut targets = work.vec_with_capacity(key_items.key_arity())?;
913
914 for (component_index, key_item) in key_items.key_items().iter().enumerate() {
915 let key_item = key_item.as_ref();
916 let field = key_item.field();
917 work.charge(Resource::PredicateExpressionSteps, 1 + field.len() as u64)?;
918 let root = field.split_once('.').map_or(field, |(root, _)| root);
919 let Some(field_slot) = schema_info.field_slot_index(root) else {
920 return Ok(None);
921 };
922 slots.push(field_slot);
923 targets.push(IndexCompileTarget {
924 component_index,
925 field_slot,
926 kind: match key_item {
927 SemanticIndexKeyItemRef::Field(_) => IndexCompileTargetKind::Field,
928 SemanticIndexKeyItemRef::AcceptedExpression(expression) => {
929 IndexCompileTargetKind::Expression(expression.op())
930 }
931 },
932 });
933 }
934
935 Ok(Some((slots, targets)))
936}