Skip to main content

uqa_sql/schema/columns/
removal.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Discover foreign keys that refer to a deleted column in catalog order.
8use crate::{assignment::columns::ColumnCatalogError, ast::ForeignKey, SQLError};
9pub trait ColumnRemovalCatalog {
10    fn try_resolve_table_name(&self, table: &str) -> Result<Option<String>, ColumnCatalogError>;
11    fn table_names(&self) -> Result<Vec<String>, ColumnCatalogError>;
12    fn try_foreign_keys(&self, table: &str) -> Result<Vec<ForeignKey>, ColumnCatalogError>;
13}
14pub fn foreign_keys_referencing_column(
15    catalog: &dyn ColumnRemovalCatalog,
16    table: &str,
17    column: &str,
18) -> Result<Vec<(String, String)>, SQLError> {
19    let canonical = catalog
20        .try_resolve_table_name(table)
21        .map_err(|error| {
22            crate::catalog::errors::storage_error("ALTER TABLE DROP COLUMN", error.as_ref())
23        })?
24        .ok_or_else(|| SQLError::UnknownTable(table.to_string()))?;
25    let mut dependents = Vec::new();
26    for referrer in catalog.table_names().map_err(|error| {
27        crate::catalog::errors::storage_error("ALTER TABLE DROP COLUMN", error.as_ref())
28    })? {
29        for foreign_key in catalog.try_foreign_keys(&referrer).map_err(|error| {
30            crate::catalog::errors::storage_error("ALTER TABLE DROP COLUMN", error.as_ref())
31        })? {
32            if foreign_key.ref_table == canonical
33                && foreign_key.ref_columns.iter().any(|name| name == column)
34            {
35                dependents.push((
36                    referrer.clone(),
37                    foreign_key.name.clone().ok_or_else(|| {
38                        SQLError::Internal("dependent FOREIGN KEY has no durable name".into())
39                    })?,
40                ));
41            }
42        }
43    }
44    Ok(dependents)
45}