2017-01-18 18:05:05 +01:00
|
|
|
<?php
|
2016-09-14 16:27:39 +02:00
|
|
|
|
|
|
|
namespace Amp\Postgres\Test;
|
|
|
|
|
2017-07-27 07:32:34 +02:00
|
|
|
use Amp\Coroutine;
|
|
|
|
use Amp\Delayed;
|
2019-09-27 05:41:47 +02:00
|
|
|
use Amp\Iterator;
|
2017-05-26 17:47:44 +02:00
|
|
|
use Amp\Loop;
|
2019-09-27 05:41:47 +02:00
|
|
|
use Amp\PHPUnit\AsyncTestCase;
|
2017-11-06 01:12:12 +01:00
|
|
|
use Amp\Postgres\Link;
|
2017-06-21 05:17:53 +02:00
|
|
|
use Amp\Postgres\Listener;
|
2017-12-01 17:28:36 +01:00
|
|
|
use Amp\Postgres\QueryExecutionError;
|
2017-12-03 02:56:40 +01:00
|
|
|
use Amp\Postgres\ResultSet;
|
2017-06-21 05:17:53 +02:00
|
|
|
use Amp\Postgres\Transaction;
|
2019-09-27 05:41:47 +02:00
|
|
|
use Amp\Promise;
|
2018-07-01 19:33:12 +02:00
|
|
|
use Amp\Sql\CommandResult;
|
|
|
|
use Amp\Sql\QueryError;
|
|
|
|
use Amp\Sql\Statement;
|
|
|
|
use Amp\Sql\Transaction as SqlTransaction;
|
2018-07-03 01:45:09 +02:00
|
|
|
use Amp\Sql\TransactionError;
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
abstract class AbstractLinkTest extends AsyncTestCase
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2016-09-14 16:27:39 +02:00
|
|
|
/** @var \Amp\Postgres\Connection */
|
|
|
|
protected $connection;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array Start test data for database.
|
|
|
|
*/
|
2020-02-06 23:34:49 +01:00
|
|
|
public function getData(): array
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2016-09-14 16:27:39 +02:00
|
|
|
return [
|
|
|
|
['amphp', 'org'],
|
|
|
|
['github', 'com'],
|
|
|
|
['google', 'com'],
|
|
|
|
['php', 'net'],
|
|
|
|
];
|
|
|
|
}
|
2017-05-16 06:28:37 +02:00
|
|
|
|
2017-06-15 05:46:25 +02:00
|
|
|
/**
|
|
|
|
* @param string $connectionString
|
|
|
|
*
|
2017-11-06 01:12:12 +01:00
|
|
|
* @return \Amp\Postgres\Link Connection or Link object to be tested.
|
2017-06-15 05:46:25 +02:00
|
|
|
*/
|
2017-11-06 01:12:12 +01:00
|
|
|
abstract public function createLink(string $connectionString): Link;
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2020-02-06 23:34:49 +01:00
|
|
|
public function setUp(): void
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
parent::setUp();
|
2017-11-18 04:33:49 +01:00
|
|
|
$this->connection = $this->createLink('host=localhost user=postgres');
|
2017-11-05 22:38:17 +01:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testQueryWithTupleResult(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $this->connection->query("SELECT * FROM test");
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2017-05-16 06:28:37 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData();
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testQueryWithUnconsumedTupleResult(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $this->connection->query("SELECT * FROM test");
|
2017-11-06 01:50:52 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2017-11-06 01:50:52 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
unset($result); // Force destruction of result object.
|
2017-11-06 01:50:52 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $this->connection->query("SELECT * FROM test");
|
2017-11-06 01:50:52 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2017-11-06 01:50:52 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData();
|
|
|
|
|
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
2017-11-06 01:50:52 +01:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testQueryWithCommandResult(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var CommandResult $result */
|
|
|
|
$result = yield $this->connection->query("INSERT INTO test VALUES ('canon', 'jp')");
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(CommandResult::class, $result);
|
|
|
|
$this->assertSame(1, $result->getAffectedRowCount());
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testQueryWithEmptyQuery(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2020-02-06 23:34:49 +01:00
|
|
|
$this->expectException(QueryError::class);
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Sql\CommandResult $result */
|
|
|
|
return $this->connection->query('');
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testQueryWithSyntaxError(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Sql\CommandResult $result */
|
|
|
|
try {
|
|
|
|
$result = yield $this->connection->query("SELECT & FROM test");
|
|
|
|
$this->fail(\sprintf("An instance of %s was expected to be thrown", QueryExecutionError::class));
|
|
|
|
} catch (QueryExecutionError $exception) {
|
|
|
|
$diagnostics = $exception->getDiagnostics();
|
|
|
|
$this->assertArrayHasKey("sqlstate", $diagnostics);
|
|
|
|
}
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepare(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$query = "SELECT * FROM test WHERE domain=\$1";
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement */
|
|
|
|
$statement = yield $this->connection->prepare($query);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame($query, $statement->getQuery());
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement->execute([$data[0]]);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2017-05-16 06:14:02 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2018-01-24 06:00:22 +01:00
|
|
|
/**
|
|
|
|
* @depends testPrepare
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareWithNamedParams(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$query = "SELECT * FROM test WHERE domain=:domain AND tld=:tld";
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement */
|
|
|
|
$statement = yield $this->connection->prepare($query);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame($query, $statement->getQuery());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement->execute(['domain' => $data[0], 'tld' => $data[1]]);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2018-01-24 06:00:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @depends testPrepare
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareWithUnnamedParams(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$query = "SELECT * FROM test WHERE domain=? AND tld=?";
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement */
|
|
|
|
$statement = yield $this->connection->prepare($query);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame($query, $statement->getQuery());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement->execute([$data[0], $data[1]]);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2018-01-24 06:00:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @depends testPrepare
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareWithNamedParamsWithDataAppearingAsNamedParam(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$query = "SELECT * FROM test WHERE domain=:domain OR domain=':domain'";
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement */
|
|
|
|
$statement = yield $this->connection->prepare($query);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame($query, $statement->getQuery());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement->execute(['domain' => $data[0]]);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2018-01-24 06:00:22 +01:00
|
|
|
}
|
|
|
|
|
2017-07-31 07:34:05 +02:00
|
|
|
/**
|
|
|
|
* @depends testPrepare
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareInvalidQuery(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->expectException(QueryExecutionError::class);
|
|
|
|
$this->expectExceptionMessage('column "invalid" does not exist');
|
2017-07-31 07:34:05 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$query = "SELECT * FROM test WHERE invalid=\$1";
|
|
|
|
|
|
|
|
/** @var Statement $statement */
|
|
|
|
return $this->connection->prepare($query);
|
2017-07-31 07:34:05 +02:00
|
|
|
}
|
|
|
|
|
2017-07-28 06:20:16 +02:00
|
|
|
/**
|
|
|
|
* @depends testPrepare
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareSameQuery(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$sql = "SELECT * FROM test WHERE domain=\$1";
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement1 */
|
|
|
|
$statement1 = yield $this->connection->prepare($sql);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement2 */
|
|
|
|
$statement2 = yield $this->connection->prepare($sql);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(Statement::class, $statement1);
|
|
|
|
$this->assertInstanceOf(Statement::class, $statement2);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
unset($statement1);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement2->execute([$data[0]]);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2017-07-28 06:20:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @depends testPrepareSameQuery
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testSimultaneousPrepareSameQuery(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$sql = "SELECT * FROM test WHERE domain=\$1";
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$statement1 = $this->connection->prepare($sql);
|
|
|
|
$statement2 = $this->connection->prepare($sql);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/**
|
|
|
|
* @var Statement $statement1
|
|
|
|
* @var Statement $statement2
|
|
|
|
*/
|
|
|
|
list($statement1, $statement2) = yield [$statement1, $statement2];
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(Statement::class, $statement1);
|
|
|
|
$this->assertInstanceOf(Statement::class, $statement2);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement1->execute([$data[0]]);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
unset($statement1);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement2->execute([$data[0]]);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2017-07-28 06:20:16 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2017-07-28 06:20:16 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareSimilarQueryReturnsDifferentStatements(): \Generator
|
2019-03-29 16:39:32 +01:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement1 */
|
|
|
|
$statement1 = $this->connection->prepare("SELECT * FROM test WHERE domain=\$1");
|
2019-03-29 16:39:32 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement2 */
|
|
|
|
$statement2 = $this->connection->prepare("SELECT * FROM test WHERE domain=:domain");
|
2019-03-29 16:39:32 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
list($statement1, $statement2) = yield [$statement1, $statement2];
|
2019-03-29 16:39:32 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(Statement::class, $statement1);
|
|
|
|
$this->assertInstanceOf(Statement::class, $statement2);
|
2019-03-29 16:39:32 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertNotSame($statement1, $statement2);
|
2019-04-03 16:12:04 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2019-04-03 16:12:04 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$results = [];
|
2019-04-03 16:12:04 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$results[] = yield Iterator\toArray(yield $statement1->execute([$data[0]]));
|
|
|
|
$results[] = yield Iterator\toArray(yield $statement2->execute(['domain' => $data[0]]));
|
|
|
|
|
|
|
|
foreach ($results as $result) {
|
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
foreach ($result as $row) {
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
2019-04-03 16:12:04 +02:00
|
|
|
}
|
2019-09-27 05:41:47 +02:00
|
|
|
}
|
2019-03-29 16:39:32 +01:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testPrepareThenExecuteWithUnconsumedTupleResult(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var Statement $statement */
|
|
|
|
$statement = yield $this->connection->prepare("SELECT * FROM test");
|
2018-03-30 06:11:28 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement->execute();
|
2018-03-30 06:11:28 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-03-30 06:11:28 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
unset($result); // Force destruction of result object.
|
2018-03-30 06:11:28 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $statement->execute();
|
2018-03-30 06:11:28 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-03-30 06:11:28 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData();
|
|
|
|
|
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
2018-03-30 06:11:28 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testExecute(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $this->connection->execute("SELECT * FROM test WHERE domain=\$1", [$data[0]]);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2017-11-06 06:06:17 +01:00
|
|
|
/**
|
|
|
|
* @depends testExecute
|
2018-01-24 06:00:22 +01:00
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testExecuteWithNamedParams(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
|
|
|
$result = yield $this->connection->execute(
|
|
|
|
"SELECT * FROM test WHERE domain=:domain",
|
|
|
|
['domain' => $data[0]]
|
|
|
|
);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertSame(2, $result->getFieldCount());
|
2018-01-24 06:00:22 +01:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[0], $row['domain']);
|
|
|
|
$this->assertSame($data[1], $row['tld']);
|
|
|
|
}
|
2018-01-24 06:00:22 +01:00
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @depends testExecute
|
2017-11-06 06:06:17 +01:00
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testExecuteWithInvalidParams(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->expectException(\Error::class);
|
|
|
|
$this->expectExceptionMessage("Value for unnamed parameter at position 0 missing");
|
|
|
|
|
|
|
|
return $this->connection->execute("SELECT * FROM test WHERE domain=\$1");
|
2017-11-06 06:06:17 +01:00
|
|
|
}
|
|
|
|
|
2018-01-24 06:00:22 +01:00
|
|
|
/**
|
|
|
|
* @depends testExecute
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testExecuteWithInvalidNamedParams(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->expectException(\Error::class);
|
|
|
|
$this->expectExceptionMessage("Value for named parameter 'domain' missing");
|
|
|
|
|
|
|
|
return $this->connection->execute("SELECT * FROM test WHERE domain=:domain", ['tld' => 'com']);
|
2018-01-24 06:00:22 +01:00
|
|
|
}
|
|
|
|
|
2016-09-14 16:27:39 +02:00
|
|
|
/**
|
2017-07-27 07:32:34 +02:00
|
|
|
* @depends testQueryWithTupleResult
|
2016-09-14 16:27:39 +02:00
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testSimultaneousQuery(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2017-07-27 07:32:34 +02:00
|
|
|
$callback = \Amp\coroutine(function ($value) {
|
2017-12-03 02:35:49 +01:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
2017-07-27 07:32:34 +02:00
|
|
|
$result = yield $this->connection->query("SELECT {$value} as value");
|
|
|
|
|
|
|
|
if ($value) {
|
|
|
|
yield new Delayed(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (yield $result->advance()) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertEquals($value, $row['value']);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
return Promise\all([$callback(0), $callback(1)]);
|
2017-07-27 07:32:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @depends testSimultaneousQuery
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testSimultaneousQueryWithOneFailing(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2017-07-27 07:32:34 +02:00
|
|
|
$callback = \Amp\coroutine(function ($query) {
|
2017-12-03 02:35:49 +01:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
2017-07-27 07:32:34 +02:00
|
|
|
$result = yield $this->connection->query($query);
|
|
|
|
|
|
|
|
$data = $this->getData();
|
2017-05-16 06:14:02 +02:00
|
|
|
|
2017-07-27 07:32:34 +02:00
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
});
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$result = null;
|
|
|
|
|
2017-07-27 07:32:34 +02:00
|
|
|
try {
|
2019-09-27 05:41:47 +02:00
|
|
|
$successful = $callback("SELECT * FROM test");
|
|
|
|
$failing = $callback("SELECT & FROM test");
|
2017-07-27 07:32:34 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$result = yield $successful;
|
|
|
|
yield $failing;
|
2017-07-27 07:32:34 +02:00
|
|
|
} catch (QueryError $exception) {
|
2017-12-03 02:35:49 +01:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2017-07-27 07:32:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->fail(\sprintf("Test did not throw an instance of %s", QueryError::class));
|
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testSimultaneousQueryAndPrepare(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2017-07-27 07:32:34 +02:00
|
|
|
$promises = [];
|
|
|
|
$promises[] = new Coroutine((function () {
|
2017-12-03 02:35:49 +01:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
2017-07-27 07:32:34 +02:00
|
|
|
$result = yield $this->connection->query("SELECT * FROM test");
|
|
|
|
|
|
|
|
$data = $this->getData();
|
|
|
|
|
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
|
|
|
})());
|
|
|
|
|
|
|
|
$promises[] = new Coroutine((function () {
|
2018-07-01 19:33:12 +02:00
|
|
|
/** @var Statement $statement */
|
2017-07-27 07:32:34 +02:00
|
|
|
$statement = (yield $this->connection->prepare("SELECT * FROM test"));
|
|
|
|
|
2017-12-03 02:35:49 +01:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
2017-07-27 07:32:34 +02:00
|
|
|
$result = yield $statement->execute();
|
|
|
|
|
|
|
|
$data = $this->getData();
|
|
|
|
|
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
|
|
|
})());
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
return Promise\all($promises);
|
2017-07-27 07:32:34 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testSimultaneousPrepareAndExecute(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2017-07-27 07:32:34 +02:00
|
|
|
$promises[] = new Coroutine((function () {
|
2018-07-01 19:33:12 +02:00
|
|
|
/** @var Statement $statement */
|
2017-07-27 07:32:34 +02:00
|
|
|
$statement = yield $this->connection->prepare("SELECT * FROM test");
|
|
|
|
|
2017-12-03 02:35:49 +01:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
2017-07-27 07:32:34 +02:00
|
|
|
$result = yield $statement->execute();
|
|
|
|
|
|
|
|
$data = $this->getData();
|
|
|
|
|
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
|
|
|
}
|
|
|
|
})());
|
|
|
|
|
|
|
|
$promises[] = new Coroutine((function () {
|
2017-12-03 02:35:49 +01:00
|
|
|
/** @var \Amp\Postgres\ResultSet $result */
|
2017-07-27 07:32:34 +02:00
|
|
|
$result = yield $this->connection->execute("SELECT * FROM test");
|
|
|
|
|
|
|
|
$data = $this->getData();
|
|
|
|
|
|
|
|
for ($i = 0; yield $result->advance(); ++$i) {
|
|
|
|
$row = $result->getCurrent();
|
|
|
|
$this->assertSame($data[$i][0], $row['domain']);
|
|
|
|
$this->assertSame($data[$i][1], $row['tld']);
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
2017-07-27 07:32:34 +02:00
|
|
|
})());
|
2017-05-16 06:14:02 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
return Promise\all($promises);
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testTransaction(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$isolation = SqlTransaction::ISOLATION_COMMITTED;
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
/** @var \Amp\Postgres\Transaction $transaction */
|
|
|
|
$transaction = yield $this->connection->beginTransaction($isolation);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(Transaction::class, $transaction);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$data = $this->getData()[0];
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertTrue($transaction->isAlive());
|
|
|
|
$this->assertTrue($transaction->isActive());
|
|
|
|
$this->assertSame($isolation, $transaction->getIsolationLevel());
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
yield $transaction->createSavepoint('test');
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$statement = yield $transaction->prepare("SELECT * FROM test WHERE domain=:domain");
|
|
|
|
$result = yield $statement->execute(['domain' => $data[0]]);
|
2018-08-09 19:31:51 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2018-08-09 19:31:51 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
unset($result); // Force destruction of result object.
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$result = yield $transaction->execute("SELECT * FROM test WHERE domain=\$1 FOR UPDATE", [$data[0]]);
|
2018-08-09 19:31:51 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(ResultSet::class, $result);
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
unset($result); // Force destruction of result object.
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
yield $transaction->rollbackTo('test');
|
2016-09-14 16:27:39 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
yield $transaction->commit();
|
|
|
|
|
|
|
|
$this->assertFalse($transaction->isAlive());
|
|
|
|
$this->assertFalse($transaction->isActive());
|
|
|
|
|
|
|
|
try {
|
|
|
|
$result = yield $transaction->execute("SELECT * FROM test");
|
|
|
|
$this->fail('Query should fail after transaction commit');
|
|
|
|
} catch (TransactionError $exception) {
|
|
|
|
// Exception expected.
|
|
|
|
}
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|
2017-05-16 06:14:02 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testListen(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$channel = "test";
|
|
|
|
/** @var \Amp\Postgres\Listener $listener */
|
|
|
|
$listener = yield $this->connection->listen($channel);
|
2017-06-21 06:04:54 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->assertInstanceOf(Listener::class, $listener);
|
|
|
|
$this->assertSame($channel, $listener->getChannel());
|
|
|
|
|
|
|
|
Loop::delay(100, function () use ($channel) {
|
|
|
|
yield $this->connection->query(\sprintf("NOTIFY %s, '%s'", $channel, '0'));
|
|
|
|
yield $this->connection->query(\sprintf("NOTIFY %s, '%s'", $channel, '1'));
|
|
|
|
});
|
|
|
|
|
|
|
|
$count = 0;
|
|
|
|
Loop::delay(200, function () use ($listener) {
|
|
|
|
$listener->unlisten();
|
2017-06-13 07:34:20 +02:00
|
|
|
});
|
2019-09-27 05:41:47 +02:00
|
|
|
|
|
|
|
while (yield $listener->advance()) {
|
|
|
|
$this->assertSame($listener->getCurrent()->payload, (string) $count++);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->assertSame(2, $count);
|
2017-06-13 07:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @depends testListen
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testNotify(): \Generator
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$channel = "test";
|
|
|
|
/** @var \Amp\Postgres\Listener $listener */
|
|
|
|
$listener = yield $this->connection->listen($channel);
|
2017-06-21 06:04:54 +02:00
|
|
|
|
2019-09-27 05:41:47 +02:00
|
|
|
Loop::delay(100, function () use ($channel) {
|
|
|
|
yield $this->connection->notify($channel, '0');
|
|
|
|
yield $this->connection->notify($channel, '1');
|
2017-06-13 07:34:20 +02:00
|
|
|
});
|
2019-09-27 05:41:47 +02:00
|
|
|
|
|
|
|
$count = 0;
|
|
|
|
Loop::delay(200, function () use ($listener) {
|
|
|
|
$listener->unlisten();
|
|
|
|
});
|
|
|
|
|
|
|
|
while (yield $listener->advance()) {
|
|
|
|
$this->assertSame($listener->getCurrent()->payload, (string) $count++);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->assertSame(2, $count);
|
2017-06-13 07:34:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @depends testListen
|
|
|
|
*/
|
2019-09-27 05:41:47 +02:00
|
|
|
public function testListenOnSameChannel(): Promise
|
2018-07-01 19:33:12 +02:00
|
|
|
{
|
2019-09-27 05:41:47 +02:00
|
|
|
$this->expectException(QueryError::class);
|
|
|
|
$this->expectExceptionMessage('Already listening on channel');
|
|
|
|
|
|
|
|
$channel = "test";
|
|
|
|
return Promise\all([$this->connection->listen($channel), $this->connection->listen($channel)]);
|
2017-06-13 07:34:20 +02:00
|
|
|
}
|
2020-08-01 06:25:19 +02:00
|
|
|
|
|
|
|
public function testQueryAfterErroredQuery(): \Generator
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
$result = yield $this->connection->query("INSERT INTO test (domain, tld) VALUES ('github', 'com')");
|
|
|
|
} catch (QueryExecutionError $exception) {
|
|
|
|
// Expected exception due to duplicate key.
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var CommandResult $result */
|
|
|
|
$result = yield $this->connection->query("INSERT INTO test (domain, tld) VALUES ('gitlab', 'com')");
|
|
|
|
|
|
|
|
$this->assertSame(1, $result->getAffectedRowCount());
|
|
|
|
}
|
2016-09-14 16:27:39 +02:00
|
|
|
}
|