Skip to content

Fix temporary table lookup without stringified fetches and with a different case - #522

Merged
JanJakes merged 3 commits into
WordPress:trunkfrom
Nandan108:fix/temporary-table-exists-lookup
Oct 13, 2026
Merged

JanJakes merged 3 commits into
WordPress:trunkfrom
Nandan108:fix/temporary-table-exists-lookup

Conversation

@Nandan108

@Nandan108 Nandan108 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The internal check for whether a table is temporary (temporary_table_exists()) has two defects. It is used by ALTER TABLE, DROP TABLE, SHOW COLUMNS, SHOW CREATE TABLE, DESCRIBE, UPDATE, and others to decide whether to use the temporary or the standard information schema.

  1. It compares the fetched value to the string '1'. PDO SQLite returns native types unless PDO::ATTR_STRINGIFY_FETCHES is set, so on PHP 8.1 and newer, the check never finds a temporary table for callers that don't set that attribute. The WordPress plugin and the MySQL proxy set it, so they are unaffected, but the PDO-compatible API is:

    $pdo = new WP_MySQL_On_SQLite( 'mysql-on-sqlite:dbname=wp', ... );
    $pdo->query( 'CREATE TEMPORARY TABLE t (a INT)' );
    $pdo->query( 'ALTER TABLE t ADD COLUMN b INT' );
    // SQLSTATE[42S02]: Base table or view not found: 1146 Table 't' doesn't exist

    When a standard table of the same name exists, the statement silently applies to that table instead.

  2. It matches the table name case-sensitively, unlike the information schema tables (COLLATE NOCASE), so a temporary table is not found by a differently cased name:

    CREATE TEMPORARY TABLE t (a INT);
    ALTER TABLE T ADD COLUMN b INT;
    -- SQLSTATE[42S02]: Base table or view not found: 1146 Table 'T' doesn't exist

Fix

The lookup matches the name with COLLATE NOCASE and checks the fetched value for presence (false !== fetchColumn()) rather than comparing it to a string. The translation tests filter this query out of the recorded SQLite statements by its text, so the filter is updated to match.

Queries to the information schema no longer use this lookup with the name of the information schema table, such as columns. Temporary tables are not listed in the information schema, but with a case-insensitive lookup, a temporary table named Columns would hide all standard tables from information_schema.columns.

Tests

  • testTemporaryTableHasPriorityOverStandardTable runs with stringified fetches enabled and disabled.
  • testTemporaryTableIsFoundByDifferentlyCasedName uses a differently cased name in ALTER TABLE, SHOW COLUMNS, and DROP TABLE while a standard table with the same name exists.
  • testTemporaryTableNamedLikeInformationSchemaTable checks that temporary tables named like information schema tables don't change the information schema results.

All three fail on trunk.

Found while preparing a fix for CREATE TEMPORARY TABLE IF NOT EXISTS, which will reuse this lookup.

Part of #451.

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
    • Temporary tables are recognized regardless of capitalization or database fetch format.
    • ALTER TABLE and DROP TABLE correctly target temporary tables when names differ only by capitalization or overlap with a regular table.
    • Temporary tables named after information schema tables no longer appear in those schema results; the corresponding standard tables remain visible. Column listings continue to resolve differently cased references to temporary tables.

…ferent case

The temporary table lookup compared the fetched value to the string "1".
PDO SQLite returns native types unless fetches are stringified, so on
PHP 8.1 and newer, the lookup never found a temporary table for callers
that don't set PDO::ATTR_STRINGIFY_FETCHES. Statements like ALTER TABLE,
SHOW COLUMNS, or DESCRIBE then failed or used a standard table of the same
name instead.

The lookup also matched the table name case-sensitively, unlike the
information schema tables, so a temporary table was not found when the
statement used a differently cased name.

Match the name case-insensitively and check the fetched value for presence
rather than comparing it to a string.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 12, 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: ecb5793f-0ba6-4feb-b668-3ed4fd76cf21
📥 Commits

Reviewing files that changed from the base of the PR and between be0bdf8 and 7a8d622.

📒 Files selected for processing (2)
  • packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php
  • packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_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

Temporary-table existence checks now match names without regard to case and accept any fetched value other than false. Table-reference translation always uses the non-temporary information-schema mapping. Tests cover fetch stringification, differently cased references, and temporary tables named like information-schema tables.

Changes: Temporary-table resolution

Layer / File(s) Summary
Temporary-table lookup and tests
packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php, packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php, packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Translation_Tests.php
The existence check uses a case-insensitive name match and treats any fetched value other than false as a match. Tests cover differently cased ALTER TABLE and DROP TABLE references, temporary-table priority with both fetch-stringification settings, and the updated query filter.
Information-schema table resolution
packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php, packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php
Table-reference translation always uses the non-temporary information-schema mapping. Tests verify that temporary tables named tables, COLUMNS, or Statistics do not replace matching standard-table metadata.

Priority: ➖ Normal

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

Change: Bug fix

Suggested reviewers: janjakes

Merge Risk: ⚪ Minimal · up to 7a8d6

No actionable merge-blocking issue is identified; 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 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 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 summarizes the main change: fixing temporary-table lookup for non-stringified fetches and case differences.
  • 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.

When translating a reference to an information schema table, the driver
checked whether a temporary table with the same name existed, such as
"columns". If it did, the query read the temporary table metadata instead
of the standard one, so all standard tables disappeared from the result.

With the case-insensitive temporary table lookup, any differently cased
name triggers this too, e.g., a temporary table named "Columns".

Temporary tables are not listed in the information schema, so always read
the standard table metadata.
Test the differently cased name with a standard table of the same name,
including DROP TABLE. Before the lookup fix, DROP TABLE removed the
temporary table, but deleted the metadata of the standard table.

Run the temporary table priority test with stringified fetches both
enabled and disabled instead of keeping a partial copy of it.
@JanJakes

Copy link
Copy Markdown
Member

Thanks for the contribution, @Nandan108! The fix looks good.

I pushed two small improvements:

  1. Ignore temporary tables named like information schema tables: With the case-insensitive lookup, a temporary table named Columns would hide all standard tables from information_schema.columns.
  2. Extend temporary table lookup tests: Covers DROP TABLE with a differently cased name, and runs the priority test with stringified fetches on and off.

@JanJakes
JanJakes merged commit ed86f8b into WordPress:trunk Oct 13, 2026
24 checks passed
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