dbPostgreSQLUser; $pass = $pass ?? Arsse::$conf->dbPostgreSQLPass; $db = $db ?? Arsse::$conf->dbPostgreSQLDb; $host = $host ?? Arsse::$conf->dbPostgreSQLHost; $port = $port ?? Arsse::$conf->dbPostgreSQLPort; $schema = $schema ?? Arsse::$conf->dbPostgreSQLSchema; $service = $service ?? Arsse::$conf->dbPostgreSQLService; $this->makeConnection($user, $pass, $db, $host, $port, $service); foreach (static::makeSetupQueries($schema) as $q) { $this->exec($q); } } public static function makeConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service): string { $base = [ 'client_encoding' => "UTF8", 'application_name' => "arsse", 'connect_timeout' => (string) ceil(Arsse::$conf->dbTimeoutConnect ?? 0), ]; $out = []; if ($service != "") { $out['service'] = $service; } else { if ($host != "") { $out['host'] = $host; } if ($port != 5432 && !($host != "" && $host[0] == "/")) { $out['port'] = (string) $port; } if ($db != "") { $out['dbname'] = $db; } if (!$pdo) { $out['user'] = $user; if ($pass != "") { $out['password'] = $pass; } } } ksort($out); ksort($base); $out = array_merge($out, $base); $out = array_map(function($v, $k) { return "$k='".str_replace("'", "\\'", str_replace("\\", "\\\\", $v))."'"; }, $out, array_keys($out)); return implode(" ", $out); } public static function makeSetupQueries(string $schema = ""): array { $timeout = ceil(Arsse::$conf->dbTimeoutExec * 1000); $out = [ "SET TIME ZONE UTC", "SET DateStyle = 'ISO, MDY'", "SET statement_timeout = '$timeout'", ]; if (strlen($schema) > 0) { $out[] = 'SET search_path = \'"'.str_replace('"', '""', $schema).'", "$user", public\''; } return $out; } /** @codeCoverageIgnore */ public static function create(): \JKingWeb\Arsse\Db\Driver { if (self::requirementsMet()) { return new self; } elseif (PDODriver::requirementsMet()) { return new PDODriver; } else { throw new Exception("extMissing", self::driverName()); } } public static function driverName(): string { return Arsse::$lang->msg("Driver.Db.PostgreSQL.Name"); } public static function schemaID(): string { return "PostgreSQL"; } public function charsetAcceptable(): bool { return $this->query("SELECT pg_encoding_to_char(encoding) from pg_database where datname = current_database()")->getValue() == "UTF8"; } public function savepointCreate(bool $lock = false): int { if (!$this->transDepth) { $this->exec("BEGIN TRANSACTION"); } return parent::savepointCreate($lock); } public function savepointRelease(int $index = null): bool { $out = parent::savepointUndo($index); if ($out && !$this->transDepth) { $this->exec("COMMIT TRANSACTION"); } return $out; } public function savepointUndo(int $index = null): bool { $out = parent::savepointUndo($index); if ($out && !$this->transDepth) { $this->exec("ROLLBACK TRANSACTION"); } return $out; } protected function lock(): bool { if ($this->schemaVersion()) { $this->exec("LOCK TABLE arsse_meta IN EXCLUSIVE MODE NOWAIT"); } return true; } protected function unlock(bool $rollback = false): bool { $this->exec((!$rollback) ? "COMMIT" : "ROLLBACK"); return true; } public function __destruct() { } public static function requirementsMet(): bool { // stub: native interface is not yet supported return false; } protected function makeConnection(string $user, string $pass, string $db, string $host, int $port, string $service) { // stub: native interface is not yet supported throw new \Exception; } /** @codeCoverageIgnore */ protected function getError(): string { // stub: native interface is not yet supported return ""; } /** @codeCoverageIgnore */ public function exec(string $query): bool { // stub: native interface is not yet supported return true; } /** @codeCoverageIgnore */ public function query(string $query): \JKingWeb\Arsse\Db\Result { // stub: native interface is not yet supported return new ResultEmpty; } /** @codeCoverageIgnore */ public function prepareArray(string $query, array $paramTypes): \JKingWeb\Arsse\Db\Statement { // stub: native interface is not yet supported return new Statement($this->db, $s, $paramTypes); } }