1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 21:22:40 +00:00
Arsse/lib/Db/AbstractDriver.php

133 lines
5.4 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
2017-03-28 04:12:12 +00:00
namespace JKingWeb\Arsse\Db;
abstract class AbstractDriver implements Driver {
protected $locked = false;
2017-02-16 20:29:42 +00:00
protected $transDepth = 0;
protected $transStatus = [];
2017-08-29 14:50:31 +00:00
abstract public function prepareArray(string $query, array $paramTypes): Statement;
abstract protected function lock(): bool;
abstract protected function unlock(bool $rollback = false) : bool;
2017-07-21 15:13:04 +00:00
/** @codeCoverageIgnore */
2017-02-16 20:29:42 +00:00
public function schemaVersion(): int {
2017-07-21 15:13:04 +00:00
// FIXME: generic schemaVersion() will need to be covered for database engines other than SQLite
2017-02-16 20:29:42 +00:00
try {
return (int) $this->query("SELECT value from arsse_meta where key is schema_version")->getValue();
2017-08-29 14:50:31 +00:00
} catch (Exception $e) {
2017-02-16 20:29:42 +00:00
return 0;
}
}
public function begin(bool $lock = false): Transaction {
return new Transaction($this, $lock);
}
public function savepointCreate(bool $lock = false): int {
2017-08-29 14:50:31 +00:00
if ($lock && !$this->transDepth) {
$this->lock();
$this->locked = true;
}
2017-03-28 04:12:12 +00:00
$this->exec("SAVEPOINT arsse_".(++$this->transDepth));
$this->transStatus[$this->transDepth] = self::TR_PEND;
return $this->transDepth;
2017-02-16 20:29:42 +00:00
}
public function savepointRelease(int $index = null): bool {
$index = $index ?? $this->transDepth;
2017-08-29 14:50:31 +00:00
if (array_key_exists($index, $this->transStatus)) {
switch ($this->transStatus[$index]) {
case self::TR_PEND:
$this->exec("RELEASE SAVEPOINT arsse_".$index);
$this->transStatus[$index] = self::TR_COMMIT;
$a = $index;
2017-08-29 14:50:31 +00:00
while (++$a && $a <= $this->transDepth) {
if ($this->transStatus[$a] <= self::TR_PEND) {
2017-07-21 02:40:09 +00:00
$this->transStatus[$a] = self::TR_PEND_COMMIT;
}
}
$out = true;
break;
case self::TR_PEND_COMMIT:
$this->transStatus[$index] = self::TR_COMMIT;
$out = true;
break;
case self::TR_PEND_ROLLBACK:
$this->transStatus[$index] = self::TR_COMMIT;
$out = false;
break;
case self::TR_COMMIT:
case self::TR_ROLLBACK: //@codeCoverageIgnore
throw new Exception("savepointStale", ['action' => "commit", 'index' => $index]);
default:
throw new Exception("savepointStatusUnknown", $this->transStatus[$index]); // @codeCoverageIgnore
}
2017-08-29 14:50:31 +00:00
if ($index==$this->transDepth) {
while ($this->transDepth > 0 && $this->transStatus[$this->transDepth] > self::TR_PEND) {
array_pop($this->transStatus);
$this->transDepth--;
}
}
2017-08-29 14:50:31 +00:00
if (!$this->transDepth && $this->locked) {
$this->unlock();
$this->locked = false;
}
return $out;
2017-02-16 20:29:42 +00:00
} else {
throw new Exception("savepointInvalid", ['action' => "commit", 'index' => $index]);
2017-02-16 20:29:42 +00:00
}
}
public function savepointUndo(int $index = null): bool {
$index = $index ?? $this->transDepth;
2017-08-29 14:50:31 +00:00
if (array_key_exists($index, $this->transStatus)) {
switch ($this->transStatus[$index]) {
case self::TR_PEND:
$this->exec("ROLLBACK TRANSACTION TO SAVEPOINT arsse_".$index);
$this->exec("RELEASE SAVEPOINT arsse_".$index);
$this->transStatus[$index] = self::TR_ROLLBACK;
$a = $index;
2017-08-29 14:50:31 +00:00
while (++$a && $a <= $this->transDepth) {
if ($this->transStatus[$a] <= self::TR_PEND) {
2017-07-21 02:40:09 +00:00
$this->transStatus[$a] = self::TR_PEND_ROLLBACK;
}
}
$out = true;
break;
case self::TR_PEND_COMMIT:
$this->transStatus[$index] = self::TR_ROLLBACK;
$out = false;
break;
case self::TR_PEND_ROLLBACK:
$this->transStatus[$index] = self::TR_ROLLBACK;
$out = true;
break;
case self::TR_COMMIT:
case self::TR_ROLLBACK: //@codeCoverageIgnore
throw new Exception("savepointStale", ['action' => "rollback", 'index' => $index]);
default:
throw new Exception("savepointStatusUnknown", $this->transStatus[$index]); // @codeCoverageIgnore
}
2017-08-29 14:50:31 +00:00
if ($index==$this->transDepth) {
while ($this->transDepth > 0 && $this->transStatus[$this->transDepth] > self::TR_PEND) {
array_pop($this->transStatus);
$this->transDepth--;
}
}
2017-08-29 14:50:31 +00:00
if (!$this->transDepth && $this->locked) {
$this->unlock(true);
$this->locked = false;
}
return $out;
2017-02-16 20:29:42 +00:00
} else {
throw new Exception("savepointInvalid", ['action' => "rollback", 'index' => $index]);
2017-02-16 20:29:42 +00:00
}
}
public function prepare(string $query, ...$paramType): Statement {
2017-02-16 20:29:42 +00:00
return $this->prepareArray($query, $paramType);
}
2017-08-29 14:50:31 +00:00
}