Skip to content

Commit e0428f6

Browse files
committed
Doctrine3: Making actual progress
1 parent bf946f3 commit e0428f6

21 files changed

+598
-197
lines changed

src/Crate/DBAL/Driver/PDOCrate/CrateStatement.php

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,128 @@
2222

2323
namespace Crate\DBAL\Driver\PDOCrate;
2424

25+
use Crate\PDO\PDOStatement;
26+
use Crate\PDO\PDOInterface;
27+
use Doctrine\DBAL\Driver\PDO\Exception;
2528
use Doctrine\DBAL\Driver\PDOStatementImplementations;
2629
use Doctrine\DBAL\Driver\Statement as StatementInterface;
27-
use Crate\PDO\PDOStatement;
30+
use Doctrine\DBAL\Driver\Result as ResultInterface;
31+
use Doctrine\DBAL\ParameterType;
32+
use Doctrine\Deprecations\Deprecation;
33+
use PDO;
2834

2935
/**
3036
* @internal
3137
*/
32-
class CrateStatement extends PDOStatement implements StatementInterface
38+
final class CrateStatement implements StatementInterface
3339
{
34-
use PDOStatementImplementations;
40+
41+
/**
42+
* @var PDOInterface
43+
*/
44+
private $pdo;
45+
46+
private PDOStatement $stmt;
47+
48+
public function __construct(PDOInterface $pdo, $sql)
49+
{
50+
$this->pdo = $pdo;
51+
$this->stmt = $pdo->prepare($sql);
52+
}
53+
54+
/**
55+
* {@inheritDoc}
56+
*/
57+
public function execute($params = null): ResultInterface
58+
{
59+
60+
if ($params !== null) {
61+
Deprecation::trigger(
62+
'doctrine/dbal',
63+
'https://github.com/doctrine/dbal/pull/5556',
64+
'Passing $params to Statement::execute() is deprecated. Bind parameters using'
65+
. ' Statement::bindParam() or Statement::bindValue() instead.',
66+
);
67+
}
68+
$this->stmt->execute($params);
69+
return new Result($this);
70+
}
71+
72+
/**
73+
* {@inheritDoc}
74+
*/
75+
public function columnCount(): int
76+
{
77+
return $this->stmt->columnCount();
78+
}
79+
80+
/**
81+
* {@inheritDoc}
82+
*/
83+
public function rowCount(): int
84+
{
85+
return $this->stmt->rowCount();
86+
}
87+
88+
/**
89+
* {@inheritDoc}
90+
*/
91+
public function bindValue($param, $value, $type = ParameterType::STRING)
92+
{
93+
$this->stmt->bindValue($param, $value, $type);
94+
}
95+
96+
/**
97+
* {@inheritDoc}
98+
*/
99+
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null)
100+
{
101+
return $this->stmt->bindParam($param, $variable, $type, $length);
102+
}
103+
104+
/**
105+
* {@inheritDoc}
106+
*/
107+
public function fetch(
108+
$fetch_style = PDO::FETCH_ASSOC,
109+
$cursor_orientation = PDO::FETCH_ORI_NEXT,
110+
$cursor_offset = 0,
111+
) {
112+
return $this->stmt->fetch($fetch_style, $cursor_orientation, $cursor_offset);
113+
}
114+
115+
/**
116+
* @phpstan-param PDO::FETCH_* $mode
117+
*
118+
* @return list<mixed>
119+
*
120+
* @throws Exception
121+
*/
122+
public function fetchAll(int $mode): array
123+
{
124+
return $this->stmt->fetchAll($mode);
125+
}
126+
127+
public function fetchColumn($column_number = 0)
128+
{
129+
return $this->stmt->fetchColumn($column_number);
130+
}
131+
132+
/**
133+
* {@inheritDoc}
134+
*/
135+
public function closeCursor(): int
136+
{
137+
return $this->stmt->closeCursor();
138+
}
139+
140+
/**
141+
* Gets the wrapped driver statement.
142+
*
143+
* @return Driver\Statement
144+
*/
145+
public function getWrappedStatement()
146+
{
147+
return $this->stmt;
148+
}
35149
}

src/Crate/DBAL/Driver/PDOCrate/Driver.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
use Crate\DBAL\Platforms\CratePlatform4;
2727
use Crate\DBAL\Schema\CrateSchemaManager;
2828
use Doctrine\DBAL\Connection;
29-
use Doctrine\DBAL\Driver\API\ExceptionConverter;
3029
use Doctrine\DBAL\Platforms\AbstractPlatform;
3130
use Doctrine\DBAL\VersionAwarePlatformDriver;
3231

@@ -70,16 +69,16 @@ private function constructPdoDsn(array $params)
7069
*/
7170
public function getDatabasePlatform()
7271
{
73-
return new CratePlatform();
72+
return new CratePlatform4();
7473
}
7574

7675
/**
7776
* {@inheritDoc}
7877
*/
7978
public function getSchemaManager(Connection $conn, AbstractPlatform $platform)
8079
{
81-
// TODO: `$platform` added when upgrading to Doctrine3 - what to do with it?
82-
return new CrateSchemaManager($conn);
80+
// Added by Doctrine 3.
81+
return new CrateSchemaManager($conn, $conn->getDatabasePlatform());
8382
}
8483

8584
/**
@@ -117,7 +116,7 @@ public function createDatabasePlatformForVersion($version)
117116
*/
118117
public function getExceptionConverter(): ExceptionConverter
119118
{
120-
// TODO: Implement getExceptionConverter() method.
121-
// Added when upgrading to Doctrine3.
119+
// Added by Doctrine 3.
120+
return new ExceptionConverter();
122121
}
123122
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Crate\DBAL\Driver\PDOCrate;
6+
7+
use Doctrine\DBAL\Driver\AbstractException;
8+
use PDOException;
9+
10+
/** @internal */
11+
final class Exception extends AbstractException
12+
{
13+
public static function new(PDOException $exception): self
14+
{
15+
if ($exception->errorInfo !== null) {
16+
[$sqlState, $code] = $exception->errorInfo;
17+
18+
$code ??= 0;
19+
} else {
20+
$code = $exception->getCode();
21+
$sqlState = null;
22+
}
23+
24+
return new self($exception->getMessage(), $sqlState, $code, $exception);
25+
}
26+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Crate\DBAL\Driver\PDOCrate;
6+
7+
use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface;
8+
use Doctrine\DBAL\Driver\Exception;
9+
use Doctrine\DBAL\Exception\ConnectionException;
10+
use Doctrine\DBAL\Exception\DriverException;
11+
use Doctrine\DBAL\Exception\InvalidFieldNameException;
12+
use Doctrine\DBAL\Exception\SchemaDoesNotExist;
13+
use Doctrine\DBAL\Exception\SyntaxErrorException;
14+
use Doctrine\DBAL\Exception\TableExistsException;
15+
use Doctrine\DBAL\Exception\TableNotFoundException;
16+
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
17+
use Doctrine\DBAL\Query;
18+
19+
use Doctrine\DBAL\Schema\Exception\ColumnDoesNotExist;
20+
use function strpos;
21+
22+
/** @internal */
23+
final class ExceptionConverter implements ExceptionConverterInterface
24+
{
25+
/** @link https://cratedb.com/docs/crate/reference/en/latest/interfaces/http.html#error-codes */
26+
public function convert(Exception $exception, ?Query $query): DriverException
27+
{
28+
switch ($exception->getSQLState()) {
29+
case '4000':
30+
return new SyntaxErrorException($exception, $query);
31+
32+
case '4008':
33+
case '4043':
34+
return new InvalidFieldNameException($exception, $query);
35+
36+
case '4041':
37+
return new TableNotFoundException($exception, $query);
38+
39+
case '4045':
40+
return new SchemaDoesNotExist($exception, $query);
41+
42+
case '4091':
43+
return new UniqueConstraintViolationException($exception, $query);
44+
45+
case '4093':
46+
return new TableExistsException($exception, $query);
47+
}
48+
49+
// Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.4.10),
50+
// in some cases (mainly connection errors) the PDO exception wouldn't provide a SQLSTATE via its code.
51+
// We have to match against the SQLSTATE in the error message in these cases.
52+
if ($exception->getCode() === 7 && strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) {
53+
return new ConnectionException($exception, $query);
54+
}
55+
56+
return new DriverException($exception, $query);
57+
}
58+
}

src/Crate/DBAL/Driver/PDOCrate/PDOConnection.php

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@
2323
namespace Crate\DBAL\Driver\PDOCrate;
2424

2525
use Crate\PDO\PDOCrateDB;
26+
use Crate\PDO\PDOStatement;
2627
use Doctrine\DBAL\Driver\PDO\Exception;
27-
use Doctrine\DBAL\Driver\PDO\Statement;
28-
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
29-
use Doctrine\DBAL\Driver\Statement as StatementInterface;
28+
use Doctrine\DBAL\Driver\Result as ResultInterface;
29+
use Doctrine\DBAL\Driver\Connection as ConnectionInterface;
30+
use Doctrine\DBAL\ParameterType;
31+
use PDO;
32+
use PDOException;
3033

31-
class PDOConnection extends PDOCrateDB implements ServerInfoAwareConnection
34+
class PDOConnection implements ConnectionInterface
3235
{
36+
37+
private PDOCrateDB $connection;
38+
3339
/**
3440
* @param string $dsn
3541
* @param string $user
@@ -38,19 +44,20 @@ class PDOConnection extends PDOCrateDB implements ServerInfoAwareConnection
3844
*/
3945
public function __construct($dsn, $user = null, $password = null, ?array $options = null)
4046
{
41-
parent::__construct($dsn, $user, $password, $options);
42-
$this->setAttribute(\PDO::ATTR_STATEMENT_CLASS, CrateStatement::class);
43-
$this->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
47+
$this->connection = new PDOCrateDB($dsn, $user, $password, $options);
48+
$this->connection->setAttribute(PDO::ATTR_STATEMENT_CLASS, PDOStatement::class);
49+
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
4450
}
4551

46-
/**
47-
* Checks whether a query is required to retrieve the database server version.
48-
*
49-
* @return boolean True if a query is required to retrieve the database server version, false otherwise.
50-
*/
51-
public function requiresQueryForServerVersion()
52+
public function getServerVersion()
5253
{
53-
return false;
54+
// Unable to detect platform version.
55+
return null;
56+
}
57+
58+
public function getNativeConnection(): PDOCrateDB
59+
{
60+
return $this->connection;
5461
}
5562

5663
/**
@@ -61,13 +68,10 @@ public function requiresQueryForServerVersion()
6168
* - https://github.com/doctrine/dbal/pull/517
6269
* - https://github.com/doctrine/dbal/pull/373
6370
*/
64-
public function prepare($sql, $options = null): StatementInterface
71+
public function prepare($sql, $options = []): CrateStatement
6572
{
6673
try {
67-
$stmt = $this->connection->prepare($sql, $options);
68-
assert($stmt instanceof PDOStatement);
69-
70-
return new Statement($stmt);
74+
return new CrateStatement($this->connection, $sql, $options);
7175
} catch (PDOException $exception) {
7276
throw Exception::new($exception);
7377
}
@@ -80,12 +84,60 @@ public function exec($sql): int
8084
{
8185
try {
8286
$result = $this->connection->exec($sql);
87+
assert($result !== false);
88+
return $result;
89+
} catch (PDOException $exception) {
90+
throw Exception::new($exception);
91+
}
92+
}
8393

94+
/**
95+
* {@inheritDoc}
96+
*/
97+
public function quer2y(string $sql): Result
98+
{
99+
try {
100+
$result = $this->connection->query($sql);
84101
assert($result !== false);
102+
return new Result($result);
103+
} catch (PDOException $exception) {
104+
throw Exception::new($exception);
105+
}
106+
}
85107

86-
return $result;
108+
public function query(string $sql): ResultInterface
109+
{
110+
try {
111+
$stmt = $this->prepare($sql);
112+
$stmt->execute();
113+
return new Result($stmt);
87114
} catch (PDOException $exception) {
88115
throw Exception::new($exception);
89116
}
90117
}
118+
119+
public function quote($value, $type = ParameterType::STRING): string
120+
{
121+
return $this->connection->quote($value, $type);
122+
}
123+
124+
public function lastInsertId($name = null): string
125+
{
126+
return $this->connection->lastInsertId($name);
127+
}
128+
129+
public function beginTransaction(): bool
130+
{
131+
return true;
132+
}
133+
134+
public function commit(): bool
135+
{
136+
return true;
137+
}
138+
139+
public function rollBack(): bool
140+
{
141+
return true;
142+
}
91143
}

0 commit comments

Comments
 (0)