Skip to main content

uqa_sql/schema/
expressions.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Shared stored-expression analysis. SQL retains the original bound syntax; a planner-owned copy decides immutability and constant partition keys.
8
9use super::SchemaBindingContext;
10use crate::{
11    ast::{ColumnDef, Expr},
12    plan::ExpressionPlan,
13    ColumnType, RowSchema, SQLError, ScalarExpr,
14};
15
16pub struct AnalyzedSchemaExpression {
17    pub expression: Expr,
18    pub ty: Option<ColumnType>,
19    pub scalar: ScalarExpr,
20    pub schema: RowSchema,
21}
22
23pub struct PlannedSchemaExpression {
24    pub expression: Expr,
25    pub ty: Option<ColumnType>,
26    pub immutable: bool,
27    pub constant: bool,
28}
29
30pub fn row_schema(columns: &[ColumnDef]) -> RowSchema {
31    RowSchema::with_types(
32        columns.iter().map(|column| column.name.clone()).collect(),
33        columns
34            .iter()
35            .map(|column| Some(column.ty.clone()))
36            .collect(),
37    )
38}
39
40/// Analyze every branch before planning, and bind original routine/type/input identities for storage. Assignment coercion follows the planner's mutability check.
41pub fn analyze_schema_expression(
42    context: &SchemaBindingContext<'_, '_>,
43    expression: &Expr,
44    columns: &[ColumnDef],
45) -> Result<AnalyzedSchemaExpression, SQLError> {
46    let mut expression = expression.clone();
47    let schema = row_schema(columns);
48    let original = ExpressionPlan::lower(expression.clone());
49    let mut analyzed = original.clone();
50    let source = crate::binding::analyze_stored_expression_inputs(
51        context.catalog,
52        &mut analyzed,
53        context.binding,
54        &schema,
55    )?;
56    crate::binding::bind_expression_plan_routines_for_storage(
57        context.catalog,
58        &mut analyzed,
59        &[],
60        context.binding,
61        &schema,
62    )?;
63    let sites = crate::binding::syntax_sites::expression_syntax_sites(&original, &analyzed)?;
64    crate::catalog::stored_ast::bind_stored_expression_sites(&mut expression, &sites)?;
65    super::dependencies::oid_alias::read_oid_alias_constants(context.catalog, &mut expression)?;
66    let scalar = crate::type_resolution::bind_type_introspection_with_resolver(
67        analyzed.scalar,
68        &schema,
69        &[],
70        context.catalog,
71    );
72    Ok(AnalyzedSchemaExpression {
73        expression,
74        ty: source,
75        scalar,
76        schema,
77    })
78}