Skip to content

Commit ce2247e

Browse files
authored
Fixed bug that database-pgsql does not support migration. (#5417)
1 parent 8d5feb1 commit ce2247e

9 files changed

+645
-29
lines changed

src/DBAL/Connection.php

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Database\PgSQL\DBAL;
13+
14+
use Doctrine\DBAL\Driver\Result as ResultInterface;
15+
use Doctrine\DBAL\Driver\Statement as StatementInterface;
16+
use Doctrine\DBAL\ParameterType;
17+
use Swoole\Coroutine\PostgreSQL;
18+
use Swoole\Coroutine\PostgreSQLStatement;
19+
20+
class Connection implements \Doctrine\DBAL\Driver\Connection
21+
{
22+
/**
23+
* Create a new PDO connection instance.
24+
*/
25+
public function __construct(private PostgreSQL $connection)
26+
{
27+
}
28+
29+
/**
30+
* Execute an SQL statement.
31+
*/
32+
public function exec(string $sql): int
33+
{
34+
$stmt = $this->connection->query($sql);
35+
36+
\assert($stmt instanceof PostgreSQLStatement);
37+
38+
return $stmt->affectedRows();
39+
}
40+
41+
/**
42+
* Prepare a new SQL statement.
43+
*/
44+
public function prepare(string $sql): StatementInterface
45+
{
46+
$stmt = $this->connection->prepare($sql);
47+
48+
\assert($stmt instanceof PostgreSQLStatement);
49+
50+
return new Statement($stmt);
51+
}
52+
53+
/**
54+
* Execute a new query against the connection.
55+
*/
56+
public function query(string $sql): ResultInterface
57+
{
58+
$stmt = $this->connection->query($sql);
59+
60+
\assert($stmt instanceof PostgreSQLStatement);
61+
62+
return new Result($stmt);
63+
}
64+
65+
/**
66+
* Get the last insert ID.
67+
*
68+
* @param null|string $name
69+
* @return string
70+
*/
71+
public function lastInsertId($name = null)
72+
{
73+
if ($name !== null) {
74+
return $this->query(sprintf('SELECT CURRVAL(%s)', $this->quote($name)))->fetchOne();
75+
}
76+
77+
return $this->query('SELECT LASTVAL()')->fetchOne();
78+
}
79+
80+
/**
81+
* Begin a new database transaction.
82+
*/
83+
public function beginTransaction(): bool
84+
{
85+
$this->exec('BEGIN');
86+
87+
return true;
88+
}
89+
90+
/**
91+
* Commit a database transaction.
92+
*/
93+
public function commit(): bool
94+
{
95+
$this->exec('COMMIT');
96+
97+
return true;
98+
}
99+
100+
/**
101+
* Roll back a database transaction.
102+
*/
103+
public function rollBack(): bool
104+
{
105+
$this->exec('ROLLBACK');
106+
107+
return true;
108+
}
109+
110+
/**
111+
* Wrap quotes around the given input.
112+
*
113+
* @param string $input
114+
* @param string $type
115+
* @return string
116+
*/
117+
public function quote($input, $type = ParameterType::STRING)
118+
{
119+
return $this->connection->escapeLiteral($input);
120+
}
121+
122+
/**
123+
* Get the server version for the connection.
124+
*/
125+
public function getServerVersion(): string
126+
{
127+
$result = $this->query('SHOW server_version');
128+
129+
$serverVersion = $result->fetchOne();
130+
if ($version = strstr($serverVersion, ' ', true)) {
131+
return $version;
132+
}
133+
134+
return $serverVersion;
135+
}
136+
137+
public function getNativeConnection(): PostgreSQL
138+
{
139+
return $this->connection;
140+
}
141+
}

src/DBAL/Exception.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Database\PgSQL\DBAL;
13+
14+
use Doctrine\DBAL\Driver\Exception as DriverExceptionInterface;
15+
use Exception as BaseException;
16+
use Throwable;
17+
18+
class Exception extends BaseException implements DriverExceptionInterface
19+
{
20+
/**
21+
* The SQLSTATE of the driver.
22+
*/
23+
private ?string $sqlState;
24+
25+
/**
26+
* @param string $message the driver error message
27+
* @param null|string $sqlState the SQLSTATE the driver is in at the time the error occurred, if any
28+
* @param int $code the driver specific error code if any
29+
* @param null|Throwable $previous the previous throwable used for the exception chaining
30+
*/
31+
public function __construct($message, $sqlState = null, $code = 0, ?Throwable $previous = null)
32+
{
33+
parent::__construct($message, $code, $previous);
34+
35+
$this->sqlState = $sqlState;
36+
}
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
public function getSQLState()
42+
{
43+
return $this->sqlState;
44+
}
45+
}

src/DBAL/PostgresDriver.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,20 @@
1212
namespace Hyperf\Database\PgSQL\DBAL;
1313

1414
use Doctrine\DBAL\Driver\AbstractPostgreSQLDriver;
15-
use Hyperf\Database\DBAL\Concerns\ConnectsToDatabase;
15+
use InvalidArgumentException;
16+
use Swoole\Coroutine\PostgreSQL;
1617

1718
class PostgresDriver extends AbstractPostgreSQLDriver
1819
{
19-
use ConnectsToDatabase;
20+
/**
21+
* Create a new database connection.
22+
*/
23+
public function connect(array $params)
24+
{
25+
if (! isset($params['pdo']) || ! $params['pdo'] instanceof PostgreSQL) {
26+
throw new InvalidArgumentException('The "pdo" property must be required.');
27+
}
28+
29+
return new Connection($params['pdo']);
30+
}
2031
}

src/DBAL/Result.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Database\PgSQL\DBAL;
13+
14+
use Doctrine\DBAL\Driver\Result as ResultInterface;
15+
use Swoole\Coroutine\PostgreSQLStatement;
16+
17+
final class Result implements ResultInterface
18+
{
19+
public function __construct(private PostgreSQLStatement $result)
20+
{
21+
}
22+
23+
/** {@inheritdoc} */
24+
public function fetchNumeric()
25+
{
26+
return $this->result->fetchArray(result_type: SW_PGSQL_NUM);
27+
}
28+
29+
/** {@inheritdoc} */
30+
public function fetchAssociative()
31+
{
32+
return $this->result->fetchAssoc();
33+
}
34+
35+
/** {@inheritdoc} */
36+
public function fetchOne()
37+
{
38+
$row = $this->fetchNumeric();
39+
if ($row === false) {
40+
return false;
41+
}
42+
43+
return $row[0];
44+
}
45+
46+
/** {@inheritdoc} */
47+
public function fetchAllNumeric(): array
48+
{
49+
return $this->result->fetchAll(SW_PGSQL_NUM);
50+
}
51+
52+
/** {@inheritdoc} */
53+
public function fetchAllAssociative(): array
54+
{
55+
return $this->result->fetchAll(SW_PGSQL_ASSOC);
56+
}
57+
58+
/** {@inheritdoc} */
59+
public function fetchFirstColumn(): array
60+
{
61+
$resultSet = $this->result->fetchAll(SW_PGSQL_NUM);
62+
if ($resultSet === false) {
63+
return [];
64+
}
65+
66+
return array_map(fn ($row) => $row[0], $resultSet);
67+
}
68+
69+
public function rowCount(): int
70+
{
71+
return (int) $this->result->affectedRows();
72+
}
73+
74+
public function columnCount(): int
75+
{
76+
return (int) $this->result->fieldCount();
77+
}
78+
79+
public function free(): void
80+
{
81+
}
82+
}

src/DBAL/Statement.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact [email protected]
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace Hyperf\Database\PgSQL\DBAL;
13+
14+
use Doctrine\DBAL\Driver\Statement as StatementInterface;
15+
use Doctrine\DBAL\ParameterType;
16+
use Swoole\Coroutine\PostgreSQLStatement;
17+
18+
use function ksort;
19+
20+
final class Statement implements StatementInterface
21+
{
22+
private array $parameters = [];
23+
24+
public function __construct(private PostgreSQLStatement $stmt)
25+
{
26+
}
27+
28+
/** {@inheritdoc} */
29+
public function bindValue($param, $value, $type = ParameterType::STRING): bool
30+
{
31+
$this->parameters[$param] = $value;
32+
return true;
33+
}
34+
35+
/** {@inheritdoc} */
36+
public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool
37+
{
38+
$this->parameters[$param] = &$variable;
39+
return true;
40+
}
41+
42+
/** {@inheritdoc} */
43+
public function execute($params = null): Result
44+
{
45+
if (! empty($params)) {
46+
foreach ($params as $param => $value) {
47+
if (is_int($param)) {
48+
$this->bindValue($param + 1, $value, ParameterType::STRING);
49+
} else {
50+
$this->bindValue($param, $value, ParameterType::STRING);
51+
}
52+
}
53+
}
54+
55+
ksort($this->parameters);
56+
57+
if (! $this->stmt->execute($this->parameters)) {
58+
throw new Exception($this->stmt->error ?? 'Execute failed.');
59+
}
60+
61+
return new Result($this->stmt);
62+
}
63+
}

0 commit comments

Comments
 (0)