From ad91e7bae4d06502a0853d84188fbcf544668dd6 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 21 Apr 2024 03:01:19 +0200 Subject: [PATCH] added ResultDriver --- src/Database/Connection.php | 2 +- src/Database/Driver.php | 8 +-- src/Database/Drivers/PdoDriver.php | 4 +- src/Database/Drivers/PdoResultDriver.php | 72 ++++++++++++++++++++++++ src/Database/Helpers.php | 6 +- src/Database/ResultDriver.php | 42 ++++++++++++++ src/Database/ResultSet.php | 29 ++++++---- src/Database/Table/Selection.php | 4 +- 8 files changed, 141 insertions(+), 26 deletions(-) create mode 100644 src/Database/Drivers/PdoResultDriver.php create mode 100644 src/Database/ResultDriver.php diff --git a/src/Database/Connection.php b/src/Database/Connection.php index e60cf2466..071121834 100644 --- a/src/Database/Connection.php +++ b/src/Database/Connection.php @@ -205,7 +205,7 @@ public function query(#[Language('SQL')] string $sql, #[Language('GenericSQL')] [$this->sql, $params] = $this->preprocess($sql, ...$params); try { $result = new ResultSet($this, $this->sql, $params, $this->rowNormalizer); - } catch (\PDOException $e) { + } catch (DriverException $e) { Arrays::invoke($this->onQuery, $this, $e); throw $e; } diff --git a/src/Database/Driver.php b/src/Database/Driver.php index 92a9c621a..fee2eb9a0 100644 --- a/src/Database/Driver.php +++ b/src/Database/Driver.php @@ -34,7 +34,7 @@ function connect(string $dsn, ?string $user = null, ?string $password = null, ?a */ function convertException(\PDOException $e): DriverException; - function query(string $queryString, array $params); + function query(string $queryString, array $params): ResultDriver; function beginTransaction(): void; @@ -91,12 +91,6 @@ function getIndexes(string $table): array; /** @return list */ function getForeignKeys(string $table): array; - /** - * Returns associative array of detected types (IStructure::FIELD_*) in result set. - * @return array - */ - function getColumnTypes(\PDOStatement $statement): array; - /** * Cheks if driver supports specific property * @param string $item self::SUPPORT_* property diff --git a/src/Database/Drivers/PdoDriver.php b/src/Database/Drivers/PdoDriver.php index 51184528e..cae6a28b2 100644 --- a/src/Database/Drivers/PdoDriver.php +++ b/src/Database/Drivers/PdoDriver.php @@ -46,7 +46,7 @@ public function getPdo(): ?PDO } - public function query(string $queryString, array $params) + public function query(string $queryString, array $params): PdoResultDriver { try { $types = ['boolean' => PDO::PARAM_BOOL, 'integer' => PDO::PARAM_INT, 'resource' => PDO::PARAM_LOB, 'NULL' => PDO::PARAM_NULL]; @@ -59,7 +59,7 @@ public function query(string $queryString, array $params) $statement->setFetchMode(PDO::FETCH_ASSOC); @$statement->execute(); // @ PHP generates warning when ATTR_ERRMODE = ERRMODE_EXCEPTION bug #73878 - return $statement; + return new PdoResultDriver($statement, $this); } catch (PDOException $e) { $e = $this->convertException($e); diff --git a/src/Database/Drivers/PdoResultDriver.php b/src/Database/Drivers/PdoResultDriver.php new file mode 100644 index 000000000..28386a4c9 --- /dev/null +++ b/src/Database/Drivers/PdoResultDriver.php @@ -0,0 +1,72 @@ +result = $result; + $this->driver = $driver; + } + + + public function fetch(): ?array + { + $data = $this->result->fetch(); + if (!$data) { + $this->result->closeCursor(); + return null; + } + + return $data; + } + + + public function getColumnCount(): int + { + return $this->result->columnCount(); + } + + + public function getRowCount(): int + { + return $this->result->rowCount(); + } + + + public function getColumnTypes(): array + { + return $this->driver->getColumnTypes($this->result); + } + + + public function getColumnMeta(int $col): array + { + return $this->result->getColumnMeta($col); + } + + + public function getPdoStatement(): \PDOStatement + { + return $this->result; + } +} diff --git a/src/Database/Helpers.php b/src/Database/Helpers.php index 34f263f64..31340c53c 100644 --- a/src/Database/Helpers.php +++ b/src/Database/Helpers.php @@ -302,11 +302,11 @@ public static function toPairs(array $rows, string|int|null $key = null, string| /** * Finds duplicate columns in select statement */ - public static function findDuplicates(\PDOStatement $statement): string + public static function findDuplicates(ResultDriver $result): string { $cols = []; - for ($i = 0; $i < $statement->columnCount(); $i++) { - $meta = $statement->getColumnMeta($i); + for ($i = 0; $i < $result->getColumnCount(); $i++) { + $meta = $result->getColumnMeta($i); $cols[$meta['name']][] = $meta['table'] ?? ''; } diff --git a/src/Database/ResultDriver.php b/src/Database/ResultDriver.php new file mode 100644 index 000000000..dc19e8bf6 --- /dev/null +++ b/src/Database/ResultDriver.php @@ -0,0 +1,42 @@ +{substr($queryString, 2)}(); } else { - $this->pdoStatement = $driver->query($queryString, $params); + $this->result = $driver->query($queryString, $params); } $this->time = microtime(true) - $time; @@ -63,7 +62,7 @@ public function getConnection(): Connection */ public function getPdoStatement(): ?\PDOStatement { - return $this->pdoStatement; + return $this->result->getPDOStatement(); } @@ -81,19 +80,19 @@ public function getParameters(): array public function getColumnCount(): ?int { - return $this->pdoStatement ? $this->pdoStatement->columnCount() : null; + return $this->result?->getColumnCount(); } public function getRowCount(): ?int { - return $this->pdoStatement ? $this->pdoStatement->rowCount() : null; + return $this->result?->getRowCount(); } public function getColumnTypes(): array { - $this->types ??= $this->connection->getDriver()->getColumnTypes($this->pdoStatement); + $this->types ??= $this->result->getColumnTypes(); return $this->types; } @@ -169,13 +168,12 @@ public function valid(): bool */ public function fetch(): ?Row { - $data = $this->pdoStatement ? $this->pdoStatement->fetch() : null; - if (!$data) { - $this->pdoStatement->closeCursor(); + $data = $this->result?->fetch(); + if ($data === null) { return null; - } elseif ($this->lastRow === null && count($data) !== $this->pdoStatement->columnCount()) { - $duplicates = Helpers::findDuplicates($this->pdoStatement); + } elseif ($this->lastRow === null && count($data) !== $this->result->getColumnCount()) { + $duplicates = Helpers::findDuplicates($this->result); trigger_error("Found duplicate columns in database result set: $duplicates."); } @@ -191,6 +189,13 @@ public function fetch(): ?Row } + /** @internal */ + public function fetchArray(): ?array + { + return $this->result?->fetch(); + } + + /** * Fetches single field. */ diff --git a/src/Database/Table/Selection.php b/src/Database/Table/Selection.php index b773bf718..31a2a20a7 100644 --- a/src/Database/Table/Selection.php +++ b/src/Database/Table/Selection.php @@ -525,11 +525,13 @@ protected function execute(): void $this->rows = []; $usedPrimary = true; - foreach ($result->getPdoStatement() as $key => $row) { + $key = 0; + while ($row = $result->fetchArray()) { $row = $this->createRow($result->normalizeRow($row)); $primary = $row->getSignature(false); $usedPrimary = $usedPrimary && $primary !== ''; $this->rows[$usedPrimary ? $primary : $key] = $row; + $key++; } $this->data = $this->rows;