Skip to content

Commit ba7dbbb

Browse files
committed
Patch driver to work around three Turso compatibility issues
- temporary_table_exists: short-circuit to false. Turso doesn't support TEMP tables or expose sqlite_temp_master, so the predicate is always false by definition. Fixes ~250 'no such table: sqlite_temp_master'. - sync_column_key_info: Turso's UPDATE parser rejects row-value assignment from a subquery (SET (a, b) = (SELECT ...)). Rewrite as two correlated subqueries, one per target column. Fixes ~40 '2 columns assigned 1 values' errors. - bootstrap.php: add a wp_die polyfill. Fixes 21 'Call to undefined function wp_die()' errors.
1 parent 43b7af5 commit ba7dbbb

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

.github/workflows/phpunit-tests-turso.yml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,133 @@ jobs:
420420
- name: Install gdb
421421
run: sudo apt-get install -y --no-install-recommends gdb
422422

423+
# These patches to the driver work around Turso behaviours that the SQL
424+
# layer in this repo currently assumes. Each is a localised rewrite so
425+
# the driver still produces correct behaviour when run against Turso;
426+
# they are not behaviour changes for real SQLite.
427+
- name: Patch driver for Turso compatibility
428+
working-directory: packages/mysql-on-sqlite
429+
run: |
430+
python3 - <<'PY'
431+
import re
432+
433+
# 1. Turso doesn't expose `sqlite_temp_master`. The driver queries it
434+
# to decide whether to use temp-schema tables, but Turso doesn't
435+
# support TEMP tables at all, so the predicate is always false.
436+
path = 'src/sqlite/class-wp-sqlite-information-schema-builder.php'
437+
src = open(path).read()
438+
old = (
439+
"\tpublic function temporary_table_exists( string $table_name ): bool {\n"
440+
"\t\t/*\n"
441+
"\t\t * We could search in the \"{$this->temporary_table_prefix}tables\" table,\n"
442+
"\t\t * but it may not exist yet, so using \"sqlite_temp_master\" is simpler.\n"
443+
"\t\t */\n"
444+
"\t\t$stmt = $this->connection->query(\n"
445+
"\t\t\t\"SELECT 1 FROM sqlite_temp_master WHERE type = 'table' AND name = ?\",\n"
446+
"\t\t\tarray( $table_name )\n"
447+
"\t\t);\n"
448+
"\t\treturn $stmt->fetchColumn() === '1';\n"
449+
"\t}"
450+
)
451+
new = (
452+
"\tpublic function temporary_table_exists( string $table_name ): bool {\n"
453+
"\t\t// Turso compatibility: it does not support TEMP tables or\n"
454+
"\t\t// expose sqlite_temp_master, so this is always false.\n"
455+
"\t\treturn false;\n"
456+
"\t}"
457+
)
458+
assert old in src, 'temporary_table_exists body not found'
459+
src = src.replace(old, new, 1)
460+
461+
# 2. Turso's UPDATE statement doesn't accept row-value assignment from
462+
# a subquery (`SET (a, b) = (SELECT ...)`). Rewrite the single query
463+
# in sync_column_key_info as two correlated subqueries, one per
464+
# target column.
465+
old = (
466+
"\t\t$this->connection->query(\n"
467+
"\t\t\t'\n"
468+
"\t\t\t\tUPDATE ' . $this->connection->quote_identifier( $columns_table_name ) . \" AS c\n"
469+
"\t\t\t\tSET (column_key, is_nullable) = (\n"
470+
"\t\t\t\t\tSELECT\n"
471+
"\t\t\t\t\t\tCASE\n"
472+
"\t\t\t\t\t\t\tWHEN MAX(s.index_name = 'PRIMARY') THEN 'PRI'\n"
473+
"\t\t\t\t\t\t\tWHEN MAX(s.non_unique = 0 AND s.seq_in_index = 1) THEN 'UNI'\n"
474+
"\t\t\t\t\t\t\tWHEN MAX(s.seq_in_index = 1) THEN 'MUL'\n"
475+
"\t\t\t\t\t\t\tELSE ''\n"
476+
"\t\t\t\t\t\tEND,\n"
477+
"\t\t\t\t\t\tCASE\n"
478+
"\t\t\t\t\t\t\tWHEN MAX(s.index_name = 'PRIMARY') THEN 'NO'\n"
479+
"\t\t\t\t\t\t\tELSE c.is_nullable\n"
480+
"\t\t\t\t\t\tEND\n"
481+
"\t\t\t\t\tFROM \" . $this->connection->quote_identifier( $statistics_table_name ) . ' AS s\n"
482+
"\t\t\t\t\tWHERE s.table_schema = c.table_schema\n"
483+
"\t\t\t\t\tAND s.table_name = c.table_name\n"
484+
"\t\t\t\t\tAND s.column_name = c.column_name\n"
485+
"\t\t\t\t)\n"
486+
"\t\t\t WHERE c.table_schema = ?\n"
487+
"\t\t\t AND c.table_name = ?\n"
488+
"\t\t\t',\n"
489+
"\t\t\tarray( self::SAVED_DATABASE_NAME, $table_name )\n"
490+
"\t\t);"
491+
)
492+
assert old in src, 'sync_column_key_info UPDATE not found'
493+
new = ''' $columns_table = $this->connection->quote_identifier( $columns_table_name );
494+
$statistics_table = $this->connection->quote_identifier( $statistics_table_name );
495+
$this->connection->query(
496+
"
497+
UPDATE $columns_table AS c
498+
SET column_key = (
499+
SELECT
500+
CASE
501+
WHEN MAX(s.index_name = 'PRIMARY') THEN 'PRI'
502+
WHEN MAX(s.non_unique = 0 AND s.seq_in_index = 1) THEN 'UNI'
503+
WHEN MAX(s.seq_in_index = 1) THEN 'MUL'
504+
ELSE ''
505+
END
506+
FROM $statistics_table AS s
507+
WHERE s.table_schema = c.table_schema
508+
AND s.table_name = c.table_name
509+
AND s.column_name = c.column_name
510+
),
511+
is_nullable = (
512+
SELECT
513+
CASE
514+
WHEN MAX(s.index_name = 'PRIMARY') THEN 'NO'
515+
ELSE c.is_nullable
516+
END
517+
FROM $statistics_table AS s
518+
WHERE s.table_schema = c.table_schema
519+
AND s.table_name = c.table_name
520+
AND s.column_name = c.column_name
521+
)
522+
WHERE c.table_schema = ?
523+
AND c.table_name = ?
524+
",
525+
array( self::SAVED_DATABASE_NAME, $table_name )
526+
);'''
527+
src = src.replace(old, new, 1)
528+
open(path, 'w').write(src)
529+
print('patched information-schema-builder.php')
530+
531+
# 3. wp_die polyfill: 21 tests hit an error path in the driver that
532+
# calls wp_die(). Real WordPress provides it; the unit-test bootstrap
533+
# does not. Add a minimal polyfill.
534+
path = 'tests/bootstrap.php'
535+
src = open(path).read()
536+
marker = "if ( ! function_exists( 'do_action' ) ) {"
537+
inject = (
538+
"if ( ! function_exists( 'wp_die' ) ) {\n"
539+
"\tfunction wp_die( $message = '', $title = '', $args = array() ) {\n"
540+
"\t\tthrow new \\RuntimeException( is_string( $message ) ? $message : 'wp_die' );\n"
541+
"\t}\n"
542+
"}\n\n"
543+
)
544+
assert marker in src
545+
src = src.replace(marker, inject + marker, 1)
546+
open(path, 'w').write(src)
547+
print('added wp_die polyfill to bootstrap.php')
548+
PY
549+
423550
- name: Capture failing SQL from the first failing driver test
424551
continue-on-error: true
425552
env:

0 commit comments

Comments
 (0)