1#[cfg(any(test, feature = "sql"))]
7use crate::db::predicate::MissingRowPolicy;
8use crate::{
9 db::{
10 access::{AccessPlan, ExecutableAccessPlan, SemanticIndexKeyItemsRef},
11 predicate::{IndexCompileTarget, Predicate, PredicateProgram},
12 query::plan::{
13 AccessPlannedQuery, ContinuationPolicy, DistinctExecutionStrategy,
14 EffectiveRuntimeFilterProgram, ExecutionShapeSignature, FieldSlot, GroupPlan,
15 GroupedAggregateExecutionSpec, GroupedDistinctExecutionStrategy, GroupedPlanStrategy,
16 LogicalPlan, PlannerRouteProfile, PredicatePushdownDiagnostics, QueryMode,
17 ResidualFilterContract, ResidualFilterShape, ResolvedOrder, ResolvedOrderField,
18 ResolvedOrderValueSource, ScalarPlan, StaticExecutionPlanningContract,
19 derive_logical_pushdown_eligibility,
20 expr::{
21 CompiledExpr, Expr, ProjectionSpec, compile_scalar_projection_expr_with_schema,
22 compile_scalar_projection_plan_with_schema,
23 },
24 extend_unique_grouped_aggregate_specs_from_expr, grouped_aggregate_execution_specs,
25 grouped_aggregate_specs_from_projection_spec, grouped_cursor_policy_violation,
26 grouped_plan_strategy, lower_data_row_direct_projection_slots_with_schema,
27 lower_direct_projection_slots_with_schema, lower_projection_identity,
28 lower_projection_intent, residual_query_predicate_after_access_path_bounds,
29 residual_query_predicate_after_filtered_access_contract,
30 resolved_grouped_distinct_execution_strategy_with_schema_info,
31 },
32 schema::SchemaInfo,
33 },
34 error::InternalError,
35 model::{
36 entity::EntityModel,
37 index::{IndexKeyItem, IndexKeyItemsRef},
38 },
39};
40
41impl QueryMode {
42 #[must_use]
44 pub const fn is_load(&self) -> bool {
45 match self {
46 Self::Load(_) => true,
47 Self::Delete(_) => false,
48 }
49 }
50
51 #[must_use]
53 pub const fn is_delete(&self) -> bool {
54 match self {
55 Self::Delete(_) => true,
56 Self::Load(_) => false,
57 }
58 }
59}
60
61impl LogicalPlan {
62 #[must_use]
64 pub(in crate::db) const fn scalar_semantics(&self) -> &ScalarPlan {
65 match self {
66 Self::Scalar(plan) => plan,
67 Self::Grouped(plan) => &plan.scalar,
68 }
69 }
70
71 #[must_use]
73 #[cfg(test)]
74 pub(in crate::db) const fn scalar_semantics_mut(&mut self) -> &mut ScalarPlan {
75 match self {
76 Self::Scalar(plan) => plan,
77 Self::Grouped(plan) => &mut plan.scalar,
78 }
79 }
80
81 #[must_use]
83 #[cfg(test)]
84 pub(in crate::db) const fn scalar(&self) -> &ScalarPlan {
85 self.scalar_semantics()
86 }
87
88 #[must_use]
90 #[cfg(test)]
91 pub(in crate::db) const fn scalar_mut(&mut self) -> &mut ScalarPlan {
92 self.scalar_semantics_mut()
93 }
94}
95
96impl AccessPlannedQuery {
97 #[must_use]
99 pub(in crate::db) const fn scalar_plan(&self) -> &ScalarPlan {
100 self.logical.scalar_semantics()
101 }
102
103 #[must_use]
106 #[cfg(any(test, feature = "sql"))]
107 pub(in crate::db) const fn scalar_consistency(&self) -> MissingRowPolicy {
108 self.scalar_plan().consistency
109 }
110
111 #[must_use]
113 #[cfg(test)]
114 pub(in crate::db) const fn scalar_plan_mut(&mut self) -> &mut ScalarPlan {
115 self.logical.scalar_semantics_mut()
116 }
117
118 #[must_use]
120 #[cfg(test)]
121 pub(in crate::db) const fn scalar(&self) -> &ScalarPlan {
122 self.scalar_plan()
123 }
124
125 #[must_use]
127 #[cfg(test)]
128 pub(in crate::db) const fn scalar_mut(&mut self) -> &mut ScalarPlan {
129 self.scalar_plan_mut()
130 }
131
132 #[must_use]
134 pub(in crate::db) const fn grouped_plan(&self) -> Option<&GroupPlan> {
135 match &self.logical {
136 LogicalPlan::Scalar(_) => None,
137 LogicalPlan::Grouped(plan) => Some(plan),
138 }
139 }
140
141 #[must_use]
143 pub(in crate::db) fn projection_spec(&self, model: &EntityModel) -> ProjectionSpec {
144 if let Some(static_contract) = &self.static_execution_planning_contract {
145 return static_contract.projection_spec.clone();
146 }
147
148 lower_projection_intent(model, &self.logical, &self.projection_selection)
149 }
150
151 #[must_use]
153 pub(in crate::db::query) fn projection_spec_for_identity(&self) -> ProjectionSpec {
154 lower_projection_identity(&self.logical, &self.projection_selection)
155 }
156
157 #[must_use]
163 pub(in crate::db) fn execution_preparation_predicate(&self) -> Option<Predicate> {
164 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
165 return static_contract.execution_preparation_predicate.clone();
166 }
167
168 derive_execution_preparation_predicate(self)
169 }
170
171 #[must_use]
175 pub(in crate::db) fn effective_execution_predicate(&self) -> Option<Predicate> {
176 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
177 return static_contract
178 .residual_filter_contract
179 .residual_filter_predicate()
180 .cloned();
181 }
182
183 derive_residual_filter_predicate(self)
184 }
185
186 #[must_use]
189 pub(in crate::db) fn has_residual_filter_predicate(&self) -> bool {
190 self.effective_execution_predicate().is_some()
191 }
192
193 #[must_use]
196 pub(in crate::db) fn residual_filter_expr(&self) -> Option<&Expr> {
197 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
198 return static_contract
199 .residual_filter_contract
200 .residual_filter_expr();
201 }
202
203 if !derive_has_residual_filter(self) {
204 return None;
205 }
206
207 self.scalar_plan().filter_expr.as_ref()
208 }
209
210 #[must_use]
213 pub(in crate::db) fn has_residual_filter_expr(&self) -> bool {
214 self.residual_filter_expr().is_some()
215 }
216
217 #[must_use]
219 pub(in crate::db) fn residual_filter_shape(&self) -> ResidualFilterShape {
220 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
221 return static_contract.residual_filter_contract.shape();
222 }
223
224 ResidualFilterShape::from_presence(
225 self.residual_filter_expr().is_some(),
226 self.effective_execution_predicate().is_some(),
227 )
228 }
229
230 #[must_use]
233 pub(in crate::db) fn predicate_pushdown_label(&self) -> String {
234 self.predicate_pushdown_diagnostics().label()
235 }
236
237 #[must_use]
239 pub(in crate::db) fn predicate_pushdown_diagnostics(&self) -> PredicatePushdownDiagnostics {
240 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
241 return static_contract.predicate_pushdown_diagnostics;
242 }
243
244 derive_predicate_pushdown_diagnostics(self, self.residual_filter_shape())
245 }
246
247 #[must_use]
249 pub(in crate::db) fn predicate_pushdown_outcome_label(&self) -> &'static str {
250 self.predicate_pushdown_diagnostics().outcome_label()
251 }
252
253 #[must_use]
255 pub(in crate::db) fn predicate_pushdown_reason_label(&self) -> &'static str {
256 self.predicate_pushdown_diagnostics().reason_label()
257 }
258
259 #[must_use]
261 pub(in crate::db) fn execution_preparation_compiled_predicate(
262 &self,
263 ) -> Option<&PredicateProgram> {
264 self.static_execution_planning_contract()?
265 .execution_preparation_compiled_predicate
266 .as_ref()
267 }
268
269 #[must_use]
271 pub(in crate::db) fn effective_runtime_compiled_predicate(&self) -> Option<&PredicateProgram> {
272 match self
273 .static_execution_planning_contract()?
274 .residual_filter_contract
275 .effective_runtime_filter_program()
276 {
277 Some(program) => program.predicate_program(),
278 None => None,
279 }
280 }
281
282 #[cfg(test)]
284 #[must_use]
285 pub(in crate::db) fn effective_runtime_compiled_filter_expr(&self) -> Option<&CompiledExpr> {
286 match self
287 .static_execution_planning_contract()?
288 .residual_filter_contract
289 .effective_runtime_filter_program()
290 {
291 Some(program) => program.expression_filter(),
292 None => None,
293 }
294 }
295
296 #[must_use]
298 pub(in crate::db) fn effective_runtime_filter_program(
299 &self,
300 ) -> Option<&EffectiveRuntimeFilterProgram> {
301 self.static_execution_planning_contract()?
302 .residual_filter_contract
303 .effective_runtime_filter_program()
304 }
305
306 #[must_use]
308 pub(in crate::db) fn distinct_execution_strategy(&self) -> DistinctExecutionStrategy {
309 if !self.scalar_plan().distinct {
310 return DistinctExecutionStrategy::None;
311 }
312
313 match distinct_runtime_dedup_strategy(&self.access) {
317 Some(strategy) => strategy,
318 None => DistinctExecutionStrategy::None,
319 }
320 }
321
322 #[cfg(test)]
324 pub(in crate::db) fn finalize_planner_route_profile_for_model(&mut self, model: &EntityModel) {
325 self.set_planner_route_profile(project_planner_route_profile_for_model(model, self));
326 }
327
328 pub(in crate::db) fn finalize_planner_route_profile_for_model_with_schema(
330 &mut self,
331 schema_info: &SchemaInfo,
332 ) {
333 self.set_planner_route_profile(project_planner_route_profile_for_schema(schema_info, self));
334 }
335
336 #[cfg(test)]
338 pub(in crate::db) fn finalize_static_execution_planning_contract_for_model_only(
339 &mut self,
340 model: &EntityModel,
341 ) -> Result<(), InternalError> {
342 self.finalize_static_execution_planning_contract_for_model_with_schema(
343 model,
344 SchemaInfo::cached_for_generated_entity_model(model),
345 )
346 }
347
348 pub(in crate::db) fn finalize_static_execution_planning_contract_for_model_with_schema(
350 &mut self,
351 model: &EntityModel,
352 schema_info: &SchemaInfo,
353 ) -> Result<(), InternalError> {
354 self.bind_group_field_slots_to_schema(schema_info)?;
355 self.static_execution_planning_contract = Some(
356 project_static_execution_planning_contract_for_model(model, schema_info, self)?,
357 );
358
359 Ok(())
360 }
361
362 fn bind_group_field_slots_to_schema(
366 &mut self,
367 schema_info: &SchemaInfo,
368 ) -> Result<(), InternalError> {
369 if !schema_info.has_accepted_authority() {
370 return Ok(());
371 }
372 let LogicalPlan::Grouped(grouped) = &mut self.logical else {
373 return Ok(());
374 };
375
376 let accepted_slots = grouped
377 .group
378 .group_fields
379 .iter()
380 .map(|field_slot| FieldSlot::resolve_with_schema(schema_info, field_slot.field()))
381 .collect::<Option<Vec<_>>>()
382 .ok_or_else(InternalError::planner_executor_invariant)?;
383 grouped.group.group_fields = accepted_slots;
384
385 Ok(())
386 }
387
388 #[must_use]
390 pub(in crate::db) fn execution_shape_signature(
391 &self,
392 entity_path: &'static str,
393 ) -> ExecutionShapeSignature {
394 ExecutionShapeSignature::new(self.continuation_signature(entity_path))
395 }
396
397 #[must_use]
400 pub(in crate::db) fn predicate_fully_satisfied_by_access_contract(&self) -> bool {
401 if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
402 return self.scalar_plan().predicate.is_some()
403 && !static_contract
404 .residual_filter_contract
405 .has_residual_filter();
406 }
407
408 derive_predicate_fully_satisfied_by_access_contract(self)
409 }
410
411 #[must_use]
413 pub(in crate::db) fn scalar_projection_plan(&self) -> Option<&[CompiledExpr]> {
414 self.static_execution_planning_contract()?
415 .scalar_projection_plan
416 .as_deref()
417 }
418
419 #[must_use]
421 pub(in crate::db) const fn has_static_execution_planning_contract(&self) -> bool {
422 self.static_execution_planning_contract.is_some()
423 }
424
425 pub(in crate::db) fn primary_key_names(&self) -> Result<Vec<&str>, InternalError> {
427 Ok(self
428 .require_static_execution_planning_contract()?
429 .primary_key_names
430 .iter()
431 .map(String::as_str)
432 .collect())
433 }
434
435 pub(in crate::db) fn projection_referenced_slots(&self) -> Result<&[usize], InternalError> {
437 Ok(self
438 .require_static_execution_planning_contract()?
439 .projection_referenced_slots
440 .as_slice())
441 }
442
443 #[cfg(any(test, all(feature = "sql", feature = "diagnostics")))]
445 pub(in crate::db) fn projected_slot_mask(&self) -> Result<&[bool], InternalError> {
446 Ok(self
447 .require_static_execution_planning_contract()?
448 .projected_slot_mask
449 .as_slice())
450 }
451
452 pub(in crate::db) fn projection_is_model_identity(&self) -> Result<bool, InternalError> {
454 Ok(self
455 .require_static_execution_planning_contract()?
456 .projection_is_model_identity)
457 }
458
459 #[must_use]
461 pub(in crate::db) fn order_referenced_slots(&self) -> Option<&[usize]> {
462 self.static_execution_planning_contract()?
463 .order_referenced_slots
464 .as_deref()
465 }
466
467 #[must_use]
469 pub(in crate::db) fn resolved_order(&self) -> Option<&ResolvedOrder> {
470 self.static_execution_planning_contract()?
471 .resolved_order
472 .as_ref()
473 }
474
475 #[must_use]
477 pub(in crate::db) fn slot_map(&self) -> Option<&[usize]> {
478 self.static_execution_planning_contract()?
479 .slot_map
480 .as_deref()
481 }
482
483 #[must_use]
485 pub(in crate::db) fn grouped_aggregate_execution_specs(
486 &self,
487 ) -> Option<&[GroupedAggregateExecutionSpec]> {
488 self.static_execution_planning_contract()?
489 .grouped_aggregate_execution_specs
490 .as_deref()
491 }
492
493 #[must_use]
495 pub(in crate::db) fn grouped_distinct_execution_strategy(
496 &self,
497 ) -> Option<&GroupedDistinctExecutionStrategy> {
498 self.static_execution_planning_contract()?
499 .grouped_distinct_execution_strategy
500 .as_ref()
501 }
502
503 pub(in crate::db) fn frozen_projection_spec(&self) -> Result<&ProjectionSpec, InternalError> {
505 Ok(&self
506 .require_static_execution_planning_contract()?
507 .projection_spec)
508 }
509
510 #[must_use]
512 #[cfg(any(test, feature = "sql"))]
513 pub(in crate::db) fn frozen_direct_projection_slots(&self) -> Option<&[usize]> {
514 self.static_execution_planning_contract()?
515 .projection_direct_slots
516 .as_deref()
517 }
518
519 #[must_use]
521 #[cfg(any(test, feature = "sql"))]
522 pub(in crate::db) fn frozen_data_row_direct_projection_slots(&self) -> Option<&[usize]> {
523 self.static_execution_planning_contract()?
524 .projection_data_row_direct_slots
525 .as_deref()
526 }
527
528 #[must_use]
530 pub(in crate::db) fn index_compile_targets(&self) -> Option<&[IndexCompileTarget]> {
531 self.static_execution_planning_contract()?
532 .index_compile_targets
533 .as_deref()
534 }
535
536 const fn static_execution_planning_contract(&self) -> Option<&StaticExecutionPlanningContract> {
537 self.static_execution_planning_contract.as_ref()
538 }
539
540 fn require_static_execution_planning_contract(
541 &self,
542 ) -> Result<&StaticExecutionPlanningContract, InternalError> {
543 self.static_execution_planning_contract
544 .as_ref()
545 .ok_or_else(InternalError::query_executor_invariant)
546 }
547}
548
549fn distinct_runtime_dedup_strategy<K>(access: &AccessPlan<K>) -> Option<DistinctExecutionStrategy> {
550 match access {
551 AccessPlan::Union(_) | AccessPlan::Intersection(_) => {
552 Some(DistinctExecutionStrategy::PreOrdered)
553 }
554 AccessPlan::Path(path) if path.as_ref().is_index_multi_lookup() => {
555 Some(DistinctExecutionStrategy::HashMaterialize)
556 }
557 AccessPlan::Path(_) => None,
558 }
559}
560
561fn derive_continuation_policy_validated(plan: &AccessPlannedQuery) -> ContinuationPolicy {
562 let is_grouped_safe = plan
563 .grouped_plan()
564 .is_none_or(|grouped| grouped_cursor_policy_violation(grouped, true).is_none());
565
566 ContinuationPolicy::new(
567 true, true, is_grouped_safe,
570 )
571}
572
573#[must_use]
575#[cfg(test)]
576pub(in crate::db) fn project_planner_route_profile_for_model(
577 model: &EntityModel,
578 plan: &AccessPlannedQuery,
579) -> PlannerRouteProfile {
580 let primary_key_names = ordered_primary_key_names(model);
581 let secondary_order_contract = plan.scalar_plan().order.as_ref().and_then(|order| {
582 order.deterministic_secondary_order_contract_fields(primary_key_names.as_slice())
583 });
584
585 PlannerRouteProfile::new(
586 derive_continuation_policy_validated(plan),
587 derive_logical_pushdown_eligibility(plan, secondary_order_contract.as_ref()),
588 secondary_order_contract,
589 )
590}
591
592#[must_use]
594pub(in crate::db) fn project_planner_route_profile_for_schema(
595 schema_info: &SchemaInfo,
596 plan: &AccessPlannedQuery,
597) -> PlannerRouteProfile {
598 let primary_key_names = primary_key_names_from_schema(schema_info);
599 let secondary_order_contract = plan.scalar_plan().order.as_ref().and_then(|order| {
600 order.deterministic_secondary_order_contract_fields(primary_key_names.as_slice())
601 });
602
603 PlannerRouteProfile::new(
604 derive_continuation_policy_validated(plan),
605 derive_logical_pushdown_eligibility(plan, secondary_order_contract.as_ref()),
606 secondary_order_contract,
607 )
608}
609
610fn project_static_execution_planning_contract_for_model(
611 model: &EntityModel,
612 schema_info: &SchemaInfo,
613 plan: &AccessPlannedQuery,
614) -> Result<StaticExecutionPlanningContract, InternalError> {
615 let projection_spec = lower_projection_intent(model, &plan.logical, &plan.projection_selection);
616 let execution_preparation_predicate = plan.execution_preparation_predicate();
617 let residual_filter_predicate = derive_residual_filter_predicate_from_preparation(
618 plan,
619 execution_preparation_predicate.as_ref(),
620 );
621 let residual_filter_expr = derive_residual_filter_expr_for_model(model, plan);
622 let effective_runtime_filter_program = compile_effective_runtime_filter_program(
623 schema_info,
624 residual_filter_expr.as_ref(),
625 residual_filter_predicate.as_ref(),
626 )?;
627 let residual_filter_contract = ResidualFilterContract::new(
628 residual_filter_expr,
629 residual_filter_predicate,
630 effective_runtime_filter_program,
631 );
632 let residual_filter_shape = residual_filter_contract.shape();
633 let execution_preparation_compiled_predicate =
634 should_compile_execution_preparation_predicate(residual_filter_shape)
635 .then(|| {
636 compile_optional_predicate(schema_info, execution_preparation_predicate.as_ref())
637 })
638 .flatten();
639 let predicate_pushdown_diagnostics =
640 derive_predicate_pushdown_diagnostics(plan, residual_filter_shape);
641 let scalar_projection_plan = if plan.grouped_plan().is_none() {
642 Some(
643 compile_scalar_projection_plan_with_schema(schema_info, &projection_spec)
644 .ok_or_else(InternalError::query_executor_invariant)?
645 .iter()
646 .map(CompiledExpr::compile)
647 .collect(),
648 )
649 } else {
650 None
651 };
652 let (grouped_aggregate_execution_specs, grouped_distinct_execution_strategy) =
653 resolve_grouped_static_planning_semantics(schema_info, plan, &projection_spec)?;
654 let projection_direct_slots = lower_direct_projection_slots_with_schema(
655 model,
656 schema_info,
657 &plan.logical,
658 &plan.projection_selection,
659 );
660 let projection_data_row_direct_slots = lower_data_row_direct_projection_slots_with_schema(
661 model,
662 schema_info,
663 &plan.logical,
664 &plan.projection_selection,
665 );
666 let projection_referenced_slots =
667 projection_spec.referenced_slots_for_schema(model, schema_info)?;
668 let projected_slot_mask =
669 projected_slot_mask_for_spec(model, projection_direct_slots.as_deref());
670 let projection_is_model_identity = projection_spec.is_model_identity_for(model);
671 let resolved_order = resolved_order_for_plan(schema_info, plan)?;
672 let order_referenced_slots = order_referenced_slots_for_resolved_order(resolved_order.as_ref());
673 let slot_map = slot_map_for_schema_plan(schema_info, plan);
674 let index_compile_targets = index_compile_targets_for_schema_plan(schema_info, plan);
675
676 Ok(StaticExecutionPlanningContract {
677 primary_key_names: schema_info.primary_key_names().to_vec(),
678 projection_spec,
679 execution_preparation_predicate,
680 execution_preparation_compiled_predicate,
681 residual_filter_contract,
682 predicate_pushdown_diagnostics,
683 scalar_projection_plan,
684 grouped_aggregate_execution_specs,
685 grouped_distinct_execution_strategy,
686 projection_direct_slots,
687 projection_data_row_direct_slots,
688 projection_referenced_slots,
689 projected_slot_mask,
690 projection_is_model_identity,
691 resolved_order,
692 order_referenced_slots,
693 slot_map,
694 index_compile_targets,
695 })
696}
697
698#[cfg(test)]
699fn ordered_primary_key_names(model: &EntityModel) -> Vec<&'static str> {
700 model.primary_key_names()
701}
702
703fn primary_key_names_from_schema(schema_info: &SchemaInfo) -> Vec<&str> {
704 schema_info
705 .primary_key_names()
706 .iter()
707 .map(String::as_str)
708 .collect()
709}
710
711fn compile_effective_runtime_filter_program(
715 schema_info: &SchemaInfo,
716 residual_filter_expr: Option<&Expr>,
717 residual_filter_predicate: Option<&Predicate>,
718) -> Result<Option<EffectiveRuntimeFilterProgram>, InternalError> {
719 if let Some(predicate) = residual_filter_predicate {
724 return Ok(Some(EffectiveRuntimeFilterProgram::predicate(
725 PredicateProgram::compile_with_schema_info(schema_info, predicate),
726 )));
727 }
728
729 if let Some(filter_expr) = residual_filter_expr {
730 let compiled = compile_scalar_projection_expr_with_schema(schema_info, filter_expr)
731 .ok_or_else(InternalError::query_invalid_logical_plan)?;
732
733 return Ok(Some(EffectiveRuntimeFilterProgram::expression(
734 CompiledExpr::compile(&compiled),
735 )));
736 }
737
738 Ok(None)
739}
740
741fn derive_execution_preparation_predicate(plan: &AccessPlannedQuery) -> Option<Predicate> {
745 let query_predicate = plan.scalar_plan().predicate.as_ref()?;
746
747 match plan.access.selected_index_contract() {
748 Some(index) => {
749 residual_query_predicate_after_filtered_access_contract(index, query_predicate)
750 }
751 None => Some(query_predicate.clone()),
752 }
753}
754
755fn derive_residual_filter_predicate(plan: &AccessPlannedQuery) -> Option<Predicate> {
759 let filtered_residual = derive_execution_preparation_predicate(plan);
760
761 derive_residual_filter_predicate_from_preparation(plan, filtered_residual.as_ref())
762}
763
764fn derive_residual_filter_predicate_from_preparation(
765 plan: &AccessPlannedQuery,
766 execution_preparation_predicate: Option<&Predicate>,
767) -> Option<Predicate> {
768 let execution_preparation_predicate = execution_preparation_predicate?;
769
770 residual_query_predicate_after_access_path_bounds(
771 plan.access.as_path(),
772 execution_preparation_predicate,
773 )
774}
775
776fn derive_residual_filter_expr(plan: &AccessPlannedQuery) -> Option<Expr> {
780 let filter_expr = plan.scalar_plan().filter_expr.as_ref()?;
781 if derive_semantic_filter_fully_satisfied_by_access_contract(plan) {
782 return None;
783 }
784
785 Some(filter_expr.clone())
786}
787
788fn derive_residual_filter_expr_for_model(
792 model: &EntityModel,
793 plan: &AccessPlannedQuery,
794) -> Option<Expr> {
795 let filter_expr = plan.scalar_plan().filter_expr.as_ref()?;
796 if derive_semantic_filter_fully_satisfied_by_access_contract_for_model(model, plan) {
797 return None;
798 }
799
800 Some(filter_expr.clone())
801}
802
803fn derive_has_residual_filter(plan: &AccessPlannedQuery) -> bool {
807 match (
808 plan.scalar_plan().filter_expr.as_ref(),
809 plan.scalar_plan().predicate.as_ref(),
810 ) {
811 (None, None) => false,
812 (Some(_), None) => true,
813 (Some(_) | None, Some(_)) => !plan.predicate_fully_satisfied_by_access_contract(),
814 }
815}
816
817fn derive_predicate_pushdown_diagnostics(
821 plan: &AccessPlannedQuery,
822 residual_filter_shape: ResidualFilterShape,
823) -> PredicatePushdownDiagnostics {
824 PredicatePushdownDiagnostics::from_plan(
825 plan.scalar_plan().filter_expr.is_some(),
826 plan.scalar_plan().predicate_covers_filter_expr,
827 plan.scalar_plan().predicate.as_ref(),
828 &plan.access,
829 residual_filter_shape,
830 )
831}
832
833fn derive_predicate_fully_satisfied_by_access_contract(plan: &AccessPlannedQuery) -> bool {
836 plan.scalar_plan().predicate.is_some()
837 && derive_residual_filter_predicate(plan).is_none()
838 && derive_residual_filter_expr(plan).is_none()
839}
840
841const fn derive_semantic_filter_fully_satisfied_by_access_contract(
845 plan: &AccessPlannedQuery,
846) -> bool {
847 plan.scalar_plan().filter_expr.is_some()
848 && plan.scalar_plan().predicate.is_some()
849 && plan.scalar_plan().predicate_covers_filter_expr
850}
851
852const fn derive_semantic_filter_fully_satisfied_by_access_contract_for_model(
856 _model: &EntityModel,
857 plan: &AccessPlannedQuery,
858) -> bool {
859 derive_semantic_filter_fully_satisfied_by_access_contract(plan)
860}
861
862fn compile_optional_predicate(
865 schema_info: &SchemaInfo,
866 predicate: Option<&Predicate>,
867) -> Option<PredicateProgram> {
868 predicate.map(|predicate| PredicateProgram::compile_with_schema_info(schema_info, predicate))
869}
870
871const fn should_compile_execution_preparation_predicate(
876 residual_filter_shape: ResidualFilterShape,
877) -> bool {
878 !residual_filter_shape.is_absent()
879}
880
881fn resolve_grouped_static_planning_semantics(
885 schema_info: &SchemaInfo,
886 plan: &AccessPlannedQuery,
887 projection_spec: &ProjectionSpec,
888) -> Result<
889 (
890 Option<Vec<GroupedAggregateExecutionSpec>>,
891 Option<GroupedDistinctExecutionStrategy>,
892 ),
893 InternalError,
894> {
895 let Some(grouped) = plan.grouped_plan() else {
896 return Ok((None, None));
897 };
898
899 let mut aggregate_specs = grouped_aggregate_specs_from_projection_spec(
900 projection_spec,
901 grouped.group.group_fields.as_slice(),
902 grouped.group.aggregates.as_slice(),
903 )?;
904 extend_grouped_having_aggregate_specs(&mut aggregate_specs, grouped)?;
905
906 let grouped_aggregate_execution_specs = Some(grouped_aggregate_execution_specs(
907 schema_info,
908 aggregate_specs.as_slice(),
909 )?);
910 let grouped_distinct_execution_strategy = Some(
911 resolved_grouped_distinct_execution_strategy_with_schema_info(
912 schema_info,
913 grouped.group.group_fields.as_slice(),
914 grouped.group.aggregates.as_slice(),
915 grouped.having_expr.as_ref(),
916 )?,
917 );
918
919 Ok((
920 grouped_aggregate_execution_specs,
921 grouped_distinct_execution_strategy,
922 ))
923}
924
925fn extend_grouped_having_aggregate_specs(
926 aggregate_specs: &mut Vec<GroupedAggregateExecutionSpec>,
927 grouped: &GroupPlan,
928) -> Result<(), InternalError> {
929 if let Some(having_expr) = grouped.having_expr.as_ref() {
930 extend_unique_grouped_aggregate_specs_from_expr(aggregate_specs, having_expr)?;
931 }
932
933 Ok(())
934}
935
936fn projected_slot_mask_for_spec(
937 model: &EntityModel,
938 direct_projection_slots: Option<&[usize]>,
939) -> Vec<bool> {
940 let schema_slot_len = direct_projection_slots
941 .and_then(|slots| slots.iter().copied().max())
942 .map_or(0, |slot| slot.saturating_add(1));
943 let mut projected_slots = vec![false; model.fields().len().max(schema_slot_len)];
944
945 let Some(direct_projection_slots) = direct_projection_slots else {
946 return projected_slots;
947 };
948
949 for slot in direct_projection_slots.iter().copied() {
950 if let Some(projected) = projected_slots.get_mut(slot) {
951 *projected = true;
952 }
953 }
954
955 projected_slots
956}
957
958fn resolved_order_for_plan(
959 schema_info: &SchemaInfo,
960 plan: &AccessPlannedQuery,
961) -> Result<Option<ResolvedOrder>, InternalError> {
962 if grouped_plan_strategy(plan).is_some_and(GroupedPlanStrategy::is_top_k_group) {
963 return Ok(None);
964 }
965
966 let Some(order) = plan.scalar_plan().order.as_ref() else {
967 return Ok(None);
968 };
969
970 let mut fields = Vec::with_capacity(order.fields.len());
971 for term in &order.fields {
972 fields.push(ResolvedOrderField::new(
973 resolved_order_value_source_for_term(schema_info, term)?,
974 term.direction(),
975 ));
976 }
977
978 Ok(Some(ResolvedOrder::new(fields)))
979}
980
981fn resolved_order_value_source_for_term(
982 schema_info: &SchemaInfo,
983 term: &crate::db::query::plan::OrderTerm,
984) -> Result<ResolvedOrderValueSource, InternalError> {
985 if term.direct_field().is_none() {
986 let rendered = term.rendered_label();
987 validate_resolved_order_expr_fields(schema_info, term.expr(), rendered.as_str())?;
988 let compiled = compile_scalar_projection_expr_with_schema(schema_info, term.expr())
989 .ok_or_else(|| order_expression_scalar_seam_error(rendered.as_str()))?;
990
991 return Ok(ResolvedOrderValueSource::expression(CompiledExpr::compile(
992 &compiled,
993 )));
994 }
995
996 let Some(field) = term.direct_field() else {
997 return Err(InternalError::query_invalid_logical_plan());
998 };
999 let slot = resolve_required_schema_slot(
1000 schema_info,
1001 field,
1002 InternalError::query_invalid_logical_plan,
1003 )?;
1004
1005 Ok(ResolvedOrderValueSource::direct_field(slot))
1006}
1007
1008fn validate_resolved_order_expr_fields(
1009 schema_info: &SchemaInfo,
1010 expr: &Expr,
1011 rendered: &str,
1012) -> Result<(), InternalError> {
1013 expr.try_for_each_tree_expr(&mut |node| match node {
1014 Expr::Field(field_id) => resolve_required_schema_slot(
1015 schema_info,
1016 field_id.as_str(),
1017 InternalError::query_invalid_logical_plan,
1018 )
1019 .map(|_| ()),
1020 Expr::Aggregate(_) => Err(order_expression_scalar_seam_error(rendered)),
1021 #[cfg(test)]
1022 Expr::Alias { .. } => Err(order_expression_scalar_seam_error(rendered)),
1023 Expr::Unary { .. } => Err(order_expression_scalar_seam_error(rendered)),
1024 _ => Ok(()),
1025 })
1026}
1027
1028fn resolve_required_schema_slot<F>(
1032 schema_info: &SchemaInfo,
1033 field: &str,
1034 invalid_plan_error: F,
1035) -> Result<usize, InternalError>
1036where
1037 F: FnOnce() -> InternalError,
1038{
1039 schema_info
1040 .field_slot_index(field)
1041 .ok_or_else(invalid_plan_error)
1042}
1043
1044fn order_expression_scalar_seam_error(_rendered: &str) -> InternalError {
1047 InternalError::query_invalid_logical_plan()
1048}
1049
1050fn order_referenced_slots_for_resolved_order(
1055 resolved_order: Option<&ResolvedOrder>,
1056) -> Option<Vec<usize>> {
1057 Some(resolved_order?.referenced_slots())
1058}
1059
1060fn slot_map_for_schema_plan(
1061 schema_info: &SchemaInfo,
1062 plan: &AccessPlannedQuery,
1063) -> Option<Vec<usize>> {
1064 let executable = plan.access.executable_contract();
1065
1066 resolved_index_slots_for_access_path(schema_info, &executable)
1067}
1068
1069fn resolved_index_slots_for_access_path(
1070 schema_info: &SchemaInfo,
1071 access: &ExecutableAccessPlan<'_, crate::value::Value>,
1072) -> Option<Vec<usize>> {
1073 let path = access.as_path()?;
1074 let path_facts = path.shape_facts();
1075 let key_items = path_facts.index_key_items_for_slot_map()?;
1076 let mut slots = Vec::new();
1077
1078 match key_items.key_items() {
1079 SemanticIndexKeyItemsRef::Fields(fields) => {
1080 slots.reserve(fields.len());
1081 for field_name in fields {
1082 let slot = schema_info.field_slot_index(field_name)?;
1083 slots.push(slot);
1084 }
1085 }
1086 SemanticIndexKeyItemsRef::Accepted(items) => {
1087 slots.reserve(items.len());
1088 for key_item in items {
1089 let slot = schema_info.field_slot_index(key_item.as_ref().field())?;
1090 slots.push(slot);
1091 }
1092 }
1093 SemanticIndexKeyItemsRef::Static(IndexKeyItemsRef::Fields(fields)) => {
1094 slots.reserve(fields.len());
1095 for &field_name in fields {
1096 let slot = schema_info.field_slot_index(field_name)?;
1097 slots.push(slot);
1098 }
1099 }
1100 SemanticIndexKeyItemsRef::Static(IndexKeyItemsRef::Items(items)) => {
1101 slots.reserve(items.len());
1102 for key_item in items {
1103 let slot = schema_info.field_slot_index(key_item.field())?;
1104 slots.push(slot);
1105 }
1106 }
1107 }
1108
1109 Some(slots)
1110}
1111
1112fn index_compile_targets_for_schema_plan(
1113 schema_info: &SchemaInfo,
1114 plan: &AccessPlannedQuery,
1115) -> Option<Vec<IndexCompileTarget>> {
1116 let executable = plan.access.executable_contract();
1117 let path = executable.as_path()?;
1118 let key_items = path.shape_facts().index_key_items_for_slot_map()?;
1119 let mut targets = Vec::new();
1120
1121 match key_items.key_items() {
1122 SemanticIndexKeyItemsRef::Fields(_) | SemanticIndexKeyItemsRef::Accepted(_) => {
1123 return None;
1124 }
1125 SemanticIndexKeyItemsRef::Static(IndexKeyItemsRef::Fields(fields)) => {
1126 for (component_index, &field_name) in fields.iter().enumerate() {
1127 let field_slot = schema_info.field_slot_index(field_name)?;
1128 targets.push(IndexCompileTarget {
1129 component_index,
1130 field_slot,
1131 key_item: IndexKeyItem::Field(field_name),
1132 });
1133 }
1134 }
1135 SemanticIndexKeyItemsRef::Static(IndexKeyItemsRef::Items(items)) => {
1136 for (component_index, &key_item) in items.iter().enumerate() {
1137 let field_slot = schema_info.field_slot_index(key_item.field())?;
1138 targets.push(IndexCompileTarget {
1139 component_index,
1140 field_slot,
1141 key_item,
1142 });
1143 }
1144 }
1145 }
1146
1147 Some(targets)
1148}