Skip to main content

uqa_sql/schema/
defaults.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! PostgreSQL-compatible validation for column default expressions.
8
9use super::SchemaBindingContext;
10use crate::ast::Expr;
11use crate::RowSchema;
12use crate::{ColumnType, SQLError};
13
14pub fn validate_default_expression(
15    context: &SchemaBindingContext<'_, '_>,
16    expression: &mut Expr,
17    target: &ColumnType,
18) -> Result<(), SQLError> {
19    let plan = crate::plan::ExpressionPlan::lower(expression.clone());
20    if !plan.subqueries.is_empty() {
21        return Err(default_error(
22            "0A000",
23            "cannot use subquery in DEFAULT expression",
24        ));
25    }
26    if crate::semantics::windows::expr_has_window(&plan.scalar) {
27        return Err(default_error(
28            "42P20",
29            "window functions are not allowed in DEFAULT expressions",
30        ));
31    }
32    if crate::semantics::aggregates::contains_aggregate(context.catalog, &plan.scalar) {
33        return Err(default_error(
34            "42803",
35            "aggregate functions are not allowed in DEFAULT expressions",
36        ));
37    }
38    if crate::semantics::aggregates::expr_references_columns(&plan.scalar) {
39        return Err(default_error(
40            "0A000",
41            "cannot use column reference in DEFAULT expression",
42        ));
43    }
44    crate::type_resolution::scalar_type_with_resolver(
45        &plan.scalar,
46        &RowSchema::default(),
47        &[],
48        context.catalog,
49    )?;
50    crate::catalog::regrole_dependencies::reject_stored_regrole_constants(
51        context.catalog,
52        expression,
53        Some(target),
54    )?;
55    bind_stored_schema_expression_routines(context, expression, expression.clone())?;
56    Ok(())
57}
58
59pub fn bind_stored_schema_expression_routines(
60    context: &SchemaBindingContext<'_, '_>,
61    expression: &mut Expr,
62    typed_expression: Expr,
63) -> Result<bool, SQLError> {
64    let mut plan = crate::plan::ExpressionPlan::lower_with(typed_expression, &|name: &str| {
65        context.catalog.has_registered_aggregate_function(name)
66    });
67    crate::binding::bind_expression_plan_routines_for_storage(
68        context.catalog,
69        &mut plan,
70        &[],
71        context.binding,
72        &RowSchema::default(),
73    )?;
74    let references = crate::binding::stored_routines::collect_expression_routine_references(&plan)?;
75    crate::catalog::stored_ast::bind_stored_expression_routines(expression, &references)
76}
77
78fn default_error(sqlstate: &str, message: &str) -> SQLError {
79    SQLError::Routine {
80        sqlstate: sqlstate.into(),
81        message: message.into(),
82    }
83}