Files
turso/testing/alter_column.test
2025-10-21 10:47:08 -04:00

241 lines
9.6 KiB
Tcl
Executable File

#!/usr/bin/env tclsh
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test_on_specific_db {:memory:} alter-column-rename-and-type {
CREATE TABLE t (a INTEGER);
CREATE INDEX i ON t (a);
ALTER TABLE t ALTER COLUMN a TO b BLOB;
SELECT sql FROM sqlite_schema;
} {
"CREATE TABLE t (b BLOB)"
"CREATE INDEX i ON t (b)"
}
do_execsql_test_in_memory_any_error fail-alter-column-primary-key {
CREATE TABLE t (a);
ALTER TABLE t ALTER COLUMN a TO a PRIMARY KEY;
}
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))"
}