Skip to content

Commit

Permalink
added ResultDriver
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed May 7, 2024
1 parent f95ebe5 commit ad91e7b
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/Database/Connection.php
Expand Up @@ -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;
}
Expand Down
8 changes: 1 addition & 7 deletions src/Database/Driver.php
Expand Up @@ -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;

Expand Down Expand Up @@ -91,12 +91,6 @@ function getIndexes(string $table): array;
/** @return list<array{name: string, local: string, table: string, foreign: string}> */
function getForeignKeys(string $table): array;

/**
* Returns associative array of detected types (IStructure::FIELD_*) in result set.
* @return array<string, string>
*/
function getColumnTypes(\PDOStatement $statement): array;

/**
* Cheks if driver supports specific property
* @param string $item self::SUPPORT_* property
Expand Down
4 changes: 2 additions & 2 deletions src/Database/Drivers/PdoDriver.php
Expand Up @@ -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];
Expand All @@ -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);
Expand Down
72 changes: 72 additions & 0 deletions src/Database/Drivers/PdoResultDriver.php
@@ -0,0 +1,72 @@
<?php

/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/

declare(strict_types=1);

namespace Nette\Database\Drivers;

use Nette;


/**
* PDO-based result-set driver.
*/
class PdoResultDriver implements Nette\Database\ResultDriver
{
private \PDOStatement $result;

private PdoDriver $driver;


public function __construct(\PDOStatement $result, PdoDriver $driver)
{
$this->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;
}
}
6 changes: 3 additions & 3 deletions src/Database/Helpers.php
Expand Up @@ -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'] ?? '';
}

Expand Down
42 changes: 42 additions & 0 deletions src/Database/ResultDriver.php
@@ -0,0 +1,42 @@
<?php

/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/

declare(strict_types=1);

namespace Nette\Database;


/**
* Supplemental database driver for result-set.
*/
interface ResultDriver
{
/**
* Fetches the row at current position and moves the internal cursor to the next position.
*/
function fetch(): ?array;

/**
* Returns the number of columns in a result set.
*/
function getColumnCount(): int;

/**
* Returns the number of rows in a result set.
*/
function getRowCount(): int;

/**
* Returns associative array of detected types (IStructure::FIELD_*) in result set.
*/
function getColumnTypes(): array;

/**
* Returns associative array of original table names.
*/
function getColumnMeta(int $col): array;
}
29 changes: 17 additions & 12 deletions src/Database/ResultSet.php
Expand Up @@ -10,15 +10,14 @@
namespace Nette\Database;

use Nette;
use PDO;


/**
* Represents a result set.
*/
class ResultSet implements \Iterator, IRowContainer
{
private ?\PDOStatement $pdoStatement = null;
private ?ResultDriver $result = null;

/** @var callable(array, ResultSet): array */
private $normalizer;
Expand All @@ -44,7 +43,7 @@ public function __construct(
if (str_starts_with($queryString, '::')) {
$driver->{substr($queryString, 2)}();
} else {
$this->pdoStatement = $driver->query($queryString, $params);
$this->result = $driver->query($queryString, $params);
}

$this->time = microtime(true) - $time;
Expand All @@ -63,7 +62,7 @@ public function getConnection(): Connection
*/
public function getPdoStatement(): ?\PDOStatement
{
return $this->pdoStatement;
return $this->result->getPDOStatement();
}


Expand All @@ -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;
}

Expand Down Expand Up @@ -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.");
}

Expand All @@ -191,6 +189,13 @@ public function fetch(): ?Row
}


/** @internal */
public function fetchArray(): ?array
{
return $this->result?->fetch();
}


/**
* Fetches single field.
*/
Expand Down
4 changes: 3 additions & 1 deletion src/Database/Table/Selection.php
Expand Up @@ -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;
Expand Down

0 comments on commit ad91e7b

Please sign in to comment.