128 lines
4.1 KiB
PHP
128 lines
4.1 KiB
PHP
<?php
|
|
|
|
class WP_SQLite_Crosscheck_DB_ extends WP_SQLite_DB {
|
|
|
|
public function __construct( string $dbname ) {
|
|
parent::__construct( $dbname );
|
|
$GLOBALS['sqlite'] = $this;
|
|
$GLOBALS['mysql'] = new wpdb(
|
|
DB_USER,
|
|
DB_PASSWORD,
|
|
DB_NAME,
|
|
DB_HOST
|
|
);
|
|
// $this->resetDatabases();
|
|
}
|
|
|
|
private function resetDatabases() {
|
|
if ( file_exists( FQDB ) ) {
|
|
unlink( FQDB );
|
|
}
|
|
$GLOBALS['mysql']->query( 'DROP DATABASE IF EXISTS ' . DB_NAME );
|
|
$GLOBALS['mysql']->query( 'CREATE DATABASE ' . DB_NAME );
|
|
$GLOBALS['mysql']->query( 'USE ' . DB_NAME );
|
|
}
|
|
|
|
public function query( $query ) {
|
|
/**
|
|
* In MySQL, AUTO_INCREMENT columns don't reuse IDs assigned in rollback transactions
|
|
* In SQLite, AUTOINCREMENT columns do reuse IDs assigned in rollback transactions
|
|
*
|
|
* Let's store the current AUTOINCREMENT value for each table, and restore it afterwards.
|
|
*/
|
|
if ( preg_match( '/^\s*rollback/i', $query ) ) {
|
|
$autoincrements = array();
|
|
$tables = $GLOBALS['@pdo']->query( "SELECT name as `table` FROM sqlite_master WHERE type='table' ORDER BY name" )->fetchAll();
|
|
foreach ( $tables as $table ) {
|
|
$table = $table['table'];
|
|
$autoincrement = $GLOBALS['@pdo']->query( "SELECT seq FROM sqlite_sequence WHERE name = '$table'" )->fetchColumn();
|
|
$autoincrements[ $table ] = $autoincrement ?: 1;
|
|
}
|
|
}
|
|
$sqlite_retval = parent::query( $query );
|
|
if ( preg_match( '/^\s*rollback/i', $query ) ) {
|
|
foreach ( $autoincrements as $table => $autoincrement ) {
|
|
$GLOBALS['@pdo']->query( "UPDATE sqlite_sequence SET seq = $autoincrement WHERE name = '$table'" );
|
|
}
|
|
}
|
|
$this->crosscheck( $query, $sqlite_retval );
|
|
return $sqlite_retval;
|
|
}
|
|
|
|
private function crosscheck( $query, $sqlite_retval ) {
|
|
// echo $query."\n\n";
|
|
// Be lenient on cross-checking some query types
|
|
if ( preg_match( '/^\s*SET storage_engine/i', $query ) ) {
|
|
return;
|
|
}
|
|
$this->show_errors = false;
|
|
$this->suppress_errors = true;
|
|
$GLOBALS['mysql']->show_errors = false;
|
|
$GLOBALS['mysql']->suppress_errors = true;
|
|
|
|
ob_start();
|
|
$mysql_retval = $GLOBALS['mysql']->query( $query );
|
|
ob_end_clean();
|
|
|
|
$tests = array(
|
|
array( 'retval', $mysql_retval, $sqlite_retval ),
|
|
array( 'num_rows', $GLOBALS['mysql']->num_rows, $GLOBALS['sqlite']->num_rows ),
|
|
array( 'insert_id', $GLOBALS['mysql']->insert_id, $GLOBALS['sqlite']->insert_id ),
|
|
array( 'rows_affected', $GLOBALS['mysql']->rows_affected, $GLOBALS['sqlite']->rows_affected ),
|
|
);
|
|
|
|
foreach ( $tests as $test ) {
|
|
list($factor, $mysql, $sqlite) = $test;
|
|
if ( $mysql !== $sqlite ) {
|
|
if ( 'insert_id' === $factor ) {
|
|
// On multi-inserts MySQL returns the first inserted ID
|
|
// while SQLite returns the last one. The cached insert_id
|
|
// value stays the same for a number of subsequent queries.
|
|
// Let's forgive this for now.
|
|
continue;
|
|
}
|
|
if ( 'rows_affected' === $factor && $mysql_retval === $mysql ) {
|
|
// SQLite doesn't provide the rowcount() functionality
|
|
continue;
|
|
}
|
|
if ( 'retval' === $factor && $GLOBALS['mysql']->rows_affected === $mysql ) {
|
|
// SQLite doesn't provide the rowcount() functionality
|
|
continue;
|
|
}
|
|
echo "======================================================\n";
|
|
echo "======== *** $factor *** differed for query ========= \n";
|
|
echo "======================================================\n";
|
|
echo "MySQL query: \n";
|
|
echo "$query\n\n";
|
|
|
|
echo "SQLite queries: \n";
|
|
foreach ( $this->dbh->last_translation->queries as $query ) {
|
|
echo $query->sql . "\n";
|
|
}
|
|
echo "\n";
|
|
|
|
$this->report_factor(
|
|
'error',
|
|
$GLOBALS['mysql']->last_error,
|
|
$GLOBALS['sqlite']->last_error
|
|
);
|
|
foreach ( $tests as $test ) {
|
|
$this->report_factor(
|
|
$test[0],
|
|
$test[1],
|
|
$test[2]
|
|
);
|
|
}
|
|
// throw new Exception();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function report_factor( $factor, $mysql, $sqlite ) {
|
|
echo "$factor: \n";
|
|
echo ' MySQL: ' . var_export( $mysql, true ) . "\n";
|
|
echo ' SQLite: ' . var_export( $sqlite, true ) . "\n\n";
|
|
}
|
|
}
|