# 2025 September 18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altercons # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { finish_test return } foreach {tn before after} { 1 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b)) } { CREATE TABLE t1(a, b) } 2 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) NOT NULL) } { CREATE TABLE t1(a, b NOT NULL) } 3 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b)NOT NULL) } { CREATE TABLE t1(a, b NOT NULL) } 3 { CREATE TABLE t1(a, b NOT NULL CONSTRAINT abc CHECK(t1.a != t1.b)); } { CREATE TABLE t1(a, b NOT NULL) } 4 { CREATE TABLE t1(a, b, CONSTRAINT abc CHECK(t1.a != t1.b)) } { CREATE TABLE t1(a, b) } 5 { CREATE TABLE t1(a, b, CONSTRAINT abc CHECK(t1.a != t1.b), PRIMARY KEY(a))} { CREATE TABLE t1(a, b, PRIMARY KEY(a)) } 6 { CREATE TABLE t1(a, b,CONSTRAINT abc CHECK(t1.a != t1.b),PRIMARY KEY(a))} { CREATE TABLE t1(a, b,PRIMARY KEY(a)) } 7 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) CONSTRAINT def UNIQUE) } { CREATE TABLE t1(a, b CONSTRAINT def UNIQUE) } 8 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) CHECK (123)) } { CREATE TABLE t1(a, b CHECK (123)) } 9 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) DEFAULT NULL) } { CREATE TABLE t1(a, b DEFAULT NULL) } 10 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) COLLATE nocase) } { CREATE TABLE t1(a, b COLLATE nocase) } 11 { CREATE TABLE t1(a, b CONSTRAINT abc CHECK(t1.a != t1.b) REFERENCES t2) } { CREATE TABLE t1(a, b REFERENCES t2) } 12 { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT abc CHECK(a!=b) CONSTRAINT three) } { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT three) } 13 { CREATE TABLE t1(a, b, c, CONSTRAINT abc CONSTRAINT one CHECK(a!=b) CONSTRAINT three) } { CREATE TABLE t1(a, b, c, CONSTRAINT one CHECK(a!=b) CONSTRAINT three) } 14 { CREATE TABLE t1(a, b, c, CONSTRAINT abc) } { CREATE TABLE t1(a, b, c) } 15 { CREATE TABLE t1(a, b, c, CONSTRAINT abc, CHECK( a!=b )) } { CREATE TABLE t1(a, b, c, CHECK( a!=b )) } 16 { CREATE TABLE t1(a, b, c, CONSTRAINT abc /* hello */ CHECK( a!=b )) } { CREATE TABLE t1(a, b, c) } 17 { CREATE TABLE t1(a, b, c, /* world */ CONSTRAINT abc CHECK( a!=b )) } { CREATE TABLE t1(a, b, c) } 18 { CREATE TABLE t1(a, b, c -- comment CONSTRAINT abc NOT NULL ) } { CREATE TABLE t1(a, b, c) } 19 { CREATE TABLE t1(a, b, c, -- comment CONSTRAINT abc CHECK (a>b) CONSTRAINT two ) } { CREATE TABLE t1(a, b, c, CONSTRAINT two ) } 20 { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT abc CHECK (a>b)CONSTRAINT two) } { CREATE TABLE t1(a, b, c, CONSTRAINT one CONSTRAINT two) } 21 { CREATE TABLE t1(a, b, c CONSTRAINT abc AS (b+1)) } { CREATE TABLE t1(a, b, c AS (b+1)) } 22 { CREATE TABLE t1(a, b, c CONSTRAINT abc GENERATED ALWAYS AS (b+1) STORED) } { CREATE TABLE t1(a, b, c GENERATED ALWAYS AS (b+1) STORED) } } { reset_db do_execsql_test 1.$tn.0 $before do_execsql_test 1.$tn.1 { ALTER TABLE t1 DROP CONSTRAINT abc; } {} do_execsql_test 1.$tn.2 { SELECT sql FROM sqlite_schema WHERE name='t1' } [list [string trim $after]] } #------------------------------------------------------------------------- do_execsql_test 2.0 { CREATE TABLE t2(x, y CONSTRAINT ccc UNIQUE); } do_catchsql_test 2.1 { ALTER TABLE t2 DROP CONSTRAINT ccc } {1 {constraint may not be dropped: ccc}} do_catchsql_test 2.2 { ALTER TABLE t2 DROP CONSTRAINT ddd } {1 {no such constraint: ddd}} #------------------------------------------------------------------------- reset_db foreach {tn col before after} { 1 a { CREATE TABLE t1(a NOT NULL, b) } { CREATE TABLE t1(a, b) } 2 a { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL, b) } { CREATE TABLE t1(a, b) } 3 a { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL UNIQUE, b) } { CREATE TABLE t1(a UNIQUE, b) } 4 b { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL UNIQUE, b) } { CREATE TABLE t1(a NOT NULL ON CONFLICT FAIL UNIQUE, b) } 5 a { CREATE TABLE t1(a CHECK(a=0) } { CREATE TABLE t1(a, b, CONSTRAINT nn CHECK (a>=0)) } 2 { CREATE TABLE t1(a, b ) } { ALTER TABLE t1 ADD CONSTRAINT nn CHECK (a>=0) } { CREATE TABLE t1(a, b , CONSTRAINT nn CHECK (a>=0)) } 3 { CREATE TABLE t1(a, b ) } { ALTER TABLE t1 ADD CHECK (a>=0) } { CREATE TABLE t1(a, b , CHECK (a>=0)) } } { reset_db do_execsql_test 6.3.$tn.1 $before do_execsql_test 6.3.$tn.2 $alter do_execsql_test 6.3.$tn.3 { SELECT sql FROM sqlite_schema WHERE type='table'; } [list [string trim $after]] } do_execsql_test 6.4.1 { CREATE TABLE b1(a, b, CONSTRAINT abc CHECK (a!=2)); } do_catchsql_test 6.4.2 { ALTER TABLE b1 ADD CONSTRAINT abc CHECK (a!=3); } {1 {constraint abc already exists}} do_execsql_test 6.4.1 { SELECT sql FROM sqlite_schema WHERE tbl_name='b1' } {{CREATE TABLE b1(a, b, CONSTRAINT abc CHECK (a!=2))}} do_execsql_test 6.5 { CREATE TABLE abc(x,y); } do_catchsql_test 6.6 { ALTER TABLE abc ADD CHECK (z>=0); } {1 {no such column: z}} #------------------------------------------------------------------------- # Try attaching a NOT NULL to a generated column. # reset_db do_execsql_test 7.0 { CREATE TABLE x1(a, b AS (a+1)); INSERT INTO x1 VALUES(1), (2), (3), (NULL); } do_catchsql_test 7.1 { ALTER TABLE x1 ALTER b SET NOT NULL; } {1 {constraint failed}} do_catchsql_test 7.2 { DELETE FROM x1 WHERE b IS NULL; ALTER TABLE x1 ALTER b SET NOT NULL; } {0 {}} do_execsql_test 7.3 { SELECT b FROM x1 } {2 3 4} do_catchsql_test 7.4 { ALTER TABLE x1 ALTER rowid SET NOT NULL; } {1 {no such column: rowid}} do_execsql_test 7.5 { CREATE VIEW v1 AS SELECT a, b FROM x1; } do_catchsql_test 7.6 { ALTER TABLE v1 RENAME a TO c; } {1 {cannot rename columns of view "v1"}} do_catchsql_test 7.7 { ALTER TABLE v1 ALTER a SET NOT NULL; } {1 {cannot edit constraints of view "v1"}} do_catchsql_test 7.8 { ALTER TABLE sqlite_schema ALTER sql SET NOT NULL; } {1 {table sqlite_master may not be altered}} do_catchsql_test 7.9 { ALTER TABLE v1 ALTER a DROP NOT NULL } {1 {cannot edit constraints of view "v1"}} #------------------------------------------------------------------------- reset_db do_execsql_test 8.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b NOT NULL, c CHECK (c!=555), d); INSERT INTO t1 VALUES(1, 1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3, 3); } do_execsql_test 8.1.1 { ALTER TABLE t1 ALTER a SET NOT NULL; ALTER TABLE t1 ALTER b SET NOT NULL; ALTER TABLE t1 ALTER c SET NOT NULL; ALTER TABLE t1 ALTER d SET NOT NULL; } do_execsql_test 8.1.2 { SELECT sql FROM sqlite_schema WHERE tbl_name = 't1' } {{CREATE TABLE t1(a INTEGER PRIMARY KEY NOT NULL, b NOT NULL, c CHECK (c!=555) NOT NULL, d NOT NULL)}} do_execsql_test 8.1.3 { SELECT * FROM t1 WHERE a=2; } {2 2 2 2} do_execsql_test 8.2.1 { ALTER TABLE t1 ALTER a DROP NOT NULL; ALTER TABLE t1 ALTER b DROP NOT NULL; ALTER TABLE t1 ALTER c DROP NOT NULL; ALTER TABLE t1 ALTER d DROP NOT NULL; } do_execsql_test 8.2.2 { SELECT sql FROM sqlite_schema WHERE tbl_name = 't1' } {{CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c CHECK (c!=555), d)}} do_execsql_test 8.2.3 { SELECT * FROM t1 WHERE a=3; } {3 3 3 3} #------------------------------------------------------------------------- reset_db forcedelete test.db2 do_execsql_test 9.0 { CREATE TABLE t1(x, y, z); ATTACH 'test.db2' AS aux; CREATE TABLE aux.t1(x, y, z); INSERT INTO aux.t1 VALUES(1, 1, 1); INSERT INTO aux.t1 VALUES(2, 2, 2); INSERT INTO aux.t1 VALUES(3, 3, NULL); CREATE TABLE aux.t2(x, y, z); } do_catchsql_test 9.1.1 { ALTER TABLE aux.t1 ALTER COLUMN z SET NOT NULL } {1 {constraint failed}} do_execsql_test 9.1.2 { UPDATE aux.t1 SET z=x; ALTER TABLE aux.t1 ALTER COLUMN z SET NOT NULL; SELECT sql FROM aux.sqlite_schema WHERE name='t1'; } {{CREATE TABLE t1(x, y, z NOT NULL)}} do_execsql_test 9.1.3 { ALTER TABLE aux.t1 ALTER z DROP NOT NULL; SELECT sql FROM aux.sqlite_schema WHERE name='t1'; } {{CREATE TABLE t1(x, y, z)}} do_execsql_test 9.1.4 { ALTER TABLE t2 ALTER x SET NOT NULL; SELECT sql FROM aux.sqlite_schema WHERE name='t2'; } {{CREATE TABLE t2(x NOT NULL, y, z)}} do_execsql_test 9.1.5 { ALTER TABLE t2 ALTER x DROP NOT NULL; SELECT sql FROM aux.sqlite_schema WHERE name='t2'; } {{CREATE TABLE t2(x, y, z)}} do_catchsql_test 9.2.1 { ALTER TABLE aux.t1 ADD CONSTRAINT bill CHECK (y!=2); } {1 {constraint failed}} do_execsql_test 9.2.2 { UPDATE aux.t1 SET y=4 WHERE y=2; ALTER TABLE aux.t1 ADD CONSTRAINT bill CHECK (y!=2); SELECT sql FROM aux.sqlite_schema WHERE name='t1'; } {{CREATE TABLE t1(x, y, z, CONSTRAINT bill CHECK (y!=2))}} do_execsql_test 9.2.3 { ALTER TABLE aux.t1 DROP CONSTRAINT bill; SELECT sql FROM aux.sqlite_schema WHERE name='t1'; } {{CREATE TABLE t1(x, y, z)}} do_execsql_test 9.2.4 { ALTER TABLE t2 ADD CONSTRAINT william CHECK (z!=''); SELECT sql FROM aux.sqlite_schema WHERE name='t2'; } {{CREATE TABLE t2(x, y, z, CONSTRAINT william CHECK (z!=''))}} do_execsql_test 9.2.5 { ALTER TABLE t2 DROP CONSTRAINT william; SELECT sql FROM aux.sqlite_schema WHERE name='t2'; } {{CREATE TABLE t2(x, y, z)}} finish_test