Skip to content

Fix matching a foreign key reference to a unique key with a different case - #534

Merged
JanJakes merged 2 commits into
WordPress:trunkfrom
Nandan108:fix/foreign-key-column-case
Oct 14, 2026
Merged

JanJakes merged 2 commits into
WordPress:trunkfrom
Nandan108:fix/foreign-key-column-case

Conversation

@Nandan108

@Nandan108 Nandan108 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #523.

When a foreign key references columns with a different letter case than the referenced table declares them, the referenced unique constraint is not found:

CREATE TABLE t1 (id INT, name VARCHAR(255), PRIMARY KEY (id, name));
CREATE TABLE t2 (id INT, name VARCHAR(255), FOREIGN KEY (id, name) REFERENCES t1 (ID, Name));
SELECT unique_constraint_name FROM information_schema.referential_constraints WHERE table_name = 't2';
-- NULL   (MySQL: PRIMARY)

MySQL column names are case-insensitive, but the lookup compared the referenced column names to the index columns with !==. The foreign key itself works, since SQLite also matches column names case-insensitively; only the information schema entry is wrong.

Fix

The names are compared case-insensitively with strcasecmp(), which compares them directly, without creating lowercased copies first. Identifiers are restricted to ASCII in this driver, so this is sufficient.

Tests

testInformationSchemaForeignKeysReferencingColumnsInDifferentLetterCase references a single-column primary key, a composite unique key, and a unique key in a foreign key added with ALTER TABLE, all with differently cased column names, and checks UNIQUE_CONSTRAINT_NAME. It fails on trunk with NULL for all three.

Use of AI

This change was prepared with Claude Code (Claude Fable 5.1). I reviewed the code, the tests, and this description, and I take responsibility for the change.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Foreign-key metadata now correctly matches referenced columns when their names use different letter casing. This applies to single-column and composite references, whether constraints are defined during table creation or added afterward.
    • Information schema results now identify the expected unique indexes for these foreign-key references, including primary-key references.

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: e13039da-9f4f-4a36-814a-e16eb54adafc
📥 Commits

Reviewing files that changed from the base of the PR and between 81d6afa and bffd503.

📒 Files selected for processing: 2
  • packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php
  • packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

📝 Walkthrough

The information-schema builder now matches referenced foreign-key columns without regard to letter case. A metadata test covers references to primary and composite unique keys, including an added constraint.

Changes: Foreign-key metadata matching

Layer / File(s) Summary
Match referenced columns and validate metadata
packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php, packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Metadata_Tests.php
The builder uses case-insensitive comparison when matching referenced columns to unique-index prefixes. The test checks metadata for primary-key, composite unique-key, and added-constraint references with different letter casing.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Suggested reviewers: janjakes

Merge Risk: ⚪ Minimal · up to bffd5

The foreign-key metadata change appears ready to merge after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: fixing case-sensitive matching between foreign key references and unique keys.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Nandan108 and others added 2 commits October 14, 2026 17:17
… 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 <noreply@anthropic.com>
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.
@JanJakes
JanJakes force-pushed the fix/foreign-key-column-case branch from e3a7785 to bffd503 Compare October 14, 2026 15:18
@JanJakes

Copy link
Copy Markdown
Member

Thanks again, @Nandan108! I rebased the branch on the latest trunk and pushed one commit on top with small improvements (strcasecmp() to avoid string allocation, improved test coverage).

@JanJakes
JanJakes merged commit 4d94f39 into WordPress:trunk Oct 14, 2026
24 checks passed
@JanJakes JanJakes mentioned this pull request Oct 21, 2026
JanJakes added a commit that referenced this pull request Oct 21, 2026
## Release `3.1.1`

Version bump and changelog update for release `3.1.1`.

**Changelog draft:**
* Support date arithmetic with `INTERVAL` operators
([#539](#539))
* Fix `ROLLBACK` as the first transaction of a connection
([#537](#537))
* Fix matching a foreign key reference to a unique key with a different
case
([#534](#534))
* Fix `FOUND_ROWS()` without `SQL_CALC_FOUND_ROWS`
([#533](#533))
* Fix unique keys and foreign key restore without stringified fetches
([#532](#532))
* Fix `CREATE TEMPORARY TABLE IF NOT EXISTS` and `DROP TEMPORARY TABLE`
as the first temporary table
([#524](#524))
* Fix a warning for a foreign key referencing a table with a shorter
unique key
([#523](#523))
* Fix temporary table lookup without stringified fetches and with a
different case
([#522](#522))

**Full changelog:**
v3.1.0...release/v3.1.1

## Next steps

1. **Review** the changes in this pull request.
2. **Push** any additional edits to this branch (`release/v3.1.1`).
3. **Merge** this pull request to complete the release.

Merging will automatically build the plugin ZIP, create a [GitHub
release](https://github.com/WordPress/sqlite-database-integration/releases),
and deploy to
[WordPress.org](https://wordpress.org/plugins/sqlite-database-integration/).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants