Skip to main content

uqa_sql/plan/
input_projection.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Substitute analyzed input expressions without evaluating their values.
8
9use super::{ExpressionPlan, ScalarExpr};
10use crate::{ast::InternalColumnRef, SQLError};
11use std::collections::BTreeMap;
12
13#[cfg(test)]
14mod tests;
15
16/// Inline structurally identified inputs at their use sites. Each query keeps its own scalar-subquery arena, and inserted expressions retain their analyzed routine bindings.
17pub fn substitute_expression_inputs(
18    plan: &mut ExpressionPlan,
19    inputs: &BTreeMap<InternalColumnRef, ExpressionPlan>,
20) -> Result<(), SQLError> {
21    if inputs.is_empty() {
22        return Ok(());
23    }
24    super::subqueries::rewrite_expression_with_arena(
25        &mut plan.scalar,
26        &mut plan.subqueries,
27        &mut |node, arena| {
28            let ScalarExpr::InternalColumn(column) = node else {
29                return Ok(());
30            };
31            let Some(input) = inputs.get(column) else {
32                return Ok(());
33            };
34            let mut replacement = input.scalar.clone();
35            let offset = arena.len();
36            super::rewrite_scalar_expression(&mut replacement, &mut |node| match node {
37                ScalarExpr::ScalarSubquery(id)
38                | ScalarExpr::Exists { subquery: id, .. }
39                | ScalarExpr::InSubquery { subquery: id, .. } => *id += offset,
40                _ => {}
41            });
42            arena.extend(input.subqueries.iter().cloned());
43            *node = replacement;
44            Ok(())
45        },
46    )
47}