Skip to content

Commit dc09446

Browse files
committed
Add support for CHECK constraints
1 parent 8d63ed0 commit dc09446

File tree

4 files changed

+412
-38
lines changed

4 files changed

+412
-38
lines changed

tests/WP_SQLite_Driver_Tests.php

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)