2018-11-23 00:55:54 +00:00
< ? php
/** @ license MIT
* Copyright 2017 J . King , Dustin Wilson et al .
* See LICENSE and AUTHORS files for details */
declare ( strict_types = 1 );
namespace JKingWeb\Arsse\Test ;
use JKingWeb\Arsse\Arsse ;
2018-11-25 04:18:17 +00:00
use JKingWeb\Arsse\Db\Driver ;
2018-11-23 00:55:54 +00:00
class DatabaseInformation {
public $name ;
public $backend ;
public $pdo ;
public $resultClass ;
public $statementClass ;
public $driverClass ;
public $stringOutput ;
public $interfaceConstructor ;
2018-11-25 04:18:17 +00:00
public $truncateFunction ;
public $razeFunction ;
2018-11-23 00:55:54 +00:00
protected static $data ;
public function __construct ( string $name ) {
if ( ! isset ( self :: $data )) {
self :: $data = self :: getData ();
}
if ( ! isset ( self :: $data [ $name ])) {
throw new \Exception ( " Invalid database driver name " );
}
$this -> name = $name ;
foreach ( self :: $data [ $name ] as $key => $value ) {
$this -> $key = $value ;
}
}
public static function list () : array {
if ( ! isset ( self :: $data )) {
self :: $data = self :: getData ();
}
return array_keys ( self :: $data );
}
public static function listPDO () : array {
if ( ! isset ( self :: $data )) {
self :: $data = self :: getData ();
}
return array_values ( array_filter ( array_keys ( self :: $data ), function ( $k ) {
return self :: $data [ $k ][ 'pdo' ];
}));
}
protected static function getData () {
2018-11-25 04:18:17 +00:00
$sqlite3TableList = function ( $db ) : array {
$listTables = " SELECT name from sqlite_master where type = 'table' and name like 'arsse_%' " ;
if ( $db instanceof Driver ) {
$tables = $db -> query ( $listTables ) -> getAll ();
$tables = sizeof ( $tables ) ? array_column ( $tables , " name " ) : [];
} elseif ( $db instanceof \PDO ) {
2018-11-27 19:26:33 +00:00
retry :
try {
$tables = $db -> query ( $listTables ) -> fetchAll ( \PDO :: FETCH_ASSOC );
} catch ( \PDOException $e ) {
goto retry ;
}
2018-11-25 04:18:17 +00:00
$tables = sizeof ( $tables ) ? array_column ( $tables , " name " ) : [];
} else {
$tables = [];
$result = $db -> query ( $listTables );
while ( $r = $result -> fetchArray ( \SQLITE3_ASSOC )) {
$tables [] = $r [ 'name' ];
}
$result -> finalize ();
}
return $tables ;
};
$sqlite3TruncateFunction = function ( $db , array $afterStatements = []) use ( $sqlite3TableList ) {
2018-11-27 19:26:33 +00:00
// rollback any pending transaction
try {
$db -> exec ( " ROLLBACK " );
2018-12-05 22:28:11 +00:00
} catch ( \Throwable $e ) {
2018-11-27 19:26:33 +00:00
}
2018-11-25 04:18:17 +00:00
foreach ( $sqlite3TableList ( $db ) as $table ) {
if ( $table == " arsse_meta " ) {
$db -> exec ( " DELETE FROM $table where key <> 'schema_version' " );
} else {
$db -> exec ( " DELETE FROM $table " );
}
}
foreach ( $afterStatements as $st ) {
$db -> exec ( $st );
}
};
$sqlite3RazeFunction = function ( $db , array $afterStatements = []) use ( $sqlite3TableList ) {
2018-11-27 19:26:33 +00:00
// rollback any pending transaction
try {
$db -> exec ( " ROLLBACK " );
2018-12-05 22:28:11 +00:00
} catch ( \Throwable $e ) {
2018-11-27 19:26:33 +00:00
}
2018-11-25 04:18:17 +00:00
$db -> exec ( " PRAGMA foreign_keys=0 " );
foreach ( $sqlite3TableList ( $db ) as $table ) {
$db -> exec ( " DROP TABLE IF EXISTS $table " );
}
$db -> exec ( " PRAGMA user_version=0 " );
$db -> exec ( " PRAGMA foreign_keys=1 " );
foreach ( $afterStatements as $st ) {
$db -> exec ( $st );
}
};
$pgObjectList = function ( $db ) : array {
$listObjects = " SELECT table_name as name, 'TABLE' as type from information_schema.tables where table_schema = current_schema() and table_name like 'arsse_%' union SELECT collation_name as name, 'COLLATION' as type from information_schema.collations where collation_schema = current_schema() " ;
if ( $db instanceof Driver ) {
return $db -> query ( $listObjects ) -> getAll ();
} elseif ( $db instanceof \PDO ) {
return $db -> query ( $listObjects ) -> fetchAll ( \PDO :: FETCH_ASSOC );
} else {
throw \Exception ( " Native PostgreSQL interface not implemented " );
}
};
2018-11-23 00:55:54 +00:00
return [
'SQLite 3' => [
'pdo' => false ,
'backend' => " SQLite 3 " ,
'statementClass' => \JKingWeb\Arsse\Db\SQLite3\Statement :: class ,
'resultClass' => \JKingWeb\Arsse\Db\SQLite3\Result :: class ,
'driverClass' => \JKingWeb\Arsse\Db\SQLite3\Driver :: class ,
'stringOutput' => false ,
'interfaceConstructor' => function () {
try {
$d = new \SQLite3 ( Arsse :: $conf -> dbSQLite3File );
} catch ( \Throwable $e ) {
return ;
}
$d -> enableExceptions ( true );
return $d ;
},
2018-11-25 04:18:17 +00:00
'truncateFunction' => $sqlite3TruncateFunction ,
'razeFunction' => $sqlite3RazeFunction ,
2018-11-23 00:55:54 +00:00
],
'PDO SQLite 3' => [
'pdo' => true ,
'backend' => " SQLite 3 " ,
'statementClass' => \JKingWeb\Arsse\Db\PDOStatement :: class ,
'resultClass' => \JKingWeb\Arsse\Db\PDOResult :: class ,
'driverClass' => \JKingWeb\Arsse\Db\SQLite3\PDODriver :: class ,
'stringOutput' => true ,
'interfaceConstructor' => function () {
try {
$d = new \PDO ( " sqlite: " . Arsse :: $conf -> dbSQLite3File , " " , " " , [ \PDO :: ATTR_ERRMODE => \PDO :: ERRMODE_EXCEPTION ]);
$d -> exec ( " PRAGMA busy_timeout=0 " );
return $d ;
} catch ( \Throwable $e ) {
return ;
}
},
2018-11-25 04:18:17 +00:00
'truncateFunction' => $sqlite3TruncateFunction ,
'razeFunction' => $sqlite3RazeFunction ,
2018-11-23 00:55:54 +00:00
],
'PDO PostgreSQL' => [
'pdo' => true ,
'backend' => " PostgreSQL " ,
2018-11-29 18:45:37 +00:00
'statementClass' => \JKingWeb\Arsse\Db\PostgreSQL\PDOStatement :: class ,
2018-11-23 00:55:54 +00:00
'resultClass' => \JKingWeb\Arsse\Db\PDOResult :: class ,
'driverClass' => \JKingWeb\Arsse\Db\PostgreSQL\PDODriver :: class ,
2018-11-29 18:45:37 +00:00
'stringOutput' => false ,
2018-11-23 00:55:54 +00:00
'interfaceConstructor' => function () {
$connString = \JKingWeb\Arsse\Db\PostgreSQL\Driver :: makeConnectionString ( true , Arsse :: $conf -> dbPostgreSQLUser , Arsse :: $conf -> dbPostgreSQLPass , Arsse :: $conf -> dbPostgreSQLDb , Arsse :: $conf -> dbPostgreSQLHost , Arsse :: $conf -> dbPostgreSQLPort , " " );
try {
$d = new \PDO ( " pgsql: " . $connString , Arsse :: $conf -> dbPostgreSQLUser , Arsse :: $conf -> dbPostgreSQLPass , [ \PDO :: ATTR_ERRMODE => \PDO :: ERRMODE_EXCEPTION ]);
} catch ( \Throwable $e ) {
return ;
}
foreach ( \JKingWeb\Arsse\Db\PostgreSQL\PDODriver :: makeSetupQueries ( Arsse :: $conf -> dbPostgreSQLSchema ) as $q ) {
$d -> exec ( $q );
}
return $d ;
},
2018-11-25 04:18:17 +00:00
'truncateFunction' => function ( $db , array $afterStatements = []) use ( $pgObjectList ) {
2018-11-27 19:26:33 +00:00
// rollback any pending transaction
try {
$db -> exec ( " ROLLBACK " );
2018-12-05 22:28:11 +00:00
} catch ( \Throwable $e ) {
2018-11-27 19:26:33 +00:00
}
foreach ( $pgObjectList ( $db ) as $obj ) {
2018-11-25 04:18:17 +00:00
if ( $obj [ 'type' ] != " TABLE " ) {
continue ;
} elseif ( $obj [ 'name' ] == " arsse_meta " ) {
$db -> exec ( " DELETE FROM { $obj [ 'name' ] } where key <> 'schema_version' " );
} else {
$db -> exec ( " TRUNCATE TABLE { $obj [ 'name' ] } restart identity cascade " );
}
}
foreach ( $afterStatements as $st ) {
$db -> exec ( $st );
}
},
'razeFunction' => function ( $db , array $afterStatements = []) use ( $pgObjectList ) {
2018-11-27 22:16:00 +00:00
// rollback any pending transaction
try {
$db -> exec ( " ROLLBACK " );
2018-12-05 22:28:11 +00:00
} catch ( \Throwable $e ) {
2018-11-27 22:16:00 +00:00
}
2018-11-27 19:26:33 +00:00
foreach ( $pgObjectList ( $db ) as $obj ) {
$db -> exec ( " DROP { $obj [ 'type' ] } IF EXISTS { $obj [ 'name' ] } cascade " );
2018-11-25 04:18:17 +00:00
}
foreach ( $afterStatements as $st ) {
$db -> exec ( $st );
}
},
2018-11-23 00:55:54 +00:00
],
];
}
}