2021-12-14 18:32:47 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
2019-09-29 13:30:55 +00:00
|
|
|
abstract class SCORE
|
|
|
|
{
|
2021-12-14 18:32:47 +00:00
|
|
|
public const AIPK = "SCORE_AIPK";
|
|
|
|
public const INET = "SCORE_INET";
|
2019-06-27 03:29:52 +00:00
|
|
|
}
|
|
|
|
|
2019-10-14 18:31:12 +00:00
|
|
|
abstract class DBEngine
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2021-03-14 23:43:50 +00:00
|
|
|
public ?string $name = null;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function init(PDO $db)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-14 23:43:50 +00:00
|
|
|
public function scoreql_to_sql(string $data): string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2021-03-14 23:43:50 +00:00
|
|
|
return $data;
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function create_table_sql(string $name, string $data): string
|
|
|
|
{
|
|
|
|
return 'CREATE TABLE '.$name.' ('.$data.')';
|
|
|
|
}
|
2019-10-14 18:31:12 +00:00
|
|
|
|
2021-09-22 14:42:41 +00:00
|
|
|
abstract public function set_timeout(PDO $db, ?int $time);
|
2020-03-26 16:57:08 +00:00
|
|
|
|
|
|
|
abstract public function get_version(PDO $db): string;
|
2020-10-03 12:50:37 +00:00
|
|
|
|
|
|
|
abstract public function notify(PDO $db, string $channel, ?string $data=null): void;
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class MySQL extends DBEngine
|
|
|
|
{
|
2021-03-14 23:43:50 +00:00
|
|
|
public ?string $name = DatabaseDriver::MYSQL;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function init(PDO $db)
|
|
|
|
{
|
|
|
|
$db->exec("SET NAMES utf8;");
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scoreql_to_sql(string $data): string
|
|
|
|
{
|
2019-06-27 03:29:52 +00:00
|
|
|
$data = str_replace(SCORE::AIPK, "INTEGER PRIMARY KEY auto_increment", $data);
|
|
|
|
$data = str_replace(SCORE::INET, "VARCHAR(45)", $data);
|
2019-05-28 16:59:38 +00:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function create_table_sql(string $name, string $data): string
|
|
|
|
{
|
|
|
|
$data = $this->scoreql_to_sql($data);
|
|
|
|
$ctes = "ENGINE=InnoDB DEFAULT CHARSET='utf8'";
|
|
|
|
return 'CREATE TABLE '.$name.' ('.$data.') '.$ctes;
|
|
|
|
}
|
2019-10-14 18:31:12 +00:00
|
|
|
|
2021-09-22 14:42:41 +00:00
|
|
|
public function set_timeout(PDO $db, ?int $time): void
|
2019-10-14 18:31:12 +00:00
|
|
|
{
|
|
|
|
// These only apply to read-only queries, which appears to be the best we can to mysql-wise
|
2020-01-30 09:01:19 +00:00
|
|
|
// $db->exec("SET SESSION MAX_EXECUTION_TIME=".$time.";");
|
2019-10-14 18:31:12 +00:00
|
|
|
}
|
2020-03-26 16:57:08 +00:00
|
|
|
|
2020-10-03 12:50:37 +00:00
|
|
|
public function notify(PDO $db, string $channel, ?string $data=null): void
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-26 16:57:08 +00:00
|
|
|
public function get_version(PDO $db): string
|
|
|
|
{
|
|
|
|
return $db->query('select version()')->fetch()[0];
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 16:59:38 +00:00
|
|
|
class PostgreSQL extends DBEngine
|
|
|
|
{
|
2021-03-14 23:43:50 +00:00
|
|
|
public ?string $name = DatabaseDriver::PGSQL;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function init(PDO $db)
|
|
|
|
{
|
|
|
|
if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
|
|
|
|
$db->exec("SET application_name TO 'shimmie [{$_SERVER['REMOTE_ADDR']}]';");
|
|
|
|
} else {
|
|
|
|
$db->exec("SET application_name TO 'shimmie [local]';");
|
|
|
|
}
|
2020-06-22 15:08:04 +00:00
|
|
|
if (defined("DATABASE_TIMEOUT")) {
|
|
|
|
$this->set_timeout($db, DATABASE_TIMEOUT);
|
|
|
|
}
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function scoreql_to_sql(string $data): string
|
|
|
|
{
|
2019-11-25 00:24:45 +00:00
|
|
|
$data = str_replace(SCORE::AIPK, "INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY", $data);
|
2019-06-27 03:29:52 +00:00
|
|
|
$data = str_replace(SCORE::INET, "INET", $data);
|
2019-05-28 16:59:38 +00:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function create_table_sql(string $name, string $data): string
|
|
|
|
{
|
|
|
|
$data = $this->scoreql_to_sql($data);
|
|
|
|
return "CREATE TABLE $name ($data)";
|
|
|
|
}
|
2019-10-14 18:31:12 +00:00
|
|
|
|
2021-09-22 14:42:41 +00:00
|
|
|
public function set_timeout(PDO $db, ?int $time): void
|
2019-10-14 18:31:12 +00:00
|
|
|
{
|
2021-09-22 15:02:33 +00:00
|
|
|
if (is_null($time)) {
|
|
|
|
$time = 0;
|
|
|
|
}
|
2019-10-14 18:31:12 +00:00
|
|
|
$db->exec("SET statement_timeout TO ".$time.";");
|
|
|
|
}
|
2020-03-26 16:57:08 +00:00
|
|
|
|
2020-10-03 12:50:37 +00:00
|
|
|
public function notify(PDO $db, string $channel, ?string $data=null): void
|
|
|
|
{
|
|
|
|
if ($data) {
|
|
|
|
$db->exec("NOTIFY $channel, '$data';");
|
|
|
|
} else {
|
|
|
|
$db->exec("NOTIFY $channel;");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-26 16:57:08 +00:00
|
|
|
public function get_version(PDO $db): string
|
|
|
|
{
|
|
|
|
return $db->query('select version()')->fetch()[0];
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// shimmie functions for export to sqlite
|
2021-03-14 23:43:50 +00:00
|
|
|
function _unix_timestamp($date): int
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return strtotime($date);
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _now(): string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
2019-12-10 03:50:47 +00:00
|
|
|
return date("Y-m-d H:i:s");
|
2019-05-28 16:59:38 +00:00
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _floor($a): float
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return floor($a);
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _log($a, $b=null): float
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
if (is_null($b)) {
|
|
|
|
return log($a);
|
|
|
|
} else {
|
|
|
|
return log($a, $b);
|
|
|
|
}
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _isnull($a): bool
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return is_null($a);
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _md5($a): string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return md5($a);
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _concat($a, $b): string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return $a . $b;
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _lower($a): string
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return strtolower($a);
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _rand(): int
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return rand();
|
|
|
|
}
|
2021-03-14 23:43:50 +00:00
|
|
|
function _ln($n): float
|
2019-05-28 16:59:38 +00:00
|
|
|
{
|
|
|
|
return log($n);
|
|
|
|
}
|
|
|
|
|
|
|
|
class SQLite extends DBEngine
|
|
|
|
{
|
2021-03-14 23:43:50 +00:00
|
|
|
public ?string $name = DatabaseDriver::SQLITE;
|
2019-05-28 16:59:38 +00:00
|
|
|
|
|
|
|
public function init(PDO $db)
|
|
|
|
{
|
2020-01-26 13:19:35 +00:00
|
|
|
ini_set('sqlite.assoc_case', '0');
|
2019-05-28 16:59:38 +00:00
|
|
|
$db->exec("PRAGMA foreign_keys = ON;");
|
|
|
|
$db->sqliteCreateFunction('UNIX_TIMESTAMP', '_unix_timestamp', 1);
|
|
|
|
$db->sqliteCreateFunction('now', '_now', 0);
|
|
|
|
$db->sqliteCreateFunction('floor', '_floor', 1);
|
|
|
|
$db->sqliteCreateFunction('log', '_log');
|
|
|
|
$db->sqliteCreateFunction('isnull', '_isnull', 1);
|
|
|
|
$db->sqliteCreateFunction('md5', '_md5', 1);
|
|
|
|
$db->sqliteCreateFunction('concat', '_concat', 2);
|
|
|
|
$db->sqliteCreateFunction('lower', '_lower', 1);
|
|
|
|
$db->sqliteCreateFunction('rand', '_rand', 0);
|
|
|
|
$db->sqliteCreateFunction('ln', '_ln', 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function scoreql_to_sql(string $data): string
|
|
|
|
{
|
2019-06-27 03:29:52 +00:00
|
|
|
$data = str_replace(SCORE::AIPK, "INTEGER PRIMARY KEY", $data);
|
|
|
|
$data = str_replace(SCORE::INET, "VARCHAR(45)", $data);
|
2019-05-28 16:59:38 +00:00
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function create_table_sql(string $name, string $data): string
|
|
|
|
{
|
|
|
|
$data = $this->scoreql_to_sql($data);
|
|
|
|
$cols = [];
|
|
|
|
$extras = "";
|
|
|
|
foreach (explode(",", $data) as $bit) {
|
|
|
|
$matches = [];
|
|
|
|
if (preg_match("/(UNIQUE)? ?INDEX\s*\((.*)\)/", $bit, $matches)) {
|
|
|
|
$uni = $matches[1];
|
|
|
|
$col = $matches[2];
|
|
|
|
$extras .= "CREATE $uni INDEX {$name}_{$col} ON {$name}({$col});";
|
|
|
|
} else {
|
|
|
|
$cols[] = $bit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$cols_redone = implode(", ", $cols);
|
|
|
|
return "CREATE TABLE $name ($cols_redone); $extras";
|
|
|
|
}
|
2019-10-14 18:31:12 +00:00
|
|
|
|
2021-09-22 14:42:41 +00:00
|
|
|
public function set_timeout(PDO $db, ?int $time): void
|
2019-10-14 18:31:12 +00:00
|
|
|
{
|
|
|
|
// There doesn't seem to be such a thing for SQLite, so it does nothing
|
|
|
|
}
|
2020-03-26 16:57:08 +00:00
|
|
|
|
2020-10-03 12:50:37 +00:00
|
|
|
public function notify(PDO $db, string $channel, ?string $data=null): void
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-26 16:57:08 +00:00
|
|
|
public function get_version(PDO $db): string
|
|
|
|
{
|
|
|
|
return $db->query('select sqlite_version()')->fetch()[0];
|
|
|
|
}
|
2018-11-05 22:30:18 +00:00
|
|
|
}
|