1
0
mirror of https://github.com/danog/postgres.git synced 2024-12-02 09:27:54 +01:00

Reuse connection statement with dissimilar parameters

This commit is contained in:
Aaron Piotrowski 2019-04-03 09:12:04 -05:00
parent 93f5a9cf1f
commit a60569ad76
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
3 changed files with 80 additions and 60 deletions

View File

@ -364,20 +364,22 @@ final class PgSqlHandle implements Handle
throw new \Error("The connection to the database has been closed");
}
return call(function () use ($sql) {
$modifiedSql = Internal\parseNamedParams($sql, $names);
$name = Handle::STATEMENT_NAME_PREFIX . \sha1($sql);
$name = Handle::STATEMENT_NAME_PREFIX . \sha1($modifiedSql);
if (isset($this->statements[$name])) {
$storage = $this->statements[$name];
if ($storage->promise instanceof Promise) {
return $storage->promise;
// Do not return promised prepared statement object, as the $names array may differ.
yield $storage->promise;
}
++$storage->refCount; // Only increase refCount when returning a new object.
++$storage->refCount;
return new Success(new PgSqlStatement($this, $name, $sql, $names));
return new PgSqlStatement($this, $name, $sql, $names);
}
$storage = new class {
@ -388,20 +390,13 @@ final class PgSqlHandle implements Handle
$this->statements[$name] = $storage;
return $storage->promise = call(function () use ($storage, $name, $names, $sql, $modifiedSql) {
try {
/** @var resource $result PostgreSQL result resource. */
yield ($storage->promise = call(function () use ($name, $modifiedSql) {
$result = yield from $this->send("pg_send_prepare", $name, $modifiedSql);
} catch (\Throwable $exception) {
unset($this->statements[$name]);
throw $exception;
} finally {
$storage->promise = null;
}
switch (\pg_result_status($result, \PGSQL_STATUS_LONG)) {
case \PGSQL_COMMAND_OK:
return new PgSqlStatement($this, $name, $sql, $names);
return $name; // Statement created successfully.
case \PGSQL_NONFATAL_ERROR:
case \PGSQL_FATAL_ERROR:
@ -419,6 +414,15 @@ final class PgSqlHandle implements Handle
throw new FailureException("Unknown result status");
// @codeCoverageIgnoreEnd
}
}));
} catch (\Throwable $exception) {
unset($this->statements[$name]);
throw $exception;
} finally {
$storage->promise = null;
}
return new PgSqlStatement($this, $name, $sql, $names);
});
}

View File

@ -385,20 +385,22 @@ final class PqHandle implements Handle
throw new \Error("The connection to the database has been closed");
}
return call(function () use ($sql) {
$modifiedSql = Internal\parseNamedParams($sql, $names);
$name = Handle::STATEMENT_NAME_PREFIX . \sha1($sql);
$name = Handle::STATEMENT_NAME_PREFIX . \sha1($modifiedSql);
if (isset($this->statements[$name])) {
$storage = $this->statements[$name];
if ($storage->promise instanceof Promise) {
return $storage->promise;
// Do not return promised prepared statement object, as the $names array may differ.
yield $storage->promise;
}
++$storage->refCount; // Only increase refCount when returning a new object.
++$storage->refCount;
return new Success(new PqStatement($this, $name, $sql, $names));
return new PqStatement($this, $name, $sql, $names);
}
$storage = new class {
@ -410,9 +412,10 @@ final class PqHandle implements Handle
$this->statements[$name] = $storage;
return $storage->promise = call(function () use ($storage, $names, $name, $sql, $modifiedSql) {
try {
$storage->statement = yield from $this->send([$this->handle, "prepareAsync"], $name, $modifiedSql);
$storage->statement = yield (
$storage->promise = new Coroutine($this->send([$this->handle, "prepareAsync"], $name, $modifiedSql))
);
} catch (\Throwable $exception) {
unset($this->statements[$name]);
throw $exception;

View File

@ -361,6 +361,19 @@ abstract class AbstractLinkTest extends TestCase
$this->assertInstanceOf(Statement::class, $statement2);
$this->assertNotSame($statement1, $statement2);
$data = $this->getData()[0];
$results = yield [$statement1->execute([$data[0]]), $statement2->execute(['domain' => $data[0]])];
foreach ($results as $result) {
/** @var \Amp\Postgres\ResultSet $result */
while (yield $result->advance()) {
$row = $result->getCurrent();
$this->assertSame($data[0], $row['domain']);
$this->assertSame($data[1], $row['tld']);
}
}
});
}