Skip to main content

uqa_sql/binding/
scope.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Outer-scope composition and common row-value typing.
8
9use crate::ast::ColumnType;
10use crate::plan::{ExpressionPlan, QueryPlan};
11use crate::RowSchema;
12use crate::{SQLError, SQLParam};
13
14use super::{BindingContext, ScalarExpr, SchemaScope};
15use crate::routines::RoutineResolution;
16
17/// Derive the exact output row type of a query plan without executing it.
18pub fn bind_query_plan_schema(
19    routines: &dyn RoutineResolution,
20    plan: &QueryPlan,
21    params: &[SQLParam],
22    ctes: &BindingContext,
23    outer: Option<&RowSchema>,
24) -> Result<RowSchema, SQLError> {
25    SchemaScope::from_context(ctes)?.bind_query(routines, plan, params, outer)
26}
27
28/// Derive the declared SQL type of a standalone expression plan without executing it. The plan-owned subquery arena participates in type resolution so scalar subqueries retain their projected type at command boundaries such as `CALL`.
29pub fn bind_expression_plan_type(
30    routines: &dyn RoutineResolution,
31    plan: &ExpressionPlan,
32    params: &[SQLParam],
33    ctes: &BindingContext,
34) -> Result<Option<ColumnType>, SQLError> {
35    SchemaScope::from_context(ctes)?.bind_expression_type(
36        routines,
37        &plan.scalar,
38        &RowSchema::default(),
39        &plan.subqueries,
40        params,
41    )
42}
43
44/// Validate a command argument's names and types without running its expressions.
45pub fn analyze_expression_plan_type(
46    routines: &dyn RoutineResolution,
47    plan: &ExpressionPlan,
48    params: &[SQLParam],
49    ctes: &BindingContext,
50) -> Result<Option<ColumnType>, SQLError> {
51    SchemaScope::for_analysis(ctes)?.bind_expression_type(
52        routines,
53        &plan.scalar,
54        &RowSchema::default(),
55        &plan.subqueries,
56        params,
57    )
58}
59
60/// Analyze every catalog and scalar reference and derive the exact output row type without executing the query.
61pub fn analyze_query_plan_schema(
62    routines: &dyn RoutineResolution,
63    plan: &QueryPlan,
64    params: &[SQLParam],
65    ctes: &BindingContext,
66    outer: Option<&RowSchema>,
67) -> Result<RowSchema, SQLError> {
68    SchemaScope::for_analysis(ctes)?.bind_query(routines, plan, params, outer)
69}
70
71pub fn analyze_query_plan_schema_with_catalog(
72    routines: &dyn RoutineResolution,
73    plan: &QueryPlan,
74    params: &[SQLParam],
75    catalog: crate::catalog::analysis::CatalogReadView,
76    resolution: crate::catalog::resolution::RelationNameResolution,
77) -> Result<RowSchema, SQLError> {
78    SchemaScope::for_catalog_analysis(catalog, resolution).bind_query(routines, plan, params, None)
79}
80
81pub fn overlay_outer_schema(current: &RowSchema, outer: Option<&RowSchema>) -> RowSchema {
82    outer.map_or_else(
83        || current.clone(),
84        |outer| RowSchema::with_outer_schema(current, outer),
85    )
86}
87
88pub fn values_types_in_scope(
89    routines: &dyn RoutineResolution,
90    rows: &[Vec<ScalarExpr>],
91    subqueries: &[QueryPlan],
92    schema: Option<&RowSchema>,
93    params: &[SQLParam],
94    ctes: &BindingContext,
95) -> Result<Vec<Option<ColumnType>>, SQLError> {
96    SchemaScope::from_context(ctes)?.bind_values_types(routines, rows, subqueries, schema, params)
97}
98
99/// The common type of two columns of the construct `context`, as `select_common_type` chooses it over typed and `unknown` (`None`) inputs; two unknown inputs stay unknown for the caller to resolve.
100pub(super) fn merge_types(
101    context: crate::type_resolution::CommonTypeContext,
102    left: Option<&ColumnType>,
103    right: Option<&ColumnType>,
104) -> Result<Option<ColumnType>, SQLError> {
105    match (left, right) {
106        (None, None) => Ok(None),
107        (Some(ty), None) | (None, Some(ty)) => Ok(Some(ty.clone())),
108        (Some(left), Some(right)) => {
109            crate::type_resolution::common_type_in(context, left, right).map(Some)
110        }
111    }
112}