From 84b16939c3e82a2816c28c5fa6eeca38cc39ced7 Mon Sep 17 00:00:00 2001 From: Samuel de Rougemont Date: Tue, 13 Oct 2026 16:39:05 +0200 Subject: [PATCH 1/2] Fix matching a foreign key reference to a unique key with a different case When looking for the unique constraint that a foreign key references, the referenced column names were compared to the index columns case-sensitively. MySQL column names are case-insensitive, so a reference like "REFERENCES t1 (ID)" to a column "id" found no unique constraint, and UNIQUE_CONSTRAINT_NAME in information_schema.referential_constraints was NULL. Compare the column names case-insensitively. Co-Authored-By: Claude Fable 5.1 --- ...s-wp-sqlite-information-schema-builder.php | 3 ++- .../WP_MySQL_On_SQLite_Metadata_Tests.php | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php index bbd3728fb..db1020d89 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php @@ -1820,9 +1820,10 @@ private function extract_referential_constraint_data( WP_Parser_Node $node, stri continue; } + // Column names are case-insensitive in MySQL. $is_prefix = true; foreach ( $reference_parts as $i => $reference_part ) { - if ( $index_columns[ $i ] !== $this->get_value( $reference_part ) ) { + if ( strtolower( $index_columns[ $i ] ) !== strtolower( $this->get_value( $reference_part ) ) ) { $is_prefix = false; break; } diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php index 7dfb79548..daf4a1c12 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php @@ -1943,6 +1943,27 @@ public function testInformationSchemaForeignKeysReferencingShorterUniqueKey(): v ); } + public function testInformationSchemaForeignKeysReferencingDifferentlyCasedColumns(): void { + $this->assertQuery( 'CREATE TABLE t1 (id INT, name VARCHAR(255), PRIMARY KEY (id, name))' ); + $this->assertQuery( + 'CREATE TABLE t2 ( + id INT, + name VARCHAR(255), + FOREIGN KEY (id, name) REFERENCES t1 (ID, Name) + )' + ); + + $result = $this->assertQuery( "SELECT unique_constraint_name FROM information_schema.referential_constraints WHERE table_name = 't2'" ); + $this->assertEquals( + array( + (object) array( + 'UNIQUE_CONSTRAINT_NAME' => 'PRIMARY', + ), + ), + $result + ); + } + public function testInformationSchemaAlterTableAddForeignKeys(): void { $this->assertQuery( 'CREATE TABLE t1 (id INT PRIMARY KEY, name VARCHAR(255))' ); $this->assertQuery( 'CREATE TABLE t2 (id INT)' ); From bffd50371785719c92ae3fa4f033d3c105d3246c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 14 Oct 2026 17:04:15 +0200 Subject: [PATCH 2/2] Use strcasecmp() and test more foreign key references Compare the column names with strcasecmp() instead of lowercasing both. Extend the test to cover a single-column PRIMARY KEY, a composite UNIQUE key, and a foreign key added with ALTER TABLE. --- ...s-wp-sqlite-information-schema-builder.php | 2 +- .../WP_MySQL_On_SQLite_Metadata_Tests.php | 38 ++++++++++++++++--- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php index db1020d89..9cd5c3dfd 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php @@ -1823,7 +1823,7 @@ private function extract_referential_constraint_data( WP_Parser_Node $node, stri // Column names are case-insensitive in MySQL. $is_prefix = true; foreach ( $reference_parts as $i => $reference_part ) { - if ( strtolower( $index_columns[ $i ] ) !== strtolower( $this->get_value( $reference_part ) ) ) { + if ( 0 !== strcasecmp( $index_columns[ $i ], $this->get_value( $reference_part ) ) ) { $is_prefix = false; break; } diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php index daf4a1c12..1215dd288 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php @@ -1943,22 +1943,48 @@ public function testInformationSchemaForeignKeysReferencingShorterUniqueKey(): v ); } - public function testInformationSchemaForeignKeysReferencingDifferentlyCasedColumns(): void { - $this->assertQuery( 'CREATE TABLE t1 (id INT, name VARCHAR(255), PRIMARY KEY (id, name))' ); + public function testInformationSchemaForeignKeysReferencingColumnsInDifferentLetterCase(): void { + $this->assertQuery( + 'CREATE TABLE t1 ( + id INT PRIMARY KEY, + code INT, + a INT NOT NULL, + b INT NOT NULL, + UNIQUE KEY u_code (code), + UNIQUE KEY u_a_b (a, b) + )' + ); $this->assertQuery( 'CREATE TABLE t2 ( - id INT, - name VARCHAR(255), - FOREIGN KEY (id, name) REFERENCES t1 (ID, Name) + t1_id INT, + x INT, + y INT, + FOREIGN KEY (t1_id) REFERENCES t1 (ID), + FOREIGN KEY (x, y) REFERENCES t1 (A, b) )' ); + $this->assertQuery( 'ALTER TABLE t2 ADD COLUMN z INT, ADD CONSTRAINT fk_z FOREIGN KEY (z) REFERENCES t1 (CoDe)' ); - $result = $this->assertQuery( "SELECT unique_constraint_name FROM information_schema.referential_constraints WHERE table_name = 't2'" ); + $result = $this->assertQuery( + "SELECT constraint_name, unique_constraint_name + FROM information_schema.referential_constraints + WHERE table_name = 't2' + ORDER BY constraint_name" + ); $this->assertEquals( array( (object) array( + 'CONSTRAINT_NAME' => 'fk_z', + 'UNIQUE_CONSTRAINT_NAME' => 'u_code', + ), + (object) array( + 'CONSTRAINT_NAME' => 't2_ibfk_1', 'UNIQUE_CONSTRAINT_NAME' => 'PRIMARY', ), + (object) array( + 'CONSTRAINT_NAME' => 't2_ibfk_2', + 'UNIQUE_CONSTRAINT_NAME' => 'u_a_b', + ), ), $result );