Merge 'core/vdbe: fix ALTER COLUMN to propagate constraints to other table references' from Preston Thorpe

with fix to ensure `PRIMARY KEY` isn't written twice

Closes #3798
This commit is contained in:
Pekka Enberg
2025-10-21 20:05:41 +03:00
committed by GitHub
5 changed files with 537 additions and 56 deletions

View File

@@ -1358,6 +1358,8 @@ impl BTreeTable {
/// `CREATE TABLE t (x)`, whereas sqlite stores it with the original extra whitespace.
pub fn to_sql(&self) -> String {
let mut sql = format!("CREATE TABLE {} (", self.name);
let needs_pk_inline = self.primary_key_columns.len() == 1;
// Add columns
for (i, column) in self.columns.iter().enumerate() {
if i > 0 {
sql.push_str(", ");
@@ -1384,8 +1386,7 @@ impl BTreeTable {
if column.unique {
sql.push_str(" UNIQUE");
}
if column.primary_key {
if needs_pk_inline && column.primary_key {
sql.push_str(" PRIMARY KEY");
}
@@ -1394,6 +1395,64 @@ impl BTreeTable {
sql.push_str(&default.to_string());
}
}
let has_table_pk = !self.primary_key_columns.is_empty();
// Add table-level PRIMARY KEY constraint if exists
if !needs_pk_inline && has_table_pk {
sql.push_str(", PRIMARY KEY (");
for (i, col) in self.primary_key_columns.iter().enumerate() {
if i > 0 {
sql.push_str(", ");
}
sql.push_str(&col.0);
}
sql.push(')');
}
for fk in &self.foreign_keys {
sql.push_str(", FOREIGN KEY (");
for (i, col) in fk.child_columns.iter().enumerate() {
if i > 0 {
sql.push_str(", ");
}
sql.push_str(col);
}
sql.push_str(") REFERENCES ");
sql.push_str(&fk.parent_table);
sql.push('(');
for (i, col) in fk.parent_columns.iter().enumerate() {
if i > 0 {
sql.push_str(", ");
}
sql.push_str(col);
}
sql.push(')');
// Add ON DELETE/UPDATE actions, NoAction is default so just make empty in that case
if fk.on_delete != RefAct::NoAction {
sql.push_str(" ON DELETE ");
sql.push_str(match fk.on_delete {
RefAct::SetNull => "SET NULL",
RefAct::SetDefault => "SET DEFAULT",
RefAct::Cascade => "CASCADE",
RefAct::Restrict => "RESTRICT",
_ => "",
});
}
if fk.on_update != RefAct::NoAction {
sql.push_str(" ON UPDATE ");
sql.push_str(match fk.on_update {
RefAct::SetNull => "SET NULL",
RefAct::SetDefault => "SET DEFAULT",
RefAct::Cascade => "CASCADE",
RefAct::Restrict => "RESTRICT",
_ => "",
});
}
if fk.deferred {
sql.push_str(" DEFERRABLE INITIALLY DEFERRED");
}
}
sql.push(')');
sql
}

View File

@@ -1331,6 +1331,39 @@ pub fn extract_view_columns(
Ok(ViewColumnSchema { tables, columns })
}
pub fn rewrite_fk_parent_cols_if_self_ref(
clause: &mut ast::ForeignKeyClause,
table: &str,
from: &str,
to: &str,
) {
if normalize_ident(clause.tbl_name.as_str()) == normalize_ident(table) {
for c in &mut clause.columns {
if normalize_ident(c.col_name.as_str()) == normalize_ident(from) {
c.col_name = ast::Name::exact(to.to_owned());
}
}
}
}
/// Update a column-level REFERENCES <tbl>(col,...) constraint
pub fn rewrite_column_references_if_needed(
col: &mut ast::ColumnDefinition,
table: &str,
from: &str,
to: &str,
) {
for cc in &mut col.constraints {
if let ast::NamedColumnConstraint {
constraint: ast::ColumnConstraint::ForeignKey { clause, .. },
..
} = cc
{
rewrite_fk_parent_cols_if_self_ref(clause, table, from, to);
}
}
}
#[cfg(test)]
pub mod tests {
use super::*;

View File

@@ -17,7 +17,9 @@ use crate::types::{
compare_immutable, compare_records_generic, Extendable, IOCompletions, ImmutableRecord,
SeekResult, Text,
};
use crate::util::normalize_ident;
use crate::util::{
normalize_ident, rewrite_column_references_if_needed, rewrite_fk_parent_cols_if_self_ref,
};
use crate::vdbe::insn::InsertFlags;
use crate::vdbe::{registers_to_ref_values, TxnCleanup};
use crate::vector::{vector32_sparse, vector_concat, vector_distance_jaccard, vector_slice};
@@ -73,7 +75,7 @@ use super::{
};
use parking_lot::RwLock;
use rand::{thread_rng, Rng, RngCore};
use turso_parser::ast::{self, Name, SortOrder};
use turso_parser::ast::{self, ForeignKeyClause, Name, SortOrder};
use turso_parser::parser::Parser;
use super::{
@@ -5463,11 +5465,9 @@ pub fn op_function(
.parse_column_definition(true)
.unwrap();
let new_sql = 'sql: {
if table != tbl_name {
break 'sql None;
}
let rename_to = normalize_ident(column_def.col_name.as_str());
let new_sql = 'sql: {
let Value::Text(sql) = sql else {
break 'sql None;
};
@@ -5521,34 +5521,160 @@ pub fn op_function(
temporary,
if_not_exists,
} => {
if table != normalize_ident(tbl_name.name.as_str()) {
break 'sql None;
}
let ast::CreateTableBody::ColumnsAndConstraints {
mut columns,
constraints,
mut constraints,
options,
} = body
else {
todo!()
};
let column = columns
.iter_mut()
.find(|column| {
column.col_name.as_str() == original_rename_from.as_str()
})
.expect("column being renamed should be present");
let normalized_tbl_name = normalize_ident(tbl_name.name.as_str());
match alter_func {
AlterTableFunc::AlterColumn => *column = column_def,
AlterTableFunc::RenameColumn => {
column.col_name = column_def.col_name
if normalized_tbl_name == table {
// This is the table being altered - update its column
let column = columns
.iter_mut()
.find(|column| {
column.col_name.as_str()
== original_rename_from.as_str()
})
.expect("column being renamed should be present");
match alter_func {
AlterTableFunc::AlterColumn => *column = column_def.clone(),
AlterTableFunc::RenameColumn => {
column.col_name = column_def.col_name.clone()
}
_ => unreachable!(),
}
_ => unreachable!(),
}
// Update table-level constraints (PRIMARY KEY, UNIQUE, FOREIGN KEY)
for constraint in &mut constraints {
match &mut constraint.constraint {
ast::TableConstraint::PrimaryKey {
columns: pk_cols,
..
} => {
for col in pk_cols {
let (ast::Expr::Name(ref name)
| ast::Expr::Id(ref name)) = *col.expr
else {
return Err(LimboError::ParseError("Unexpected expression in PRIMARY KEY constraint".to_string()));
};
if normalize_ident(name.as_str()) == rename_from
{
*col.expr = ast::Expr::Name(Name::exact(
column_def.col_name.as_str().to_owned(),
));
}
}
}
ast::TableConstraint::Unique {
columns: uniq_cols,
..
} => {
for col in uniq_cols {
let (ast::Expr::Name(ref name)
| ast::Expr::Id(ref name)) = *col.expr
else {
return Err(LimboError::ParseError("Unexpected expression in UNIQUE constraint".to_string()));
};
if normalize_ident(name.as_str()) == rename_from
{
*col.expr = ast::Expr::Name(Name::exact(
column_def.col_name.as_str().to_owned(),
));
}
}
}
ast::TableConstraint::ForeignKey {
columns: child_cols,
clause,
..
} => {
// Update child columns in this table's FK definitions
for child_col in child_cols {
if normalize_ident(child_col.col_name.as_str())
== rename_from
{
child_col.col_name = Name::exact(
column_def.col_name.as_str().to_owned(),
);
}
}
rewrite_fk_parent_cols_if_self_ref(
clause,
&normalized_tbl_name,
&rename_from,
column_def.col_name.as_str(),
);
}
_ => {}
}
for col in &mut columns {
rewrite_column_references_if_needed(
col,
&normalized_tbl_name,
&rename_from,
column_def.col_name.as_str(),
);
}
}
} else {
// This is a different table, check if it has FKs referencing the renamed column
let mut fk_updated = false;
for constraint in &mut constraints {
if let ast::TableConstraint::ForeignKey {
columns: _,
clause:
ForeignKeyClause {
tbl_name,
columns: parent_cols,
..
},
..
} = &mut constraint.constraint
{
// Check if this FK references the table being altered
if normalize_ident(tbl_name.as_str()) == table {
// Update parent column references if they match the renamed column
for parent_col in parent_cols {
if normalize_ident(parent_col.col_name.as_str())
== rename_from
{
parent_col.col_name = Name::exact(
column_def.col_name.as_str().to_owned(),
);
fk_updated = true;
}
}
}
}
}
for col in &mut columns {
let before = fk_updated;
let mut local_col = col.clone();
rewrite_column_references_if_needed(
&mut local_col,
&table,
&rename_from,
column_def.col_name.as_str(),
);
if local_col != *col {
*col = local_col;
fk_updated = true;
}
}
// Only return updated SQL if we actually changed something
if !fk_updated {
break 'sql None;
}
}
Some(
ast::Stmt::CreateTable {
tbl_name,
@@ -5563,7 +5689,7 @@ pub fn op_function(
.to_string(),
)
}
_ => todo!(),
_ => None,
}
};
@@ -8238,43 +8364,94 @@ pub fn op_alter_column(
.clone()
};
let new_column = crate::schema::Column::from(definition);
let new_name = definition.col_name.as_str().to_owned();
conn.with_schema_mut(|schema| {
let table = schema
let table_arc = schema
.tables
.get_mut(&normalized_table_name)
.expect("table being renamed should be in schema");
.expect("table being ALTERed should be in schema");
let table = Arc::make_mut(table_arc);
let table = Arc::make_mut(table);
let Table::BTree(btree) = table else {
panic!("only btree tables can be renamed");
let Table::BTree(ref mut btree_arc) = table else {
panic!("only btree tables can be altered");
};
let btree = Arc::make_mut(btree);
let column = btree
let btree = Arc::make_mut(btree_arc);
let col = btree
.columns
.get_mut(*column_index)
.expect("renamed column should be in schema");
.expect("column being ALTERed should be in schema");
if let Some(indexes) = schema.indexes.get_mut(&normalized_table_name) {
for index in indexes {
let index = Arc::make_mut(index);
for index_column in &mut index.columns {
if index_column.name
== *column.name.as_ref().expect("btree column should be named")
{
index_column.name = definition.col_name.as_str().to_owned();
// Update indexes on THIS table that name the old column (you already had this)
if let Some(idxs) = schema.indexes.get_mut(&normalized_table_name) {
for idx in idxs {
let idx = Arc::make_mut(idx);
for ic in &mut idx.columns {
if ic.name.eq_ignore_ascii_case(
col.name.as_ref().expect("btree column should be named"),
) {
ic.name = new_name.clone();
}
}
}
}
if *rename {
col.name = Some(new_name.clone());
} else {
*col = new_column.clone();
}
// Keep primary_key_columns consistent (names may change on rename)
for (pk_name, _ord) in &mut btree.primary_key_columns {
if pk_name.eq_ignore_ascii_case(&old_column_name) {
*pk_name = new_name.clone();
}
}
// Maintain rowid-alias bit after change/rename (INTEGER PRIMARY KEY)
if !*rename {
// recompute alias from `new_column`
btree.columns[*column_index].is_rowid_alias = new_column.is_rowid_alias;
}
// Update this tables OWN foreign keys
for fk_arc in &mut btree.foreign_keys {
let fk = Arc::make_mut(fk_arc);
// child side: rename child column if it matches
for cc in &mut fk.child_columns {
if cc.eq_ignore_ascii_case(&old_column_name) {
*cc = new_name.clone();
}
}
// parent side: if self-referencing, rename parent column too
if normalize_ident(&fk.parent_table) == normalized_table_name {
for pc in &mut fk.parent_columns {
if pc.eq_ignore_ascii_case(&old_column_name) {
*pc = new_name.clone();
}
}
}
}
if *rename {
column.name = new_column.name;
} else {
*column = new_column;
// fix OTHER tables that reference this table as parent
for (tname, t_arc) in schema.tables.iter_mut() {
if normalize_ident(tname) == normalized_table_name {
continue;
}
if let Table::BTree(ref mut child_btree_arc) = Arc::make_mut(t_arc) {
let child_btree = Arc::make_mut(child_btree_arc);
for fk_arc in &mut child_btree.foreign_keys {
if normalize_ident(&fk_arc.parent_table) != normalized_table_name {
continue;
}
let fk = Arc::make_mut(fk_arc);
for pc in &mut fk.parent_columns {
if pc.eq_ignore_ascii_case(&old_column_name) {
*pc = new_name.clone();
}
}
}
}
}
});

View File

@@ -22,3 +22,219 @@ do_execsql_test_in_memory_any_error fail-alter-column-unique {
CREATE TABLE t (a);
ALTER TABLE t ALTER COLUMN a TO a UNIQUE;
}
do_execsql_test_on_specific_db {:memory:} alter-table-rename-pk-column {
CREATE TABLE customers (cust_id INTEGER PRIMARY KEY, cust_name TEXT);
INSERT INTO customers VALUES (1, 'Alice'), (2, 'Bob');
ALTER TABLE customers RENAME COLUMN cust_id TO customer_id;
SELECT sql FROM sqlite_schema WHERE name = 'customers';
SELECT customer_id, cust_name FROM customers ORDER BY customer_id;
} {
"CREATE TABLE customers (customer_id INTEGER PRIMARY KEY, cust_name TEXT)"
"1|Alice"
"2|Bob"
}
do_execsql_test_on_specific_db {:memory:} alter-table-rename-composite-pk {
CREATE TABLE products (category TEXT, prod_code TEXT, name TEXT, PRIMARY KEY (category, prod_code));
INSERT INTO products VALUES ('Electronics', 'E001', 'Laptop');
ALTER TABLE products RENAME COLUMN prod_code TO product_code;
SELECT sql FROM sqlite_schema WHERE name = 'products';
SELECT category, product_code, name FROM products;
} {
"CREATE TABLE products (category TEXT, product_code TEXT, name TEXT, PRIMARY KEY (category, product_code))"
"Electronics|E001|Laptop"
}
# Foreign key child column rename
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-child {
CREATE TABLE parent (id INTEGER PRIMARY KEY);
CREATE TABLE child (cid INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent(id));
INSERT INTO parent VALUES (1);
INSERT INTO child VALUES (1, 1);
ALTER TABLE child RENAME COLUMN pid TO parent_id;
SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
"CREATE TABLE child (cid INTEGER PRIMARY KEY, parent_id INTEGER, FOREIGN KEY (parent_id) REFERENCES parent (id))"
}
# Foreign key parent column rename - critical test
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-parent {
CREATE TABLE orders (order_id INTEGER PRIMARY KEY, date TEXT);
CREATE TABLE items (item_id INTEGER PRIMARY KEY, oid INTEGER, FOREIGN KEY (oid) REFERENCES orders(order_id));
ALTER TABLE orders RENAME COLUMN order_id TO ord_id;
SELECT sql FROM sqlite_schema WHERE name = 'orders';
SELECT sql FROM sqlite_schema WHERE name = 'items';
} {
"CREATE TABLE orders (ord_id INTEGER PRIMARY KEY, date TEXT)"
"CREATE TABLE items (item_id INTEGER PRIMARY KEY, oid INTEGER, FOREIGN KEY (oid) REFERENCES orders (ord_id))"
}
# Composite foreign key parent rename
do_execsql_test_on_specific_db {:memory:} alter-table-rename-composite-fk-parent {
CREATE TABLE products (cat TEXT, code TEXT, PRIMARY KEY (cat, code));
CREATE TABLE inventory (id INTEGER PRIMARY KEY, cat TEXT, code TEXT, FOREIGN KEY (cat, code) REFERENCES products(cat, code));
ALTER TABLE products RENAME COLUMN code TO sku;
SELECT sql FROM sqlite_schema WHERE name = 'products';
SELECT sql FROM sqlite_schema WHERE name = 'inventory';
} {
"CREATE TABLE products (cat TEXT, sku TEXT, PRIMARY KEY (cat, sku))"
"CREATE TABLE inventory (id INTEGER PRIMARY KEY, cat TEXT, code TEXT, FOREIGN KEY (cat, code) REFERENCES products (cat, sku))"
}
# Multiple foreign keys to same parent
do_execsql_test_on_specific_db {:memory:} alter-table-rename-multiple-fks {
CREATE TABLE users (uid INTEGER PRIMARY KEY);
CREATE TABLE messages (mid INTEGER PRIMARY KEY, sender INTEGER, receiver INTEGER,
FOREIGN KEY (sender) REFERENCES users(uid),
FOREIGN KEY (receiver) REFERENCES users(uid));
ALTER TABLE users RENAME COLUMN uid TO user_id;
SELECT sql FROM sqlite_schema WHERE name = 'messages';
} {
"CREATE TABLE messages (mid INTEGER PRIMARY KEY, sender INTEGER, receiver INTEGER, FOREIGN KEY (sender) REFERENCES users (user_id), FOREIGN KEY (receiver) REFERENCES users (user_id))"
}
# Self-referencing foreign key
do_execsql_test_on_specific_db {:memory:} alter-table-rename-self-ref-fk {
CREATE TABLE employees (emp_id INTEGER PRIMARY KEY, manager_id INTEGER,
FOREIGN KEY (manager_id) REFERENCES employees(emp_id));
ALTER TABLE employees RENAME COLUMN emp_id TO employee_id;
SELECT sql FROM sqlite_schema WHERE name = 'employees';
} {
"CREATE TABLE employees (employee_id INTEGER PRIMARY KEY, manager_id INTEGER, FOREIGN KEY (manager_id) REFERENCES employees (employee_id))"
}
# Chain of FK renames - parent is both PK and referenced
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-chain {
CREATE TABLE t1 (a INTEGER PRIMARY KEY);
CREATE TABLE t2 (b INTEGER PRIMARY KEY, a_ref INTEGER, FOREIGN KEY (a_ref) REFERENCES t1(a));
CREATE TABLE t3 (c INTEGER PRIMARY KEY, b_ref INTEGER, FOREIGN KEY (b_ref) REFERENCES t2(b));
ALTER TABLE t1 RENAME COLUMN a TO a_new;
ALTER TABLE t2 RENAME COLUMN b TO b_new;
SELECT sql FROM sqlite_schema WHERE name = 't2';
SELECT sql FROM sqlite_schema WHERE name = 't3';
} {
"CREATE TABLE t2 (b_new INTEGER PRIMARY KEY, a_ref INTEGER, FOREIGN KEY (a_ref) REFERENCES t1 (a_new))"
"CREATE TABLE t3 (c INTEGER PRIMARY KEY, b_ref INTEGER, FOREIGN KEY (b_ref) REFERENCES t2 (b_new))"
}
# FK with ON DELETE/UPDATE actions
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-actions {
CREATE TABLE parent (pid INTEGER PRIMARY KEY);
CREATE TABLE child (cid INTEGER PRIMARY KEY, pid INTEGER,
FOREIGN KEY (pid) REFERENCES parent(pid) ON DELETE CASCADE ON UPDATE RESTRICT);
ALTER TABLE parent RENAME COLUMN pid TO parent_id;
SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
"CREATE TABLE child (cid INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent (parent_id) ON DELETE CASCADE ON UPDATE RESTRICT)"
}
# FK with DEFERRABLE
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-deferrable {
CREATE TABLE parent (id INTEGER PRIMARY KEY);
CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER,
FOREIGN KEY (pid) REFERENCES parent(id) DEFERRABLE INITIALLY DEFERRED);
ALTER TABLE parent RENAME COLUMN id TO parent_id;
SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
"CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent (parent_id) DEFERRABLE INITIALLY DEFERRED)"
}
# Rename with quoted identifiers in FK
do_execsql_test_on_specific_db {:memory:} alter-table-rename-fk-quoted {
CREATE TABLE "parent table" ("parent id" INTEGER PRIMARY KEY);
CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER,
FOREIGN KEY (pid) REFERENCES "parent table"("parent id"));
ALTER TABLE "parent table" RENAME COLUMN "parent id" TO "new id";
SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
"CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES \"parent table\" (\"new id\"))"
}
# Verify FK constraint still works after rename
do_execsql_test_on_specific_db {:memory:} alter-table-fk-constraint-after-rename {
PRAGMA foreign_keys = ON;
CREATE TABLE parent (id INTEGER PRIMARY KEY);
CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent(id));
INSERT INTO parent VALUES (1);
INSERT INTO child VALUES (1, 1);
ALTER TABLE parent RENAME COLUMN id TO parent_id;
-- This should work
INSERT INTO child VALUES (2, 1);
SELECT COUNT(*) FROM child;
} {
"2"
}
# FK constraint violation after rename should still fail
do_execsql_test_in_memory_any_error alter-table-fk-violation-after-rename {
PRAGMA foreign_keys = ON;
CREATE TABLE parent (id INTEGER PRIMARY KEY);
CREATE TABLE child (id INTEGER PRIMARY KEY, pid INTEGER, FOREIGN KEY (pid) REFERENCES parent(id));
INSERT INTO parent VALUES (1);
ALTER TABLE parent RENAME COLUMN id TO parent_id;
-- This should fail with FK violation
INSERT INTO child VALUES (1, 999);
}
# Complex scenario with multiple table constraints
do_execsql_test_on_specific_db {:memory:} alter-table-rename-complex-constraints {
CREATE TABLE t (
a INTEGER,
b TEXT,
c REAL,
PRIMARY KEY (a, b),
UNIQUE (b, c),
FOREIGN KEY (a) REFERENCES t(a)
);
ALTER TABLE t RENAME COLUMN a TO x;
ALTER TABLE t RENAME COLUMN b TO y;
SELECT sql FROM sqlite_schema WHERE name = 't';
} {
"CREATE TABLE t (x INTEGER, y TEXT, c REAL, PRIMARY KEY (x, y), UNIQUE (y, c), FOREIGN KEY (x) REFERENCES t (x))"
}
# Rename column that appears in both PK and FK
do_execsql_test_on_specific_db {:memory:} alter-table-rename-pk-and-fk {
CREATE TABLE parent (id INTEGER PRIMARY KEY);
CREATE TABLE child (
id INTEGER PRIMARY KEY,
parent_ref INTEGER,
FOREIGN KEY (id) REFERENCES parent(id),
FOREIGN KEY (parent_ref) REFERENCES parent(id)
);
ALTER TABLE parent RENAME COLUMN id TO pid;
SELECT sql FROM sqlite_schema WHERE name = 'child';
} {
"CREATE TABLE child (id INTEGER PRIMARY KEY, parent_ref INTEGER, FOREIGN KEY (id) REFERENCES parent (pid), FOREIGN KEY (parent_ref) REFERENCES parent (pid))"
}

View File

@@ -1107,9 +1107,7 @@ fn test_cdc_schema_changes_alter_table() {
Value::Text("t".to_string()),
Value::Text("t".to_string()),
Value::Integer(4),
Value::Text(
"CREATE TABLE t (x PRIMARY KEY, y PRIMARY KEY, z UNIQUE)".to_string()
)
Value::Text("CREATE TABLE t (x, y, z UNIQUE, PRIMARY KEY (x, y))".to_string())
])),
Value::Blob(record([
Value::Integer(0),
@@ -1135,9 +1133,7 @@ fn test_cdc_schema_changes_alter_table() {
Value::Text("t".to_string()),
Value::Text("t".to_string()),
Value::Integer(4),
Value::Text(
"CREATE TABLE t (x PRIMARY KEY, y PRIMARY KEY, z UNIQUE)".to_string()
)
Value::Text("CREATE TABLE t (x, y, z UNIQUE, PRIMARY KEY (x, y))".to_string())
])),
Value::Blob(record([
Value::Text("table".to_string()),
@@ -1145,7 +1141,7 @@ fn test_cdc_schema_changes_alter_table() {
Value::Text("t".to_string()),
Value::Integer(4),
Value::Text(
"CREATE TABLE t (x PRIMARY KEY, y PRIMARY KEY, z UNIQUE, t)".to_string()
"CREATE TABLE t (x, y, z UNIQUE, t, PRIMARY KEY (x, y))".to_string()
)
])),
Value::Blob(record([