Some VPS configs can't get pdo_sqlite at all — Ubuntu 20.04 with Ondrej
Sury's PHP 8.3 builds doesn't ship php8.3-sqlite3, and OS upgrade isn't
always an option. Make MySQL the documented default while keeping SQLite
working where it's available.
- Schema (0001_initial.sql): TEXT → VARCHAR(N), INTEGER → BIGINT, keys
declared with explicit PRIMARY KEY (...) syntax. Drops the previously
unused request_log table (it had AUTO_INCREMENT, which spells
differently on each engine and nothing wrote to it anyway). Both
engines accept the new column types and indexes are IF NOT EXISTS for
retry-safety.
- Migrations.php: guard commit()/rollBack() with inTransaction(). MySQL
implicitly commits any open transaction the moment it sees a DDL
statement, so by the time we explicitly commit() the transaction is
already gone and PDO throws "There is no active transaction". Same
schema in PHP CREATE TABLE migrations also moved to VARCHAR/BIGINT.
- Store::upsertStep: driver-detect via PDO::ATTR_DRIVER_NAME and emit
ON DUPLICATE KEY UPDATE for MySQL, ON CONFLICT (...) DO UPDATE for
SQLite/PostgreSQL. VALUES(col) (vs new.col aliasing) for MySQL 5.7
compatibility.
- Db.php: when DSN is mysql:, SET NAMES utf8mb4 + sql_mode strict on
every session so we get sane behaviour regardless of server defaults.
SQLite branch (PRAGMA foreign_keys/journal_mode/synchronous) unchanged.
- config.php.example: MySQL DSN is now the default + an inline SQLite
alternative block.
- DEPLOY.md: new "Database — MySQL or SQLite" section explaining when to
pick which and showing the CREATE DATABASE / CREATE USER / GRANT
statements. Install snippet split so SQLite-only steps (mkdir data,
chmod 770) are clearly optional.
Verified end-to-end on a live MySQL 8.0.34 box: POST creates session
(201), PUT step inserts (200) and updates via the upsert branch (200),
GET returns the round-tripped state, /sites lists distinct site_keys.
SQLite path still re-applies the migration idempotently locally.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>