1
0
mirror of https://github.com/danog/postgres.git synced 2024-11-26 12:04:50 +01:00

Provide SQL query to QueryError

This was an oversight when QueryExecutionError was added some time ago.

Closes #26.
This commit is contained in:
Aaron Piotrowski 2020-03-25 13:51:55 -05:00
parent 54186c9d26
commit 13ac10a086
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
4 changed files with 39 additions and 18 deletions

View File

@ -34,6 +34,17 @@ final class PgSqlCommandResult implements CommandResult
}
/**
* @deprecated This is not meant to be used to get the last insertion ID. Use `INSERT ... RETURNING column_name`
* to get the last auto-increment ID.
*
* $sql = "INSERT INTO person (lastname, firstname) VALUES (?, ?) RETURNING id;"
* $statement = yield $pool->prepare($sql);
* $result = yield $statement->execute(['Doe', 'John']);
* if (!yield $result->advance()) {
* throw new \RuntimeException("Insertion failed");
* }
* $id = $result->getCurrent()['id'];
*
* @return string
*/
public function getLastOid(): string

View File

@ -241,13 +241,14 @@ final class PgSqlHandle implements Handle
/**
* @param resource $result PostgreSQL result resource.
* @param string $sql Query SQL.
*
* @return \Amp\Sql\CommandResult|ResultSet
*
* @throws FailureException
* @throws QueryError
*/
private function createResult($result)
private function createResult($result, string $sql)
{
switch (\pg_result_status($result, \PGSQL_STATUS_LONG)) {
case \PGSQL_EMPTY_QUERY:
@ -265,7 +266,7 @@ final class PgSqlHandle implements Handle
foreach (self::DIAGNOSTIC_CODES as $fieldCode => $desciption) {
$diagnostics[$desciption] = \pg_result_error_field($result, $fieldCode);
}
throw new QueryExecutionError(\pg_result_error($result), $diagnostics);
throw new QueryExecutionError(\pg_result_error($result), $diagnostics, null, $sql);
case \PGSQL_BAD_RESPONSE:
throw new FailureException(\pg_result_error($result));
@ -286,7 +287,8 @@ final class PgSqlHandle implements Handle
public function statementExecute(string $name, array $params): Promise
{
return call(function () use ($name, $params) {
return $this->createResult(yield from $this->send("pg_send_execute", $name, $params));
\assert(isset($this->statements[$name]), "Named statement not found when executing");
return $this->createResult(yield from $this->send("pg_send_execute", $name, $params), $this->statements[$name]->sql);
});
}
@ -326,7 +328,7 @@ final class PgSqlHandle implements Handle
}
return call(function () use ($sql) {
return $this->createResult(yield from $this->send("pg_send_query", $sql));
return $this->createResult(yield from $this->send("pg_send_query", $sql), $sql);
});
}
@ -343,7 +345,7 @@ final class PgSqlHandle implements Handle
$params = Internal\replaceNamedParams($params, $names);
return call(function () use ($sql, $params) {
return $this->createResult(yield from $this->send("pg_send_query_params", $sql, $params));
return $this->createResult(yield from $this->send("pg_send_query_params", $sql, $params), $sql);
});
}
@ -378,12 +380,15 @@ final class PgSqlHandle implements Handle
use Struct;
public $refCount = 1;
public $promise;
public $sql;
};
$storage->sql = $sql;
$this->statements[$name] = $storage;
try {
yield ($storage->promise = call(function () use ($name, $modifiedSql) {
yield ($storage->promise = call(function () use ($name, $modifiedSql, $sql) {
$result = yield from $this->send("pg_send_prepare", $name, $modifiedSql);
switch (\pg_result_status($result, \PGSQL_STATUS_LONG)) {
@ -396,7 +401,7 @@ final class PgSqlHandle implements Handle
foreach (self::DIAGNOSTIC_CODES as $fieldCode => $description) {
$diagnostics[$description] = \pg_result_error_field($result, $fieldCode);
}
throw new QueryExecutionError(\pg_result_error($result), $diagnostics);
throw new QueryExecutionError(\pg_result_error($result), $diagnostics, null, $sql);
case \PGSQL_BAD_RESPONSE:
throw new FailureException(\pg_result_error($result));

View File

@ -163,6 +163,7 @@ final class PqHandle implements Handle
}
/**
* @param string|null Query SQL or null if not related.
* @param callable $method Method to execute.
* @param mixed ...$args Arguments to pass to function.
*
@ -172,7 +173,7 @@ final class PqHandle implements Handle
*
* @throws FailureException
*/
private function send(callable $method, ...$args): \Generator
private function send(?string $sql, callable $method, ...$args): \Generator
{
while ($this->busy) {
try {
@ -232,7 +233,7 @@ final class PqHandle implements Handle
case pq\Result::NONFATAL_ERROR:
case pq\Result::FATAL_ERROR:
throw new QueryExecutionError($result->errorMessage, $result->diag);
throw new QueryExecutionError($result->errorMessage, $result->diag, null, $sql ?? '');
case pq\Result::BAD_RESPONSE:
throw new FailureException($result->errorMessage);
@ -306,7 +307,7 @@ final class PqHandle implements Handle
\assert($storage->statement instanceof pq\Statement, "Statement storage in invalid state");
return new Coroutine($this->send([$storage->statement, "execAsync"], $params));
return new Coroutine($this->send($storage->sql, [$storage->statement, "execAsync"], $params));
}
/**
@ -334,7 +335,7 @@ final class PqHandle implements Handle
\assert($storage->statement instanceof pq\Statement, "Statement storage in invalid state");
return new Coroutine($this->send([$storage->statement, "deallocateAsync"]));
return new Coroutine($this->send(null, [$storage->statement, "deallocateAsync"]));
}
/**
@ -346,7 +347,7 @@ final class PqHandle implements Handle
throw new \Error("The connection to the database has been closed");
}
return new Coroutine($this->send([$this->handle, "execAsync"], $sql));
return new Coroutine($this->send($sql, [$this->handle, "execAsync"], $sql));
}
/**
@ -361,7 +362,7 @@ final class PqHandle implements Handle
$sql = Internal\parseNamedParams($sql, $names);
$params = Internal\replaceNamedParams($params, $names);
return new Coroutine($this->send([$this->handle, "execParamsAsync"], $sql, $params));
return new Coroutine($this->send($sql, [$this->handle, "execParamsAsync"], $sql, $params));
}
/**
@ -396,13 +397,16 @@ final class PqHandle implements Handle
public $refCount = 1;
public $promise;
public $statement;
public $sql;
};
$storage->sql = $sql;
$this->statements[$name] = $storage;
try {
$storage->statement = yield (
$storage->promise = new Coroutine($this->send([$this->handle, "prepareAsync"], $name, $modifiedSql))
$storage->promise = new Coroutine($this->send($sql, [$this->handle, "prepareAsync"], $name, $modifiedSql))
);
} catch (\Throwable $exception) {
unset($this->statements[$name]);
@ -420,7 +424,7 @@ final class PqHandle implements Handle
*/
public function notify(string $channel, string $payload = ""): Promise
{
return new Coroutine($this->send([$this->handle, "notifyAsync"], $channel, $payload));
return new Coroutine($this->send(null, [$this->handle, "notifyAsync"], $channel, $payload));
}
/**
@ -437,6 +441,7 @@ final class PqHandle implements Handle
try {
yield from $this->send(
null,
[$this->handle, "listenAsync"],
$channel,
static function (string $channel, string $message, int $pid) use ($emitter) {
@ -474,7 +479,7 @@ final class PqHandle implements Handle
if (!$this->handle) {
$promise = new Success; // Connection already closed.
} else {
$promise = new Coroutine($this->send([$this->handle, "unlistenAsync"], $channel));
$promise = new Coroutine($this->send(null, [$this->handle, "unlistenAsync"], $channel));
}
$promise->onResolve([$emitter, "complete"]);

View File

@ -9,9 +9,9 @@ class QueryExecutionError extends QueryError
/** @var mixed[] */
private $diagnostics;
public function __construct(string $message, array $diagnostics, \Throwable $previous = null)
public function __construct(string $message, array $diagnostics, \Throwable $previous = null, string $query = '')
{
parent::__construct($message, 0, $previous);
parent::__construct($message, $query, $previous);
$this->diagnostics = $diagnostics;
}