feat: alter table disallow generated columns, support foreign keys for alter table

This commit is contained in:
RS2007
2025-11-08 13:45:17 +05:30
parent 36c3489c53
commit 3a562f734c
2 changed files with 97 additions and 1 deletions

View File

@@ -6,7 +6,7 @@ use turso_parser::{
use crate::{ use crate::{
function::{AlterTableFunc, Func}, function::{AlterTableFunc, Func},
schema::{Column, Table, RESERVED_TABLE_PREFIXES}, schema::{Column, ForeignKey, Table, RESERVED_TABLE_PREFIXES},
translate::{ translate::{
emitter::Resolver, emitter::Resolver,
expr::{walk_expr, WalkControl}, expr::{walk_expr, WalkControl},
@@ -280,6 +280,16 @@ pub fn translate_alter_table(
)? )?
} }
ast::AlterTableBody::AddColumn(col_def) => { ast::AlterTableBody::AddColumn(col_def) => {
if col_def
.constraints
.iter()
.any(|c| matches!(c.constraint, ast::ColumnConstraint::Generated { .. }))
{
return Err(LimboError::ParseError(
"Alter table does not support adding generated columns".to_string(),
));
}
let constraints = col_def.constraints.clone();
let column = Column::from(&col_def); let column = Column::from(&col_def);
if let Some(default) = &column.default { if let Some(default) = &column.default {
@@ -310,6 +320,58 @@ pub fn translate_alter_table(
// TODO: All quoted ids will be quoted with `[]`, we should store some info from the parsed AST // TODO: All quoted ids will be quoted with `[]`, we should store some info from the parsed AST
btree.columns.push(column.clone()); btree.columns.push(column.clone());
// Add foreign key constraints to the btree table
for constraint in constraints {
if let ast::ColumnConstraint::ForeignKey {
clause,
defer_clause,
} = constraint.constraint
{
let fk = ForeignKey {
parent_table: normalize_ident(clause.tbl_name.as_str()),
parent_columns: clause
.columns
.iter()
.map(|c| normalize_ident(c.col_name.as_str()))
.collect(),
on_delete: clause
.args
.iter()
.find_map(|arg| {
if let ast::RefArg::OnDelete(act) = arg {
Some(*act)
} else {
None
}
})
.unwrap_or(ast::RefAct::NoAction),
on_update: clause
.args
.iter()
.find_map(|arg| {
if let ast::RefArg::OnUpdate(act) = arg {
Some(*act)
} else {
None
}
})
.unwrap_or(ast::RefAct::NoAction),
child_columns: vec![new_column_name.to_string()],
deferred: match defer_clause {
Some(d) => {
d.deferrable
&& matches!(
d.init_deferred,
Some(ast::InitDeferredPred::InitiallyDeferred)
)
}
None => false,
},
};
btree.foreign_keys.push(Arc::new(fk));
}
}
let sql = btree.to_sql(); let sql = btree.to_sql();
let mut escaped = String::with_capacity(sql.len()); let mut escaped = String::with_capacity(sql.len());

View File

@@ -299,3 +299,37 @@ do_execsql_test_on_specific_db {:memory:} rename-parent-3-composite {
SELECT sql FROM sqlite_schema WHERE type='table' AND name='c3'; SELECT sql FROM sqlite_schema WHERE type='table' AND name='c3';
} {{CREATE TABLE c3 (x INTEGER PRIMARY KEY, fa INTEGER, fb INTEGER, FOREIGN KEY (fa, fb) REFERENCES p3_new (a, b))}} } {{CREATE TABLE c3 (x INTEGER PRIMARY KEY, fa INTEGER, fb INTEGER, FOREIGN KEY (fa, fb) REFERENCES p3_new (a, b))}}
# Adding a generated column via ALTER TABLE should error
do_execsql_test_in_memory_error_content alter-table-add-generated-column-error {
CREATE TABLE t(a);
ALTER TABLE t ADD COLUMN b AS (NULL);
} {
"Parse error: Alter table does not support adding generated columns"
}
# Add column with a foreign key reference and verify schema SQL
do_execsql_test_on_specific_db {:memory:} alter-table-add-column-with-fk-updates-schema {
CREATE TABLE t(a);
CREATE TABLE s(a);
ALTER TABLE s ADD COLUMN b REFERENCES t(a);
SELECT sql FROM sqlite_schema WHERE name = 's';
} {
"CREATE TABLE s (a, b, FOREIGN KEY (b) REFERENCES t(a))"
}
do_execsql_test_on_specific_db {:memory:} alter-table-add-self-ref-fk-updates-schema {
CREATE TABLE s(a);
ALTER TABLE s ADD COLUMN b REFERENCES s(a);
SELECT sql FROM sqlite_schema WHERE name = 's';
} {
"CREATE TABLE s (a, b, FOREIGN KEY (b) REFERENCES s(a))"
}
do_execsql_test_on_specific_db {:memory:} alter-table-add-column-with-composite-fk-updates-schema {
CREATE TABLE t(a, c);
CREATE TABLE s(a);
ALTER TABLE s ADD COLUMN b REFERENCES t(a, c);
SELECT sql FROM sqlite_schema WHERE name = 's';
} {
"CREATE TABLE s (a, b, FOREIGN KEY (b) REFERENCES t(a, c))"
}