#!/usr/bin/env php MySQL database. * * Usage: * php cli/migrate_sqlite_to_mysql.php * * Requires QDB_MASTER_KEY (source SQLite) and QDB_MYSQL_* variables (target). */ require_once __DIR__ . '/../common.php'; qdb_env_override('QDB_DRIVER', 'sqlite'); require_once __DIR__ . '/../db_init.php'; if (!is_file(QDB_PATH)) { fwrite(STDERR, "SQLite database file not found at " . QDB_PATH . PHP_EOL); exit(1); } [$sqlitePdo, $tmpDb, $lockFp] = qdb_open(false); $tables = $sqlitePdo->query( "SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name" )->fetchAll(PDO::FETCH_COLUMN); $tableData = []; foreach ($tables as $table) { $tableData[$table] = $sqlitePdo->query("SELECT * FROM `{$table}`")->fetchAll(PDO::FETCH_ASSOC); } qdb_discard($tmpDb, $lockFp); qdb_reset_driver_cache(); qdb_env_override('QDB_DRIVER', 'mysql'); [$mysqlPdo] = qdb_mysql_open(); qdb_mysql_ensure_ready($mysqlPdo); qdb_set_foreign_keys($mysqlPdo, false); $mysqlPdo->beginTransaction(); try { foreach ($tableData as $table => $rows) { if (!qdb_table_exists($mysqlPdo, $table)) { throw new RuntimeException("MySQL schema is missing source table: {$table}"); } $mysqlPdo->exec("DELETE FROM `{$table}`"); if (!$rows) { echo "{$table}: 0 rows\n"; continue; } $columns = array_keys($rows[0]); $colList = implode(', ', array_map(fn($c) => "`{$c}`", $columns)); $placeholders = implode(', ', array_map(fn($c) => ':' . $c, $columns)); $insert = $mysqlPdo->prepare("INSERT INTO `{$table}` ({$colList}) VALUES ({$placeholders})"); foreach ($rows as $row) { $params = []; foreach ($columns as $column) { $params[':' . $column] = $row[$column]; } $insert->execute($params); } echo "{$table}: " . count($rows) . " rows\n"; } $mysqlPdo->commit(); } catch (Throwable $e) { if ($mysqlPdo->inTransaction()) { $mysqlPdo->rollBack(); } throw $e; } finally { qdb_set_foreign_keys($mysqlPdo, true); } qdb_set_schema_version($mysqlPdo, QDB_VERSION); echo "Migration complete. Set QDB_DRIVER=mysql in .env and restart PHP.\n";