uqa_sql/schema/
domains.rs1use super::SchemaBindingContext;
10use crate::assignment::domain::domain_error;
11use crate::plpgsql::{bind_expr, ResolvedVariable, VariableResolver};
12use crate::{
13 ast::{ColumnType, CreateDomain, Expr},
14 catalog::domain::DomainCatalog,
15 RowSchema, SQLError,
16};
17use std::collections::BTreeSet;
18use uqa_core::Value;
19
20pub fn prepare_domain_definition(
21 context: &SchemaBindingContext<'_, '_>,
22 domains: &dyn DomainCatalog,
23 definition: &mut CreateDomain,
24 schema_names: &BTreeSet<String>,
25) -> Result<(), SQLError> {
26 definition.base =
27 crate::type_resolution::resolve_declared_column_type(context.catalog, &definition.base)?;
28 if definition.default.is_none() {
29 definition.default =
30 crate::catalog::domain::domain_default_expression(domains, &definition.base);
31 }
32 if matches!(
33 definition.base,
34 ColumnType::Void | ColumnType::Record | ColumnType::AnyArray
35 ) {
36 return Err(domain_error(
37 "42809",
38 format!(
39 "\"{}\" is not a valid base type for a domain",
40 definition.base.sql_name()
41 ),
42 ));
43 }
44 if definition.collation.is_some() {
45 return Err(SQLError::Unsupported(
46 "domain collation binding is not implemented".into(),
47 ));
48 }
49 if let Some(default) = &mut definition.default {
50 super::defaults::validate_default_expression(context, default, &definition.base)?;
51 if let Expr::Literal(Value::Str(value)) = default {
52 let mut base = &definition.base;
53 while let ColumnType::Domain { base: parent, .. } = base {
54 base = parent;
55 }
56 crate::expr::cast_value_with_type_resolution(
57 &Value::Str(value.clone()),
58 None,
59 &base.without_type_modifiers().sql_name(),
60 Some(context.catalog),
61 )?;
62 }
63 }
64 constraints::assign_names(definition, schema_names)?;
65 for check in &mut definition.checks {
66 bind_domain_check(context, &definition.base, &mut check.expression)?;
67 }
68 definition
69 .checks
70 .sort_by(|left, right| left.name.cmp(&right.name));
71 Ok(())
72}
73
74struct DomainValueResolver<'a>(&'a ColumnType);
75
76impl VariableResolver for DomainValueResolver<'_> {
77 fn resolve_name(&mut self, name: &str) -> Result<Option<ResolvedVariable>, SQLError> {
78 if name != "value" {
79 return Err(SQLError::UnknownColumn(name.into()));
80 }
81 Ok(Some(ResolvedVariable {
82 value: Value::Null,
83 declared_type: Some(self.0.sql_name()),
84 }))
85 }
86
87 fn resolve_qualified(
88 &mut self,
89 qualifier: &str,
90 _column: &str,
91 ) -> Result<Option<ResolvedVariable>, SQLError> {
92 Err(SQLError::UnknownTable(qualifier.into()))
93 }
94
95 fn resolve_param(&mut self, index: usize) -> Result<Option<ResolvedVariable>, SQLError> {
96 Err(domain_error(
97 "42P02",
98 format!("there is no parameter ${index}"),
99 ))
100 }
101}
102
103fn bind_domain_check(
104 context: &SchemaBindingContext<'_, '_>,
105 base: &ColumnType,
106 expression: &mut Expr,
107) -> Result<(), SQLError> {
108 let typed = bind_expr(expression, &mut DomainValueResolver(base))?;
109 let plan = crate::plan::ExpressionPlan::lower(typed.clone());
110 if !plan.subqueries.is_empty() {
111 return Err(domain_error(
112 "0A000",
113 "cannot use subquery in check constraint",
114 ));
115 }
116 if crate::semantics::windows::expr_has_window(&plan.scalar) {
117 return Err(domain_error(
118 "42P20",
119 "window functions are not allowed in check constraints",
120 ));
121 }
122 if crate::semantics::aggregates::contains_aggregate(context.catalog, &plan.scalar) {
123 return Err(domain_error(
124 "42803",
125 "aggregate functions are not allowed in check constraints",
126 ));
127 }
128 let ty = crate::type_resolution::common_context_expression_type(
129 &plan.scalar,
130 &RowSchema::default(),
131 &[],
132 Some(context.catalog),
133 )?;
134 if let Some(ty) = ty {
135 if crate::expr::coercion_type_name(&ty) != "boolean" {
136 return Err(domain_error(
137 "42804",
138 format!(
139 "argument of CHECK must be type boolean, not type {}",
140 ty.sql_name()
141 ),
142 ));
143 }
144 } else {
145 *expression = Expr::Cast {
146 expr: Box::new(expression.clone()),
147 ty: "boolean".into(),
148 };
149 }
150 super::defaults::bind_stored_schema_expression_routines(context, expression, typed)?;
151 Ok(())
152}
153
154pub mod constraints;
155pub mod dependencies;
156pub mod removal;