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, FieldSlot, 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        ResidualFilterShape::from_presence(
182            self.residual_filter_expr().is_some(),
183            self.effective_execution_predicate().is_some(),
184        )
185    }
186
187    /// Return the planner-owned predicate pushdown label consumed by verbose
188    /// execution diagnostics.
189    #[must_use]
190    #[cfg(feature = "sql")]
191    pub(in crate::db) fn predicate_pushdown_label(&self) -> String {
192        self.predicate_pushdown_diagnostics().label()
193    }
194
195    /// Return planner-owned predicate-pushdown diagnostics.
196    #[must_use]
197    #[cfg(feature = "sql")]
198    pub(in crate::db) fn predicate_pushdown_diagnostics(&self) -> PredicatePushdownDiagnostics {
199        if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
200            return static_contract.predicate_pushdown_diagnostics;
201        }
202
203        derive_predicate_pushdown_diagnostics(self, self.residual_filter_shape())
204    }
205
206    /// Return the planner-owned predicate-pushdown outcome label.
207    #[must_use]
208    #[cfg(feature = "sql")]
209    pub(in crate::db) fn predicate_pushdown_outcome_label(&self) -> &'static str {
210        self.predicate_pushdown_diagnostics().outcome_label()
211    }
212
213    /// Return the planner-owned predicate-pushdown reason label.
214    #[must_use]
215    #[cfg(feature = "sql")]
216    pub(in crate::db) fn predicate_pushdown_reason_label(&self) -> &'static str {
217        self.predicate_pushdown_diagnostics().reason_label()
218    }
219
220    /// Borrow the planner-compiled execution-preparation predicate program.
221    #[must_use]
222    pub(in crate::db) fn execution_preparation_compiled_predicate(
223        &self,
224    ) -> Option<&PredicateProgram> {
225        self.static_execution_planning_contract()?
226            .execution_preparation_compiled_predicate
227            .as_ref()
228    }
229
230    /// Borrow the planner-compiled effective runtime predicate program.
231    #[must_use]
232    pub(in crate::db) fn effective_runtime_compiled_predicate(&self) -> Option<&PredicateProgram> {
233        match self
234            .static_execution_planning_contract()?
235            .residual_filter_contract
236            .effective_runtime_filter_program()
237        {
238            Some(program) => program.predicate_program(),
239            None => None,
240        }
241    }
242
243    /// Borrow the planner-frozen effective runtime scalar filter program.
244    #[must_use]
245    pub(in crate::db) fn effective_runtime_filter_program(
246        &self,
247    ) -> Option<&EffectiveRuntimeFilterProgram> {
248        self.static_execution_planning_contract()?
249            .residual_filter_contract
250            .effective_runtime_filter_program()
251    }
252
253    /// Lower scalar DISTINCT semantics into one executor-facing execution strategy.
254    #[must_use]
255    pub(in crate::db) fn distinct_execution_strategy(&self) -> DistinctExecutionStrategy {
256        if !self.scalar_plan().distinct {
257            return DistinctExecutionStrategy::None;
258        }
259
260        // DISTINCT on duplicate-safe single-path access shapes is a planner
261        // no-op for runtime dedup mechanics. Composite shapes can surface
262        // duplicate keys and therefore retain explicit dedup execution.
263        match distinct_runtime_dedup_strategy(&self.access) {
264            Some(strategy) => strategy,
265            None => DistinctExecutionStrategy::None,
266        }
267    }
268
269    /// Freeze one planner-owned route profile from accepted schema authority.
270    pub(in crate::db) fn finalize_planner_route_profile_for_model_with_schema(
271        &mut self,
272        schema_info: &SchemaInfo,
273    ) {
274        self.set_planner_route_profile(project_planner_route_profile_for_schema(schema_info, self));
275    }
276
277    /// Freeze planner-owned executor metadata with explicit schema authority.
278    pub(in crate::db) fn finalize_static_execution_planning_contract_with_schema(
279        &mut self,
280        schema_info: &SchemaInfo,
281    ) -> Result<(), InternalError> {
282        self.bind_group_field_slots_to_schema(schema_info)?;
283        self.static_execution_planning_contract = Some(
284            project_static_execution_planning_contract_with_schema(schema_info, self)?,
285        );
286
287        Ok(())
288    }
289
290    // Resolve authoring-time group field names onto accepted slots before the
291    // plan becomes executable.
292    fn bind_group_field_slots_to_schema(
293        &mut self,
294        schema_info: &SchemaInfo,
295    ) -> Result<(), InternalError> {
296        let LogicalPlan::Grouped(grouped) = &mut self.logical else {
297            return Ok(());
298        };
299
300        let accepted_slots = grouped
301            .group
302            .group_fields
303            .iter()
304            .map(|field_slot| FieldSlot::resolve_with_schema(schema_info, field_slot.field()))
305            .collect::<Option<Vec<_>>>()
306            .ok_or_else(InternalError::planner_executor_invariant)?;
307        grouped.group.group_fields = accepted_slots;
308
309        Ok(())
310    }
311
312    /// Build one immutable execution-shape signature contract for runtime layers.
313    #[must_use]
314    pub(in crate::db) fn execution_shape_signature(
315        &self,
316        entity_path: &str,
317    ) -> ExecutionShapeSignature {
318        ExecutionShapeSignature::new(self.continuation_signature(entity_path))
319    }
320
321    /// Return whether the chosen access contract fully satisfies the current
322    /// scalar query predicate without any additional runtime residual filtering.
323    #[must_use]
324    pub(in crate::db) fn predicate_fully_satisfied_by_access_contract(&self) -> bool {
325        if let Some(static_contract) = self.static_execution_planning_contract.as_ref() {
326            return self.scalar_plan().predicate.is_some()
327                && !static_contract
328                    .residual_filter_contract
329                    .has_residual_filter();
330        }
331
332        derive_predicate_fully_satisfied_by_access_contract(self)
333    }
334
335    /// Borrow the planner-frozen compiled scalar projection program.
336    #[must_use]
337    pub(in crate::db) fn scalar_projection_plan(&self) -> Option<&[CompiledExpr]> {
338        self.static_execution_planning_contract()?
339            .scalar_projection_plan
340            .as_deref()
341    }
342
343    /// Return whether planner-owned static execution metadata has already been frozen.
344    #[must_use]
345    pub(in crate::db) const fn has_static_execution_planning_contract(&self) -> bool {
346        self.static_execution_planning_contract.is_some()
347    }
348
349    /// Borrow the planner-frozen ordered primary-key field names.
350    pub(in crate::db) fn primary_key_names(&self) -> Result<Vec<&str>, InternalError> {
351        Ok(self
352            .require_static_execution_planning_contract()?
353            .primary_key_names
354            .iter()
355            .map(String::as_str)
356            .collect())
357    }
358
359    /// Borrow the planner-frozen projection slot reachability set.
360    pub(in crate::db) fn projection_referenced_slots(&self) -> Result<&[usize], InternalError> {
361        Ok(self
362            .require_static_execution_planning_contract()?
363            .projection_referenced_slots
364            .as_slice())
365    }
366
367    /// Borrow the planner-frozen mask for direct projected output slots.
368    #[cfg(any(test, feature = "diagnostics"))]
369    pub(in crate::db) fn projected_slot_mask(&self) -> Result<&[bool], InternalError> {
370        Ok(self
371            .require_static_execution_planning_contract()?
372            .projected_slot_mask
373            .as_slice())
374    }
375
376    /// Return whether projection remains the full model-identity field list.
377    pub(in crate::db) fn projection_is_model_identity(&self) -> Result<bool, InternalError> {
378        Ok(self
379            .require_static_execution_planning_contract()?
380            .projection_is_model_identity)
381    }
382
383    /// Borrow the planner-frozen ORDER BY slot reachability set, if any.
384    #[must_use]
385    pub(in crate::db) fn order_referenced_slots(&self) -> Option<&[usize]> {
386        self.static_execution_planning_contract()?
387            .order_referenced_slots
388            .as_deref()
389    }
390
391    /// Borrow the planner-frozen resolved ORDER BY program, if one exists.
392    #[must_use]
393    pub(in crate::db) fn resolved_order(&self) -> Option<&ResolvedOrder> {
394        self.static_execution_planning_contract()?
395            .resolved_order
396            .as_ref()
397    }
398
399    /// Borrow the planner-frozen access slot map used by index predicate compilation.
400    #[must_use]
401    pub(in crate::db) fn slot_map(&self) -> Option<&[usize]> {
402        self.static_execution_planning_contract()?
403            .slot_map
404            .as_deref()
405    }
406
407    /// Borrow grouped aggregate execution specs already resolved during static planning.
408    #[must_use]
409    pub(in crate::db) fn grouped_aggregate_execution_specs(
410        &self,
411    ) -> Option<&[GroupedAggregateExecutionSpec]> {
412        self.static_execution_planning_contract()?
413            .grouped_aggregate_execution_specs
414            .as_deref()
415    }
416
417    /// Borrow the planner-resolved grouped DISTINCT execution strategy when present.
418    #[must_use]
419    pub(in crate::db) fn grouped_distinct_execution_strategy(
420        &self,
421    ) -> Option<&GroupedDistinctExecutionStrategy> {
422        self.static_execution_planning_contract()?
423            .grouped_distinct_execution_strategy
424            .as_ref()
425    }
426
427    /// Borrow the frozen projection semantic shape without reopening model ownership.
428    pub(in crate::db) fn frozen_projection_spec(&self) -> Result<&ProjectionSpec, InternalError> {
429        Ok(&self
430            .require_static_execution_planning_contract()?
431            .projection_spec)
432    }
433
434    /// Borrow the frozen direct projection slots without reopening model ownership.
435    #[must_use]
436    pub(in crate::db) fn frozen_direct_projection_slots(&self) -> Option<&[usize]> {
437        self.static_execution_planning_contract()?
438            .projection_direct_slots
439            .as_deref()
440    }
441
442    /// Borrow duplicate-preserving direct projection slots for raw data-row readers.
443    #[must_use]
444    pub(in crate::db) fn frozen_data_row_direct_projection_slots(&self) -> Option<&[usize]> {
445        self.static_execution_planning_contract()?
446            .projection_data_row_direct_slots
447            .as_deref()
448    }
449
450    /// Borrow the planner-frozen key-item-aware compile targets for the chosen access path.
451    #[must_use]
452    pub(in crate::db) fn index_compile_targets(&self) -> Option<&[IndexCompileTarget]> {
453        self.static_execution_planning_contract()?
454            .index_compile_targets
455            .as_deref()
456    }
457
458    const fn static_execution_planning_contract(&self) -> Option<&StaticExecutionPlanningContract> {
459        self.static_execution_planning_contract.as_ref()
460    }
461
462    fn require_static_execution_planning_contract(
463        &self,
464    ) -> Result<&StaticExecutionPlanningContract, InternalError> {
465        self.static_execution_planning_contract
466            .as_ref()
467            .ok_or_else(InternalError::query_executor_invariant)
468    }
469}
470
471fn distinct_runtime_dedup_strategy<K>(access: &AccessPlan<K>) -> Option<DistinctExecutionStrategy> {
472    match access {
473        AccessPlan::Union(_) | AccessPlan::Intersection(_) => {
474            Some(DistinctExecutionStrategy::PreOrdered)
475        }
476        AccessPlan::Path(path) if path.as_ref().is_index_multi_lookup() => {
477            Some(DistinctExecutionStrategy::HashMaterialize)
478        }
479        AccessPlan::Path(_) => None,
480    }
481}
482
483fn derive_continuation_policy_validated(plan: &AccessPlannedQuery) -> ContinuationPolicy {
484    let is_grouped_safe = plan
485        .grouped_plan()
486        .is_none_or(|grouped| grouped_cursor_policy_violation(grouped, true).is_none());
487
488    ContinuationPolicy::new(
489        true, // Continuation resume windows require anchor semantics for pushdown-safe replay.
490        true, // Continuation resumes must advance strictly to prevent replay/regression loops.
491        is_grouped_safe,
492    )
493}
494
495/// Project one planner-owned route profile from accepted schema authority.
496#[must_use]
497pub(in crate::db) fn project_planner_route_profile_for_schema(
498    schema_info: &SchemaInfo,
499    plan: &AccessPlannedQuery,
500) -> PlannerRouteProfile {
501    let primary_key_names = primary_key_names_from_schema(schema_info);
502    let secondary_order_contract = plan.scalar_plan().order.as_ref().and_then(|order| {
503        order.deterministic_secondary_order_contract_fields(primary_key_names.as_slice())
504    });
505
506    PlannerRouteProfile::new(
507        derive_continuation_policy_validated(plan),
508        derive_logical_pushdown_eligibility(plan, secondary_order_contract.as_ref()),
509        secondary_order_contract,
510    )
511}
512
513fn project_static_execution_planning_contract_with_schema(
514    schema_info: &SchemaInfo,
515    plan: &AccessPlannedQuery,
516) -> Result<StaticExecutionPlanningContract, InternalError> {
517    let projection_spec =
518        lower_projection_intent_with_schema(schema_info, &plan.logical, &plan.projection_selection);
519    let execution_preparation_predicate = plan.execution_preparation_predicate();
520    let residual_filter_predicate = derive_residual_filter_predicate_from_preparation(
521        plan,
522        execution_preparation_predicate.as_ref(),
523    );
524    let residual_filter_expr = derive_residual_filter_expr(plan);
525    let effective_runtime_filter_program = compile_effective_runtime_filter_program(
526        schema_info,
527        residual_filter_expr.as_ref(),
528        residual_filter_predicate.as_ref(),
529    )?;
530    let residual_filter_contract = ResidualFilterContract::new(
531        residual_filter_expr,
532        residual_filter_predicate,
533        effective_runtime_filter_program,
534    );
535    let residual_filter_shape = residual_filter_contract.shape();
536    let execution_preparation_compiled_predicate =
537        should_compile_execution_preparation_predicate(residual_filter_shape)
538            .then(|| {
539                compile_optional_predicate(schema_info, execution_preparation_predicate.as_ref())
540            })
541            .flatten();
542    let predicate_pushdown_diagnostics =
543        derive_predicate_pushdown_diagnostics(plan, residual_filter_shape);
544    let scalar_projection_plan = if plan.grouped_plan().is_none() {
545        Some(
546            compile_scalar_projection_plan_with_schema(schema_info, &projection_spec)
547                .ok_or_else(InternalError::query_executor_invariant)?
548                .iter()
549                .map(CompiledExpr::compile)
550                .collect(),
551        )
552    } else {
553        None
554    };
555    let (grouped_aggregate_execution_specs, grouped_distinct_execution_strategy) =
556        resolve_grouped_static_planning_semantics(schema_info, plan, &projection_spec)?;
557    let projection_direct_slots = lower_direct_projection_slots_with_schema(
558        schema_info,
559        &plan.logical,
560        &plan.projection_selection,
561    );
562    let projection_data_row_direct_slots = lower_data_row_direct_projection_slots_with_schema(
563        schema_info,
564        &plan.logical,
565        &plan.projection_selection,
566    );
567    let projection_referenced_slots = projection_spec.referenced_slots_for_schema(schema_info)?;
568    let projected_slot_mask =
569        projected_slot_mask_for_spec(schema_info, projection_direct_slots.as_deref());
570    let projection_is_model_identity = projection_spec.is_schema_identity_for(schema_info);
571    let resolved_order = resolved_order_for_plan(schema_info, plan)?;
572    let order_referenced_slots = order_referenced_slots_for_resolved_order(resolved_order.as_ref());
573    let slot_map = slot_map_for_schema_plan(schema_info, plan);
574    let index_compile_targets = index_compile_targets_for_schema_plan(schema_info, plan);
575
576    Ok(StaticExecutionPlanningContract {
577        primary_key_names: schema_info.primary_key_names().to_vec(),
578        projection_spec,
579        execution_preparation_predicate,
580        execution_preparation_compiled_predicate,
581        residual_filter_contract,
582        predicate_pushdown_diagnostics,
583        scalar_projection_plan,
584        grouped_aggregate_execution_specs,
585        grouped_distinct_execution_strategy,
586        projection_direct_slots,
587        projection_data_row_direct_slots,
588        projection_referenced_slots,
589        projected_slot_mask,
590        projection_is_model_identity,
591        resolved_order,
592        order_referenced_slots,
593        slot_map,
594        index_compile_targets,
595    })
596}
597
598fn primary_key_names_from_schema(schema_info: &SchemaInfo) -> Vec<&str> {
599    schema_info
600        .primary_key_names()
601        .iter()
602        .map(String::as_str)
603        .collect()
604}
605
606// Compile the executor-owned residual scalar filter contract once from the
607// planner-derived residual artifacts so runtime never has to rediscover
608// residual presence or shape from semantic/filter/pushdown state.
609fn compile_effective_runtime_filter_program(
610    schema_info: &SchemaInfo,
611    residual_filter_expr: Option<&Expr>,
612    residual_filter_predicate: Option<&Predicate>,
613) -> Result<Option<EffectiveRuntimeFilterProgram>, InternalError> {
614    // Keep the existing predicate fast path when the residual semantics still
615    // fit the derived predicate contract. The expression-owned lane is only
616    // needed once pushdown loses semantic coverage and a residual predicate no
617    // longer exists.
618    if let Some(predicate) = residual_filter_predicate {
619        return Ok(Some(EffectiveRuntimeFilterProgram::predicate(
620            PredicateProgram::compile_with_schema_info(schema_info, predicate),
621        )));
622    }
623
624    if let Some(filter_expr) = residual_filter_expr {
625        let compiled = compile_scalar_projection_expr_with_schema(schema_info, filter_expr)
626            .ok_or_else(InternalError::query_invalid_logical_plan)?;
627
628        return Ok(Some(EffectiveRuntimeFilterProgram::expression(
629            CompiledExpr::compile(&compiled),
630        )));
631    }
632
633    Ok(None)
634}
635
636// Derive the executor-preparation predicate once from the selected access path.
637// This strips only filtered-index guard clauses while preserving access-bound
638// equalities that still matter to preparation/explain consumers.
639fn derive_execution_preparation_predicate(plan: &AccessPlannedQuery) -> Option<Predicate> {
640    let query_predicate = plan.scalar_plan().predicate.as_ref()?;
641
642    match plan.access.selected_index_contract() {
643        Some(index) => {
644            residual_query_predicate_after_filtered_access_contract(index, query_predicate)
645        }
646        None => Some(query_predicate.clone()),
647    }
648}
649
650// Derive the final residual predicate once from the already-filtered
651// preparation predicate plus any equality bounds guaranteed by the concrete
652// access path.
653fn derive_residual_filter_predicate(plan: &AccessPlannedQuery) -> Option<Predicate> {
654    let filtered_residual = derive_execution_preparation_predicate(plan);
655
656    derive_residual_filter_predicate_from_preparation(plan, filtered_residual.as_ref())
657}
658
659fn derive_residual_filter_predicate_from_preparation(
660    plan: &AccessPlannedQuery,
661    execution_preparation_predicate: Option<&Predicate>,
662) -> Option<Predicate> {
663    let execution_preparation_predicate = execution_preparation_predicate?;
664
665    residual_query_predicate_after_access_path_bounds(
666        plan.access.as_path(),
667        execution_preparation_predicate,
668    )
669}
670
671// Derive the explicit residual semantic expression once for finalized plans.
672// The residual expression remains the planner-owned semantic filter when any
673// runtime filtering still survives access satisfaction.
674fn derive_residual_filter_expr(plan: &AccessPlannedQuery) -> Option<Expr> {
675    let filter_expr = plan.scalar_plan().filter_expr.as_ref()?;
676    if derive_semantic_filter_fully_satisfied_by_access_contract(plan) {
677        return None;
678    }
679
680    Some(filter_expr.clone())
681}
682
683// Return whether any residual filtering survives after access planning. This
684// helper exists only for pre-finalization assembly; finalized plans must read
685// the explicit residual artifacts frozen in `StaticExecutionPlanningContract`.
686fn derive_has_residual_filter(plan: &AccessPlannedQuery) -> bool {
687    match (
688        plan.scalar_plan().filter_expr.as_ref(),
689        plan.scalar_plan().predicate.as_ref(),
690    ) {
691        (None, None) => false,
692        (Some(_), None) => true,
693        (Some(_) | None, Some(_)) => !plan.predicate_fully_satisfied_by_access_contract(),
694    }
695}
696
697// Freeze predicate-pushdown diagnostics from one logical plan shape. This keeps
698// lazy plan accessors and finalized static planning on the same argument
699// contract while leaving route selection and residual filtering unchanged.
700fn derive_predicate_pushdown_diagnostics(
701    plan: &AccessPlannedQuery,
702    residual_filter_shape: ResidualFilterShape,
703) -> PredicatePushdownDiagnostics {
704    PredicatePushdownDiagnostics::from_plan(
705        plan.scalar_plan().filter_expr.is_some(),
706        plan.scalar_plan().predicate_covers_filter_expr,
707        plan.scalar_plan().predicate.as_ref(),
708        &plan.access,
709        residual_filter_shape,
710    )
711}
712
713// Return true when the planner-owned predicate contract is fully satisfied by
714// access planning and no semantic residual filter expression survives.
715fn derive_predicate_fully_satisfied_by_access_contract(plan: &AccessPlannedQuery) -> bool {
716    plan.scalar_plan().predicate.is_some()
717        && derive_residual_filter_predicate(plan).is_none()
718        && derive_residual_filter_expr(plan).is_none()
719}
720
721// Return true when the semantic filter expression is entirely represented by
722// the planner-owned predicate contract and the chosen access path satisfies
723// that predicate without any runtime remainder.
724const fn derive_semantic_filter_fully_satisfied_by_access_contract(
725    plan: &AccessPlannedQuery,
726) -> bool {
727    plan.scalar_plan().filter_expr.is_some()
728        && plan.scalar_plan().predicate.is_some()
729        && plan.scalar_plan().predicate_covers_filter_expr
730}
731
732// Compile one optional planner-frozen predicate program while keeping the
733// static planning assembly path free of repeated `Option` mapping boilerplate.
734fn compile_optional_predicate(
735    schema_info: &SchemaInfo,
736    predicate: Option<&Predicate>,
737) -> Option<PredicateProgram> {
738    predicate.map(|predicate| PredicateProgram::compile_with_schema_info(schema_info, predicate))
739}
740
741// Avoid compiling large access-proven predicates into executor preparation.
742// When no residual filter survives, the chosen access route already enforces
743// the predicate and route/explain consumers can use the explicit residual
744// contract instead of recompiling access-bound literals.
745const fn should_compile_execution_preparation_predicate(
746    residual_filter_shape: ResidualFilterShape,
747) -> bool {
748    !residual_filter_shape.is_absent()
749}
750
751// Resolve the grouped-only static planning semantics bundle once so grouped
752// aggregate execution specs and grouped DISTINCT strategy stay derived under
753// one shared grouped-plan branch.
754fn resolve_grouped_static_planning_semantics(
755    schema_info: &SchemaInfo,
756    plan: &AccessPlannedQuery,
757    projection_spec: &ProjectionSpec,
758) -> Result<
759    (
760        Option<Vec<GroupedAggregateExecutionSpec>>,
761        Option<GroupedDistinctExecutionStrategy>,
762    ),
763    InternalError,
764> {
765    let Some(grouped) = plan.grouped_plan() else {
766        return Ok((None, None));
767    };
768
769    let mut aggregate_specs = grouped_aggregate_specs_from_projection_spec(
770        projection_spec,
771        grouped.group.group_fields.as_slice(),
772        grouped.group.aggregates.as_slice(),
773    )?;
774    extend_grouped_having_aggregate_specs(&mut aggregate_specs, grouped)?;
775
776    let grouped_aggregate_execution_specs = Some(grouped_aggregate_execution_specs(
777        schema_info,
778        aggregate_specs.as_slice(),
779    )?);
780    let grouped_distinct_execution_strategy = Some(
781        resolved_grouped_distinct_execution_strategy_with_schema_info(
782            schema_info,
783            grouped.group.group_fields.as_slice(),
784            grouped.group.aggregates.as_slice(),
785            grouped.having_expr.as_ref(),
786        )?,
787    );
788
789    Ok((
790        grouped_aggregate_execution_specs,
791        grouped_distinct_execution_strategy,
792    ))
793}
794
795fn extend_grouped_having_aggregate_specs(
796    aggregate_specs: &mut Vec<GroupedAggregateExecutionSpec>,
797    grouped: &GroupPlan,
798) -> Result<(), InternalError> {
799    if let Some(having_expr) = grouped.having_expr.as_ref() {
800        extend_unique_grouped_aggregate_specs_from_expr(aggregate_specs, having_expr)?;
801    }
802
803    Ok(())
804}
805
806fn projected_slot_mask_for_spec(
807    schema_info: &SchemaInfo,
808    direct_projection_slots: Option<&[usize]>,
809) -> Vec<bool> {
810    let schema_slot_len = direct_projection_slots
811        .and_then(|slots| slots.iter().copied().max())
812        .map_or(0, |slot| slot.saturating_add(1));
813    let mut projected_slots = vec![
814        false;
815        schema_info
816            .field_names_in_slot_order()
817            .len()
818            .max(schema_slot_len)
819    ];
820
821    let Some(direct_projection_slots) = direct_projection_slots else {
822        return projected_slots;
823    };
824
825    for slot in direct_projection_slots.iter().copied() {
826        if let Some(projected) = projected_slots.get_mut(slot) {
827            *projected = true;
828        }
829    }
830
831    projected_slots
832}
833
834fn resolved_order_for_plan(
835    schema_info: &SchemaInfo,
836    plan: &AccessPlannedQuery,
837) -> Result<Option<ResolvedOrder>, InternalError> {
838    if grouped_plan_strategy(plan).is_some_and(GroupedPlanStrategy::is_top_k_group) {
839        return Ok(None);
840    }
841
842    let Some(order) = plan.scalar_plan().order.as_ref() else {
843        return Ok(None);
844    };
845
846    let mut fields = Vec::with_capacity(order.fields.len());
847    for term in &order.fields {
848        fields.push(ResolvedOrderField::new(
849            resolved_order_value_source_for_term(schema_info, term)?,
850            term.direction(),
851        ));
852    }
853
854    Ok(Some(ResolvedOrder::new(fields)))
855}
856
857fn resolved_order_value_source_for_term(
858    schema_info: &SchemaInfo,
859    term: &crate::db::query::plan::OrderTerm,
860) -> Result<ResolvedOrderValueSource, InternalError> {
861    if term.direct_field().is_none() {
862        let rendered = term.rendered_label();
863        validate_resolved_order_expr_fields(schema_info, term.expr(), rendered.as_str())?;
864        let compiled = compile_scalar_projection_expr_with_schema(schema_info, term.expr())
865            .ok_or_else(|| order_expression_scalar_seam_error(rendered.as_str()))?;
866
867        return Ok(ResolvedOrderValueSource::expression(CompiledExpr::compile(
868            &compiled,
869        )));
870    }
871
872    let Some(field) = term.direct_field() else {
873        return Err(InternalError::query_invalid_logical_plan());
874    };
875    let slot = resolve_required_schema_slot(
876        schema_info,
877        field,
878        InternalError::query_invalid_logical_plan,
879    )?;
880
881    Ok(ResolvedOrderValueSource::direct_field(slot))
882}
883
884fn validate_resolved_order_expr_fields(
885    schema_info: &SchemaInfo,
886    expr: &Expr,
887    rendered: &str,
888) -> Result<(), InternalError> {
889    expr.try_for_each_tree_expr(&mut |node| match node {
890        Expr::Field(field_id) => resolve_required_schema_slot(
891            schema_info,
892            field_id.as_str(),
893            InternalError::query_invalid_logical_plan,
894        )
895        .map(|_| ()),
896        Expr::Aggregate(_) => Err(order_expression_scalar_seam_error(rendered)),
897        #[cfg(test)]
898        Expr::Alias { .. } => Err(order_expression_scalar_seam_error(rendered)),
899        Expr::Unary { .. } => Err(order_expression_scalar_seam_error(rendered)),
900        _ => Ok(()),
901    })
902}
903
904// Resolve one schema-authoritative field slot while keeping planner
905// invalid-logical-plan error construction at the callsite that owns the
906// diagnostic wording.
907fn resolve_required_schema_slot<F>(
908    schema_info: &SchemaInfo,
909    field: &str,
910    invalid_plan_error: F,
911) -> Result<usize, InternalError>
912where
913    F: FnOnce() -> InternalError,
914{
915    schema_info
916        .field_slot_index(field)
917        .ok_or_else(invalid_plan_error)
918}
919
920// Keep the scalar-order expression seam violation text under one helper so the
921// parse validation and compile validation paths do not drift.
922fn order_expression_scalar_seam_error(_rendered: &str) -> InternalError {
923    InternalError::query_invalid_logical_plan()
924}
925
926// Keep one stable executor-facing slot list for grouped order terms after the
927// planner has frozen the structural `ResolvedOrder`. The grouped Top-K route
928// now consumes this same referenced-slot contract instead of re-deriving order
929// sources from planner strategy at runtime.
930fn order_referenced_slots_for_resolved_order(
931    resolved_order: Option<&ResolvedOrder>,
932) -> Option<Vec<usize>> {
933    Some(resolved_order?.referenced_slots())
934}
935
936fn slot_map_for_schema_plan(
937    schema_info: &SchemaInfo,
938    plan: &AccessPlannedQuery,
939) -> Option<Vec<usize>> {
940    let executable = plan.access.executable_contract();
941
942    resolved_index_slots_for_access_path(schema_info, &executable)
943}
944
945fn resolved_index_slots_for_access_path(
946    schema_info: &SchemaInfo,
947    access: &ExecutableAccessPlan<'_, crate::value::Value>,
948) -> Option<Vec<usize>> {
949    let path = access.as_path()?;
950    let path_facts = path.shape_facts();
951    let key_items = path_facts.index_key_items_for_slot_map()?;
952    let mut slots = Vec::with_capacity(key_items.key_arity());
953    for key_item in key_items.key_items() {
954        let slot = schema_info.field_slot_index(key_item.as_ref().field())?;
955        slots.push(slot);
956    }
957
958    Some(slots)
959}
960
961fn index_compile_targets_for_schema_plan(
962    schema_info: &SchemaInfo,
963    plan: &AccessPlannedQuery,
964) -> Option<Vec<IndexCompileTarget>> {
965    let executable = plan.access.executable_contract();
966    let path = executable.as_path()?;
967    let key_items = path.shape_facts().index_key_items_for_slot_map()?;
968    let mut targets = Vec::new();
969
970    for (component_index, key_item) in key_items.key_items().iter().enumerate() {
971        let key_item = key_item.as_ref();
972        let field_slot = schema_info.field_slot_index(key_item.field())?;
973        targets.push(IndexCompileTarget {
974            component_index,
975            field_slot,
976            kind: match key_item {
977                SemanticIndexKeyItemRef::Field(_) => IndexCompileTargetKind::Field,
978                SemanticIndexKeyItemRef::AcceptedExpression(expression) => {
979                    IndexCompileTargetKind::Expression(expression.op())
980                }
981            },
982        });
983    }
984
985    Some(targets)
986}