Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the Result::getColumnName method #6428

Merged
merged 1 commit into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ awareness about deprecated code.
* Upgrade to MariaDB 10.5 or later.
* Upgrade to MySQL 8.0 or later.

## Add `Result::getColumnName()`

Driver and middleware results need to implement a new method `getColumnName()` that gives access to the
column name. Not doing so is deprecated.

# Upgrade to 4.0

## BC BREAK: removed `AbstractMySQLPlatform` methods.
Expand Down
3 changes: 3 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ parameters:
message: '#^Parameter \#2 \$callback of function array_reduce expects callable\(\(callable&TIn\)\|Closure\(mixed \$value\)\: mixed\|null, callable\(T\)\: T\)\: \(\(callable&TIn\)\|Closure\(mixed \$value\)\: mixed\|null\), Closure\(callable\|null, callable\)\: \(callable\(T\)\: T\) given\.$#'
path: src/Portability/Converter.php

# Type check for legacy implementations of the Result interface
# TODO: remove in 5.0.0
- '~^Call to function method_exists\(\) with Doctrine\\DBAL\\Driver\\Result and ''getColumnName'' will always evaluate to true\.$~'
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
Expand Down
2 changes: 2 additions & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@
</TypeDoesNotContainNull>
<TypeDoesNotContainType>
<errorLevel type="suppress">
<!-- See https://github.com/vimeo/psalm/issues/11008 -->
<file name="src/Driver/SQLite3/Result.php"/>
<!-- Ignore isset() checks in destructors. -->
<file name="src/Driver/PgSQL/Connection.php"/>
<file name="src/Driver/PgSQL/Statement.php"/>
Expand Down
11 changes: 11 additions & 0 deletions src/Cache/ArrayResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result;
use Doctrine\DBAL\Exception\InvalidColumnIndex;

use function array_keys;
use function array_values;
use function count;
use function reset;
Expand Down Expand Up @@ -84,6 +86,15 @@
return $this->columnCount;
}

public function getColumnName(int $index): string
{
if ($this->data === [] || $index > count($this->data[0])) {
throw InvalidColumnIndex::new($index);

Check warning on line 92 in src/Cache/ArrayResult.php

View check run for this annotation

Codecov / codecov/patch

src/Cache/ArrayResult.php#L92

Added line #L92 was not covered by tests
}

return array_keys($this->data[0])[$index];
}

public function free(): void
{
$this->data = [];
Expand Down
12 changes: 12 additions & 0 deletions src/Driver/IBMDB2/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\IBMDB2\Exception\StatementError;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;

use function db2_fetch_array;
use function db2_fetch_assoc;
Expand Down Expand Up @@ -99,6 +100,17 @@
return 0;
}

public function getColumnName(int $index): string

Check warning on line 103 in src/Driver/IBMDB2/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/IBMDB2/Result.php#L103

Added line #L103 was not covered by tests
{
$name = db2_field_name($this->statement, $index);

Check warning on line 105 in src/Driver/IBMDB2/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/IBMDB2/Result.php#L105

Added line #L105 was not covered by tests

if ($name === false) {
throw InvalidColumnIndex::new($index);

Check warning on line 108 in src/Driver/IBMDB2/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/IBMDB2/Result.php#L107-L108

Added lines #L107 - L108 were not covered by tests
}

return $name;

Check warning on line 111 in src/Driver/IBMDB2/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/IBMDB2/Result.php#L111

Added line #L111 was not covered by tests
}

public function free(): void
{
db2_free_result($this->statement);
Expand Down
17 changes: 17 additions & 0 deletions src/Driver/Middleware/AbstractResultMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
namespace Doctrine\DBAL\Driver\Middleware;

use Doctrine\DBAL\Driver\Result;
use LogicException;

use function get_debug_type;
use function method_exists;
use function sprintf;

abstract class AbstractResultMiddleware implements Result
{
Expand Down Expand Up @@ -61,6 +66,18 @@
return $this->wrappedResult->columnCount();
}

public function getColumnName(int $index): string
{
if (! method_exists($this->wrappedResult, 'getColumnName')) {
throw new LogicException(sprintf(
'The driver result %s does not support accessing the column name.',
get_debug_type($this->wrappedResult),
));

Check warning on line 75 in src/Driver/Middleware/AbstractResultMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Middleware/AbstractResultMiddleware.php#L72-L75

Added lines #L72 - L75 were not covered by tests
}

return $this->wrappedResult->getColumnName($index);
}

public function free(): void
{
$this->wrappedResult->free();
Expand Down
6 changes: 6 additions & 0 deletions src/Driver/Mysqli/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Mysqli\Exception\StatementError;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;
use mysqli_sql_exception;
use mysqli_stmt;

Expand Down Expand Up @@ -157,6 +158,11 @@
return $this->statement->field_count;
}

public function getColumnName(int $index): string

Check warning on line 161 in src/Driver/Mysqli/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Mysqli/Result.php#L161

Added line #L161 was not covered by tests
{
return $this->columnNames[$index] ?? throw InvalidColumnIndex::new($index);

Check warning on line 163 in src/Driver/Mysqli/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Mysqli/Result.php#L163

Added line #L163 was not covered by tests
}

public function free(): void
{
$this->statement->free_result();
Expand Down
13 changes: 13 additions & 0 deletions src/Driver/OCI8/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\OCI8\Exception\Error;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;

use function oci_cancel;
use function oci_error;
Expand Down Expand Up @@ -95,6 +96,18 @@
return 0;
}

public function getColumnName(int $index): string

Check warning on line 99 in src/Driver/OCI8/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Result.php#L99

Added line #L99 was not covered by tests
{
// OCI expects a 1-based index while DBAL works with a O-based index.
$name = @oci_field_name($this->statement, $index + 1);

Check warning on line 102 in src/Driver/OCI8/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Result.php#L102

Added line #L102 was not covered by tests

if ($name === false) {
throw InvalidColumnIndex::new($index);

Check warning on line 105 in src/Driver/OCI8/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Result.php#L104-L105

Added lines #L104 - L105 were not covered by tests
}

return $name;

Check warning on line 108 in src/Driver/OCI8/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Result.php#L108

Added line #L108 was not covered by tests
}

public function free(): void
{
oci_cancel($this->statement);
Expand Down
16 changes: 16 additions & 0 deletions src/Driver/PDO/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Doctrine\DBAL\Driver\PDO;

use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;
use PDO;
use PDOException;
use PDOStatement;
Expand Down Expand Up @@ -73,6 +74,21 @@
}
}

public function getColumnName(int $index): string
{
try {
$meta = $this->statement->getColumnMeta($index);

if ($meta === false) {
throw InvalidColumnIndex::new($index);
}

return $meta['name'];
} catch (PDOException $exception) {
throw Exception::new($exception);

Check warning on line 88 in src/Driver/PDO/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/Result.php#L88

Added line #L88 was not covered by tests
}
}

public function free(): void
{
$this->statement->closeCursor();
Expand Down
15 changes: 15 additions & 0 deletions src/Driver/PgSQL/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\PgSQL\Exception\UnexpectedValue;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;
use PgSql\Result as PgSqlResult;
use ValueError;

use function array_keys;
use function array_map;
Expand Down Expand Up @@ -145,6 +147,19 @@
return pg_num_fields($this->result);
}

public function getColumnName(int $index): string

Check warning on line 150 in src/Driver/PgSQL/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PgSQL/Result.php#L150

Added line #L150 was not covered by tests
{
if ($this->result === null) {
throw InvalidColumnIndex::new($index);

Check warning on line 153 in src/Driver/PgSQL/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PgSQL/Result.php#L152-L153

Added lines #L152 - L153 were not covered by tests
}

try {
return pg_field_name($this->result, $index);
} catch (ValueError) {
throw InvalidColumnIndex::new($index);

Check warning on line 159 in src/Driver/PgSQL/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PgSQL/Result.php#L157-L159

Added lines #L157 - L159 were not covered by tests
}
}

public function free(): void
{
if ($this->result === null) {
Expand Down
2 changes: 2 additions & 0 deletions src/Driver/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

/**
* Driver-level statement execution result.
*
* @method string getColumnName(int $index)
*/
interface Result
{
Expand Down
13 changes: 13 additions & 0 deletions src/Driver/SQLSrv/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@

use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;

use function sqlsrv_fetch;
use function sqlsrv_fetch_array;
use function sqlsrv_field_metadata;
use function sqlsrv_num_fields;
use function sqlsrv_rows_affected;

Expand Down Expand Up @@ -87,6 +89,17 @@ public function columnCount(): int
return 0;
}

public function getColumnName(int $index): string
{
$meta = sqlsrv_field_metadata($this->statement);

if ($meta === false || ! isset($meta[$index])) {
throw InvalidColumnIndex::new($index);
}

return $meta[$index]['Name'];
}

public function free(): void
{
// emulate it by fetching and discarding rows, similarly to what PDO does in this case
Expand Down
16 changes: 16 additions & 0 deletions src/Driver/SQLite3/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Doctrine\DBAL\Driver\FetchUtils;
use Doctrine\DBAL\Driver\Result as ResultInterface;
use Doctrine\DBAL\Exception\InvalidColumnIndex;
use SQLite3Result;

use const SQLITE3_ASSOC;
Expand Down Expand Up @@ -76,6 +77,21 @@
return $this->result->numColumns();
}

public function getColumnName(int $index): string

Check warning on line 80 in src/Driver/SQLite3/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/SQLite3/Result.php#L80

Added line #L80 was not covered by tests
{
if ($this->result === null) {
throw InvalidColumnIndex::new($index);

Check warning on line 83 in src/Driver/SQLite3/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/SQLite3/Result.php#L82-L83

Added lines #L82 - L83 were not covered by tests
}

$name = $this->result->columnName($index);

Check warning on line 86 in src/Driver/SQLite3/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/SQLite3/Result.php#L86

Added line #L86 was not covered by tests

if ($name === false) {
throw InvalidColumnIndex::new($index);

Check warning on line 89 in src/Driver/SQLite3/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/SQLite3/Result.php#L88-L89

Added lines #L88 - L89 were not covered by tests
}

return $name;

Check warning on line 92 in src/Driver/SQLite3/Result.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/SQLite3/Result.php#L92

Added line #L92 was not covered by tests
}

public function free(): void
{
if ($this->result === null) {
Expand Down
19 changes: 19 additions & 0 deletions src/Exception/InvalidColumnIndex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Doctrine\DBAL\Exception;

use Doctrine\DBAL\Exception;
use LogicException;

use function sprintf;

/** @psalm-immutable */
final class InvalidColumnIndex extends LogicException implements Exception
{
public static function new(int $index): self
{
return new self(sprintf('Invalid column index "%s".', $index));
}
}
14 changes: 14 additions & 0 deletions src/Portability/Converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use function array_reduce;
use function is_string;
use function rtrim;
use function strtolower;
use function strtoupper;

use const CASE_LOWER;
use const CASE_UPPER;
Expand All @@ -26,6 +28,7 @@ final class Converter
private readonly Closure $convertAllNumeric;
private readonly Closure $convertAllAssociative;
private readonly Closure $convertFirstColumn;
private readonly Closure $convertColumnName;

/**
* @param bool $convertEmptyStringToNull Whether each empty string should
Expand All @@ -48,6 +51,12 @@ public function __construct(bool $convertEmptyStringToNull, bool $rightTrimStrin
$this->convertAllNumeric = $this->createConvertAll($convertNumeric);
$this->convertAllAssociative = $this->createConvertAll($convertAssociative);
$this->convertFirstColumn = $this->createConvertAll($convertValue);

$this->convertColumnName = match ($case) {
null => static fn (string $name) => $name,
self::CASE_LOWER => strtolower(...),
self::CASE_UPPER => strtoupper(...),
};
}

/**
Expand Down Expand Up @@ -105,6 +114,11 @@ public function convertFirstColumn(array $data): array
return ($this->convertFirstColumn)($data);
}

public function convertColumnName(string $name): string
{
return ($this->convertColumnName)($name);
}

/**
* @param T $value
*
Expand Down
7 changes: 7 additions & 0 deletions src/Portability/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,11 @@ public function fetchFirstColumn(): array
parent::fetchFirstColumn(),
);
}

public function getColumnName(int $index): string
{
return $this->converter->convertColumnName(
parent::getColumnName($index),
);
}
}
Loading
Loading