@@ -8976,4 +8976,205 @@ public function testColumnInfoWithZeroRowsPhpBug(): void {
89768976 $ column_info [0 ]
89778977 );
89788978 }
8979+
8980+ public function testCheckConstraints (): void {
8981+ $ this ->assertQuery (
8982+ "CREATE TABLE t (
8983+ id INT NOT NULL CHECK (id > 0),
8984+ name VARCHAR(255) NOT NULL CHECK (name != ''),
8985+ score DOUBLE NOT NULL CHECK (score > 0 AND score < 100),
8986+ data JSON CHECK (json_valid(data)),
8987+ start_timestamp TIMESTAMP NOT NULL,
8988+ end_timestamp TIMESTAMP NOT NULL,
8989+ CONSTRAINT c1 CHECK (id < 10),
8990+ CONSTRAINT c2 CHECK (start_timestamp < end_timestamp),
8991+ CONSTRAINT c3 CHECK (length(data) < 20)
8992+ ) "
8993+ );
8994+
8995+ // Valid data.
8996+ $ this ->assertQuery (
8997+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
8998+ VALUES (1, 'test', 50, '2025-01-01 12:00:00', '2025-01-02 12:00:00', '{ \"key \": \"value \"}')
8999+ "
9000+ );
9001+
9002+ // Invalid ID.
9003+ $ exception = null ;
9004+ try {
9005+ $ this ->assertQuery (
9006+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9007+ VALUES (0, 'test', 50, '2025-01-01 12:00:00', '2025-01-02 12:00:00', '{ \"key \": \"value \"}')
9008+ "
9009+ );
9010+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9011+ $ exception = $ e ;
9012+ }
9013+ $ this ->assertNotNull ( $ exception );
9014+ $ this ->assertSame (
9015+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: t_chk_1 ' ,
9016+ $ exception ->getMessage ()
9017+ );
9018+
9019+ // Invalid name.
9020+ $ exception = null ;
9021+ try {
9022+ $ this ->assertQuery (
9023+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9024+ VALUES (1, '', 50, '2025-01-01 12:00:00', '2025-01-02 12:00:00', '{ \"key \": \"value \"}')
9025+ "
9026+ );
9027+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9028+ $ exception = $ e ;
9029+ }
9030+ $ this ->assertNotNull ( $ exception );
9031+ $ this ->assertSame (
9032+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: t_chk_2 ' ,
9033+ $ exception ->getMessage ()
9034+ );
9035+
9036+ // Invalid score.
9037+ $ exception = null ;
9038+ try {
9039+ $ this ->assertQuery (
9040+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9041+ VALUES (1, 'test', 100, '2025-01-01 12:00:00', '2025-01-02 12:00:00', '{ \"key \": \"value \"}')
9042+ "
9043+ );
9044+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9045+ $ exception = $ e ;
9046+ }
9047+ $ this ->assertNotNull ( $ exception );
9048+ $ this ->assertSame (
9049+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: t_chk_3 ' ,
9050+ $ exception ->getMessage ()
9051+ );
9052+
9053+ // Invalid data.
9054+ $ exception = null ;
9055+ try {
9056+ $ this ->assertQuery (
9057+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9058+ VALUES (1, 'test', 50, '2025-01-01 12:00:00', '2025-01-02 12:00:00', 'invalid JSON')
9059+ "
9060+ );
9061+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9062+ $ exception = $ e ;
9063+ }
9064+ $ this ->assertNotNull ( $ exception );
9065+ $ this ->assertSame (
9066+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: t_chk_4 ' ,
9067+ $ exception ->getMessage ()
9068+ );
9069+
9070+ // Invalid c1.
9071+ $ exception = null ;
9072+ try {
9073+ $ this ->assertQuery (
9074+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9075+ VALUES (11, 'test', 50, '2025-01-01 12:00:00', '2025-01-02 12:00:00', '{ \"key \": \"value \"}')
9076+ "
9077+ );
9078+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9079+ $ exception = $ e ;
9080+ }
9081+ $ this ->assertNotNull ( $ exception );
9082+ $ this ->assertSame (
9083+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: c1 ' ,
9084+ $ exception ->getMessage ()
9085+ );
9086+
9087+ // Invalid c2.
9088+ $ exception = null ;
9089+ try {
9090+ $ this ->assertQuery (
9091+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9092+ VALUES (1, 'test', 50, '2025-01-02 12:00:00', '2025-01-01 12:00:00', '{ \"key \": \"value \"}')
9093+ "
9094+ );
9095+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9096+ $ exception = $ e ;
9097+ }
9098+ $ this ->assertNotNull ( $ exception );
9099+ $ this ->assertSame (
9100+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: c2 ' ,
9101+ $ exception ->getMessage ()
9102+ );
9103+
9104+ // Invalid c3.
9105+ $ exception = null ;
9106+ try {
9107+ $ this ->assertQuery (
9108+ "INSERT INTO t (id, name, score, start_timestamp, end_timestamp, data)
9109+ VALUES (1, 'test', 50, '2025-01-01 12:00:00', '2025-01-02 12:00:00', '{ \"key \": \"a-very-long-value \"}')
9110+ "
9111+ );
9112+ } catch ( WP_SQLite_Driver_Exception $ e ) {
9113+ $ exception = $ e ;
9114+ }
9115+ $ this ->assertNotNull ( $ exception );
9116+ $ this ->assertSame (
9117+ 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: c3 ' ,
9118+ $ exception ->getMessage ()
9119+ );
9120+
9121+ // SHOW CREATE TABLE
9122+ $ result = $ this ->assertQuery ( 'SHOW CREATE TABLE t ' );
9123+ $ this ->assertCount ( 1 , $ result );
9124+ $ this ->assertEquals (
9125+ implode (
9126+ "\n" ,
9127+ array (
9128+ 'CREATE TABLE `t` ( ' ,
9129+ ' `id` int NOT NULL, ' ,
9130+ ' `name` varchar(255) NOT NULL, ' ,
9131+ ' `score` double NOT NULL, ' ,
9132+ ' `data` json DEFAULT NULL, ' ,
9133+ ' `start_timestamp` timestamp NOT NULL, ' ,
9134+ ' `end_timestamp` timestamp NOT NULL, ' ,
9135+
9136+ // The of the check expressions below is not 100% matching MySQL,
9137+ // because in MySQL the expressions are parsed and normalized.
9138+ ' CONSTRAINT `c1` CHECK ( id < 10 ), ' ,
9139+ ' CONSTRAINT `c2` CHECK ( start_timestamp < end_timestamp ), ' ,
9140+ ' CONSTRAINT `c3` CHECK ( length ( data ) < 20 ), ' ,
9141+ ' CONSTRAINT `t_chk_1` CHECK ( id > 0 ), ' ,
9142+ " CONSTRAINT `t_chk_2` CHECK ( name != '' ), " ,
9143+ ' CONSTRAINT `t_chk_3` CHECK ( score > 0 AND score < 100 ), ' ,
9144+ ' CONSTRAINT `t_chk_4` CHECK ( json_valid ( data ) ) ' ,
9145+ ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ' ,
9146+ )
9147+ ),
9148+ $ result [0 ]->{'Create Table ' }
9149+ );
9150+ }
9151+
9152+ public function testAlterTableAddCheckConstraint (): void {
9153+ $ this ->assertQuery ( 'CREATE TABLE t (id INT) ' );
9154+ $ this ->assertQuery ( 'ALTER TABLE t ADD CONSTRAINT c CHECK (id > 0) ' );
9155+
9156+ // SHOW CREATE TABLE
9157+ $ this ->assertQuery ( 'SHOW CREATE TABLE t ' );
9158+ $ result = $ this ->engine ->get_query_results ();
9159+ $ this ->assertEquals (
9160+ implode (
9161+ "\n" ,
9162+ array (
9163+ 'CREATE TABLE `t` ( ' ,
9164+ ' `id` int DEFAULT NULL, ' ,
9165+ ' CONSTRAINT `c` CHECK ( id > 0 ) ' ,
9166+ ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ' ,
9167+ )
9168+ ),
9169+ $ result [0 ]->{'Create Table ' }
9170+ );
9171+
9172+ // Insert valid data.
9173+ $ this ->assertQuery ( 'INSERT INTO t (id) VALUES (1) ' );
9174+
9175+ // Insert invalid data.
9176+ $ this ->expectException ( WP_SQLite_Driver_Exception::class );
9177+ $ this ->expectExceptionMessage ( 'SQLSTATE[23000]: Integrity constraint violation: 19 CHECK constraint failed: c ' );
9178+ $ this ->assertQuery ( 'INSERT INTO t (id) VALUES (0) ' );
9179+ }
89799180}
0 commit comments