Skip to main content

uqa_sql/schema/foreign_tables/
dependencies.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Foreign-column dependency validation and pure declaration rewrites.
8
9#[cfg(test)]
10mod tests;
11use crate::ast::{ColumnDef, TableCheck};
12use crate::schema::dependencies::schema_expr_references_column;
13
14pub fn clear_foreign_column_default(columns: &mut [ColumnDef], column_name: &str) -> bool {
15    let Some(column) = columns.iter_mut().find(|column| column.name == column_name) else {
16        return false;
17    };
18    column.default.take().is_some()
19}
20
21pub fn remove_foreign_check(
22    columns: &mut [ColumnDef],
23    checks: &mut Vec<TableCheck>,
24    constraint_name: &str,
25) -> bool {
26    for column in columns {
27        if column.check.is_some() && column.check_name.as_deref() == Some(constraint_name) {
28            column.check = None;
29            column.check_name = None;
30            column.check_object_id = None;
31            column.check_is_local = true;
32            column.check_enforced = true;
33            column.check_validated = true;
34            column.check_no_inherit = false;
35            return true;
36        }
37    }
38    let Some(index) = checks
39        .iter()
40        .position(|check| check.name.as_deref() == Some(constraint_name))
41    else {
42        return false;
43    };
44    checks.remove(index);
45    true
46}
47
48pub fn validate_foreign_column_removal(
49    columns: &[ColumnDef],
50    table_name: &str,
51    column_name: &str,
52) -> Result<(), String> {
53    for column in columns {
54        if column.name == column_name {
55            continue;
56        }
57        if column
58            .default
59            .as_ref()
60            .is_some_and(|expression| schema_expr_references_column(expression, column_name))
61            || column.generated.as_ref().is_some_and(|generated| {
62                schema_expr_references_column(&generated.expression, column_name)
63            })
64        {
65            return Err(format!(
66                    "cannot drop generated column `{table_name}`.`{column_name}` because column `{}` depends on it",
67                    column.name
68                ));
69        }
70    }
71    Ok(())
72}
73
74pub fn remove_foreign_column(
75    columns: &mut Vec<ColumnDef>,
76    checks: &mut Vec<TableCheck>,
77    column_index: usize,
78    column_name: &str,
79) {
80    for column in columns.iter_mut() {
81        if column.name != column_name
82            && column
83                .check
84                .as_ref()
85                .is_some_and(|expression| schema_expr_references_column(expression, column_name))
86        {
87            column.check = None;
88            column.check_name = None;
89            column.check_object_id = None;
90            column.check_is_local = true;
91            column.check_enforced = true;
92            column.check_validated = true;
93            column.check_no_inherit = false;
94        }
95    }
96    columns.remove(column_index);
97    checks.retain(|check| !schema_expr_references_column(&check.expr, column_name));
98}
99
100pub use crate::schema::sequences::dependencies::detach_sequence_provenance as detach_foreign_sequence_provenance;