fix: ADR-0035 4g — reconstruct table-CHECK metadata on rebuild
do_rebuild_from_text re-emitted table-level CHECKs into the recreated DDL (so they stayed enforced) but never repopulated __rdbms_playground_ table_checks. A fresh rebuild (missing .db, reconstructed from project.yaml) therefore left the CHECK metadata empty: DROP CONSTRAINT, describe, and a later save would lose it — including a named CHECK's name. In-place rebuilds only worked because the wipe never touched the table. (Latent since 4a.3 for unnamed checks; exposed by 4g's named round-trip claim.) Rebuild now wipes and repopulates CHECK_TABLE from the yaml snapshot (name + seq + expr), like META/REL, and adds the 4g `name` column if a pre-4g table predates it (the rebuild-only migration). Regression test: a named CHECK's metadata survives a fresh rebuild (DROP CONSTRAINT by name resolves).
This commit is contained in:
@@ -8643,6 +8643,23 @@ fn do_rebuild_from_text(
|
||||
))
|
||||
.map_err(DbError::from_rusqlite)?;
|
||||
|
||||
// 0b. The table-level CHECK metadata is the source of truth that
|
||||
// the engine cannot report (ADR-0035 §4a.3), so — like
|
||||
// META/REL — it is wiped and repopulated from the YAML
|
||||
// snapshot here (step 3b). Without this a fresh rebuild
|
||||
// (missing `.db`) would enforce the CHECK via the recreated
|
||||
// DDL but leave `CHECK_TABLE` empty, so `describe` / `DROP
|
||||
// CONSTRAINT` / a later save would lose it. The rebuild also
|
||||
// **migrates** a pre-§4g table that predates the `name`
|
||||
// column (the rebuild-only migration, ADR-0035 §4g): add it
|
||||
// if absent before repopulating with names.
|
||||
if !check_table_has_name_column(&tx)? {
|
||||
tx.execute_batch(&format!("ALTER TABLE {CHECK_TABLE} ADD COLUMN name TEXT;"))
|
||||
.map_err(DbError::from_rusqlite)?;
|
||||
}
|
||||
tx.execute_batch(&format!("DELETE FROM {CHECK_TABLE};"))
|
||||
.map_err(DbError::from_rusqlite)?;
|
||||
|
||||
// 1. Recreate user tables with FK constraints inline.
|
||||
for table in &snapshot.tables {
|
||||
let read_schema = build_read_schema(table, &snapshot.relationships);
|
||||
@@ -8694,6 +8711,29 @@ fn do_rebuild_from_text(
|
||||
}
|
||||
}
|
||||
|
||||
// 3b. Table-level CHECK metadata (ADR-0035 §4a.3 / §4g) — in
|
||||
// declaration order (`seq`), carrying the optional name so a
|
||||
// named CHECK round-trips through the rebuild.
|
||||
{
|
||||
let mut stmt = tx
|
||||
.prepare(&format!(
|
||||
"INSERT INTO {CHECK_TABLE} (table_name, seq, check_expr, name) \
|
||||
VALUES (?1, ?2, ?3, ?4);"
|
||||
))
|
||||
.map_err(DbError::from_rusqlite)?;
|
||||
for table in &snapshot.tables {
|
||||
for (seq, check) in table.check_constraints.iter().enumerate() {
|
||||
stmt.execute(rusqlite::params![
|
||||
table.name,
|
||||
seq as i64,
|
||||
check.expr,
|
||||
check.name,
|
||||
])
|
||||
.map_err(DbError::from_rusqlite)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Project metadata: overwrite the configure-time
|
||||
// `created_at` with the YAML's authoritative value.
|
||||
tx.execute(
|
||||
|
||||
Reference in New Issue
Block a user