Skip to main content

icydb_core/db/query/plan/semantics/
logical.rs

1//! Module: query::plan::semantics::logical
2//! Responsibility: logical-plan semantic lowering from planner contracts to access-planned queries.
3//! Does not own: access-path index selection internals or runtime execution behavior.
4//! Boundary: derives planner-owned execution semantics, shape signatures, and continuation policy.
5
6use 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    /// True if this mode represents a load intent.
38    #[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    /// True if this mode represents a delete intent.
47    #[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    /// Borrow scalar semantic fields shared by scalar/grouped logical variants.
58    #[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    /// Borrow scalar semantic fields shared by scalar/grouped logical variants.
69    #[must_use]
70    pub(in crate::db) const fn scalar_plan(&self) -> &ScalarPlan {
71        self.logical.scalar_semantics()
72    }
73
74    /// Borrow scalar missing-row consistency without exposing the full scalar
75    /// plan to executor owners that only need row-presence policy.
76    #[must_use]
77    pub(in crate::db) fn scalar_consistency(&self) -> MissingRowPolicy {
78        if self.access.has_selected_index_access_path() {
79            // An accepted secondary index is a persisted claim that every
80            // emitted key identifies an authoritative row. Ignoring a missing
81            // row would turn accepted-index corruption into an incomplete
82            // successful result.
83            MissingRowPolicy::Error
84        } else {
85            self.scalar_plan().consistency
86        }
87    }
88
89    /// Borrow grouped semantic fields when this plan is grouped.
90    #[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    /// Lower this plan through accepted schema projection authority.
99    #[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    /// Lower this plan into one projection semantic shape for identity hashing.
109    #[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    /// Return the executor-facing predicate after removing only filtered-index
115    /// guard clauses the chosen access path already proves.
116    ///
117    /// This conservative form is used by preparation/explain surfaces that
118    /// still need to see access-bound equalities as index-predicate input.
119    #[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    /// Return the executor-facing residual predicate after removing any
129    /// filtered-index guard clauses and fixed access-bound equalities already
130    /// guaranteed by the chosen path.
131    #[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    /// Return whether one explicit residual predicate survives access
144    /// planning and still participates in residual execution.
145    #[must_use]
146    pub(in crate::db) fn has_residual_filter_predicate(&self) -> bool {
147        self.effective_execution_predicate().is_some()
148    }
149
150    /// Borrow the planner-owned residual scalar filter expression when one
151    /// surviving semantic remainder still requires runtime evaluation.
152    #[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    /// Return whether one explicit residual scalar filter expression survives
168    /// access planning and still requires runtime evaluation.
169    #[must_use]
170    pub(in crate::db) fn has_residual_filter_expr(&self) -> bool {
171        self.residual_filter_expr().is_some()
172    }
173
174    /// Return the planner-owned residual-filter shape used by diagnostics.
175    #[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        // Normalize pre-finalization candidate shells to the same execution
182        // shape later frozen in the static contract. A filter expression fully
183        // represented by its predicate executes through that predicate, not a
184        // second expression program.
185        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    /// Return the planner-owned predicate pushdown label consumed by verbose
194    /// execution diagnostics.
195    #[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    /// Return planner-owned predicate-pushdown diagnostics.
202    #[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    /// Return the planner-owned predicate-pushdown outcome label.
213    #[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    /// Return the planner-owned predicate-pushdown reason label.
220    #[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    /// Borrow the planner-compiled execution-preparation predicate program.
227    #[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    /// Borrow the planner-compiled effective runtime predicate program.
237    #[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    /// Borrow the planner-frozen effective runtime scalar filter program.
250    #[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    /// Lower scalar DISTINCT semantics into one executor-facing execution strategy.
260    #[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        // DISTINCT on duplicate-safe single-path access shapes is a planner
267        // no-op for runtime dedup mechanics. Composite shapes can surface
268        // duplicate keys and therefore retain explicit dedup execution.
269        match distinct_runtime_dedup_strategy(&self.access) {
270            Some(strategy) => strategy,
271            None => DistinctExecutionStrategy::None,
272        }
273    }
274
275    /// Freeze one planner-owned route profile from accepted schema authority.
276    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    /// Freeze planner-owned executor metadata with explicit schema authority.
284    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    // Resolve authoring-time group field names onto accepted slots before the
297    // plan becomes executable.
298    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    /// Build one immutable execution-shape signature contract for runtime layers.
317    #[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    /// Return whether the chosen access contract fully satisfies the current
326    /// scalar query predicate without any additional runtime residual filtering.
327    #[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    /// Borrow the planner-frozen compiled scalar projection program.
340    #[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    /// Return whether planner-owned static execution metadata has already been frozen.
348    #[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    /// Borrow the planner-frozen ordered primary-key field names.
354    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    /// Borrow the planner-frozen projection slot reachability set.
364    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    /// Borrow the planner-frozen mask for direct projected output slots.
372    #[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    /// Return whether projection remains the full model-identity field list.
381    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    /// Borrow the planner-frozen ORDER BY slot reachability set, if any.
388    #[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    /// Borrow the planner-frozen resolved ORDER BY program, if one exists.
396    #[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    /// Borrow the planner-frozen access slot map used by index predicate compilation.
404    #[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    /// Borrow grouped aggregate execution specs already resolved during static planning.
412    #[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    /// Borrow the planner-resolved grouped DISTINCT execution strategy when present.
422    #[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    /// Borrow the frozen projection semantic shape without reopening model ownership.
432    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    /// Borrow the frozen direct projection slots without reopening model ownership.
439    #[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    /// Borrow duplicate-preserving direct projection slots for raw data-row readers.
447    #[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    /// Borrow the planner-frozen key-item-aware compile targets for the chosen access path.
455    #[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, // Continuation resume windows require anchor semantics for pushdown-safe replay.
494        true, // Continuation resumes must advance strictly to prevent replay/regression loops.
495        is_grouped_safe,
496    )
497}
498
499/// Project one planner-owned route profile from accepted schema authority.
500#[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
609// Compile the executor-owned residual scalar filter contract once from the
610// planner-derived residual artifacts so runtime never has to rediscover
611// residual presence or shape from semantic/filter/pushdown state.
612fn 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    // Keep the existing predicate fast path when the residual semantics still
618    // fit the derived predicate contract. The expression-owned lane is only
619    // needed once pushdown loses semantic coverage and a residual predicate no
620    // longer exists.
621    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
639// Derive the executor-preparation predicate once from the selected access path.
640// This strips only filtered-index guard clauses while preserving access-bound
641// equalities that still matter to preparation/explain consumers.
642fn 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
653// Derive the final residual predicate once from the already-filtered
654// preparation predicate plus any equality bounds guaranteed by the concrete
655// access path.
656fn 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
679// Derive the explicit residual semantic expression once for finalized plans.
680// The residual expression remains the planner-owned semantic filter when any
681// runtime filtering still survives access satisfaction.
682fn 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
694// Nested-path predicate shells are planner facts only: the predicate runtime
695// addresses top-level row slots. Keep the already-compiled expression as the
696// execution authority unless the selected access path proves the predicate in
697// full and no runtime filter remains.
698fn 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
715// Return whether any residual filtering survives after access planning. This
716// helper exists only for pre-finalization assembly; finalized plans must read
717// the explicit residual artifacts frozen in `StaticExecutionPlanningContract`.
718fn 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
729// Freeze predicate-pushdown diagnostics from one logical plan shape. This keeps
730// lazy plan accessors and finalized static planning on the same argument
731// contract while leaving route selection and residual filtering unchanged.
732fn 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
745// Return true when the planner-owned predicate contract is fully satisfied by
746// access planning and no semantic residual filter expression survives.
747fn 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
753// Return true when the semantic filter expression is entirely represented by
754// the planner-owned predicate contract and the chosen access path satisfies
755// that predicate without any runtime remainder.
756const 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
764// Compile one optional planner-frozen predicate program while keeping the
765// static planning assembly path free of repeated `Option` mapping boilerplate.
766fn 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
773// Avoid compiling large access-proven predicates into executor preparation.
774// When no residual filter survives, the chosen access route already enforces
775// the predicate and route/explain consumers can use the explicit residual
776// contract instead of recompiling access-bound literals.
777const fn should_compile_execution_preparation_predicate(
778    residual_filter_shape: ResidualFilterShape,
779) -> bool {
780    !residual_filter_shape.is_absent()
781}
782
783// Resolve the grouped-only static planning semantics bundle once so grouped
784// aggregate execution specs and grouped DISTINCT strategy stay derived under
785// one shared grouped-plan branch.
786fn 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
936// Resolve one schema-authoritative field slot while keeping planner
937// invalid-logical-plan error construction at the callsite that owns the
938// diagnostic wording.
939fn 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
952// Keep the scalar-order expression seam violation text under one helper so the
953// parse validation and compile validation paths do not drift.
954fn order_expression_scalar_seam_error(_rendered: &str) -> InternalError {
955    InternalError::query_invalid_logical_plan()
956}
957
958// Keep one stable executor-facing slot list for grouped order terms after the
959// planner has frozen the structural `ResolvedOrder`. The grouped Top-K route
960// now consumes this same referenced-slot contract instead of re-deriving order
961// sources from planner strategy at runtime.
962fn 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}