index/src/Data/SQLite/SQLiteStatement.php

103 lines
3.5 KiB
PHP

<?php
// SQLiteStatement.php
// Created: 2021-05-02
// Updated: 2024-08-03
namespace Index\Data\SQLite;
use SQLite3Result;
use SQLite3Stmt;
use InvalidArgumentException;
use RuntimeException;
use Index\Data\{DbTools,DbType,IDbStatement,IDbResult};
use Index\IO\Stream;
/**
* Represents a prepared SQLite SQL statement.
*/
class SQLiteStatement implements IDbStatement {
private ?SQLite3Result $result = null;
private int $lastOrdinal = 1;
/**
* Creates a new SQLiteStatement instance.
*
* @param SQLiteConnection $connection A reference to the connection which creates this statement.
* @param SQLite3Stmt $statement The raw statement instance.
* @return SQLiteStatement A new statement instance.
*/
public function __construct(
private SQLiteConnection $connection,
private SQLite3Stmt $statement
) {}
public function getParameterCount(): int {
return $this->statement->paramCount();
}
private static function convertType(int $type): int {
return match($type) {
DbType::NULL => SQLITE3_NULL,
DbType::INTEGER => SQLITE3_INTEGER,
DbType::FLOAT => SQLITE3_FLOAT,
DbType::STRING => SQLITE3_TEXT,
DbType::BLOB => SQLITE3_BLOB,
default => throw new InvalidArgumentException('$type is not a supported type.'),
};
}
private function bindParameter(int $ordinal, mixed $value, int $type): void {
if($type === DbType::AUTO)
$type = DbTools::detectType($value);
if($type === DbType::NULL)
$value = null;
if(!$this->statement->bindValue($ordinal, $value, self::convertType($type)))
throw new RuntimeException((string)$this->connection->getLastErrorString(), $this->connection->getLastErrorCode());
}
public function addParameter(int $ordinal, mixed $value, int $type = DbType::AUTO): void {
if($ordinal < 1 || $ordinal > $this->getParameterCount())
throw new InvalidArgumentException('$ordinal is not a valid parameter number.');
if($ordinal > $this->lastOrdinal)
$this->lastOrdinal = $ordinal;
$this->bindParameter($ordinal, $value, $type);
}
public function nextParameter(mixed $value, int $type = DbType::AUTO): void {
if(++$this->lastOrdinal > $this->getParameterCount())
throw new RuntimeException('Attempted to specify too many parameters.');
$this->bindParameter($this->lastOrdinal, $value, $type);
}
public function getResult(): IDbResult {
if($this->result === null)
throw new RuntimeException('No result is available.');
return new SQLiteResult($this->result);
}
public function getLastInsertId(): int|string {
return $this->connection->getLastInsertId();
}
public function execute(): void {
$result = $this->statement->execute();
if($result === false)
throw new RuntimeException((string)$this->connection->getLastErrorString(), $this->connection->getLastErrorCode());
$this->result = $result;
}
public function reset(): void {
$this->result = null;
$this->lastOrdinal = 1;
if(!$this->statement->clear())
throw new RuntimeException((string)$this->connection->getLastErrorString(), $this->connection->getLastErrorCode());
if(!$this->statement->reset())
throw new RuntimeException((string)$this->connection->getLastErrorString(), $this->connection->getLastErrorCode());
}
public function close(): void {}
}