Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ jobs:
- operating-system: 'ubuntu-latest'
php-version: '8.5'

- operating-system: 'ubuntu-latest'
php-version: '8.4'
db-version: 'MariaDB'
job-description: 'with MariaDB'

- operating-system: 'ubuntu-latest'
php-version: '8.5'
db-version: 'MariaDB'
job-description: 'with MariaDB'

name: PHP ${{ matrix.php-version }} ${{ matrix.job-description }}

runs-on: ${{ matrix.operating-system }}
Expand All @@ -38,6 +48,17 @@ jobs:
- name: Setup MySQL
run: |
sudo systemctl start mysql
if: matrix.db-version != 'MariaDB'

- name: Setup MariaDB
run: |
sudo systemctl stop mysql
sudo apt-get update
sudo apt-get install -y mariadb-server
sudo systemctl start mariadb
sudo mariadb -e "ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('root'); FLUSH PRIVILEGES;"
mariadb --version
if: matrix.db-version == 'MariaDB'

- name: Set git to use LF
run: |
Expand Down Expand Up @@ -86,10 +107,10 @@ jobs:

- name: Run static analysis
run: vendor/bin/psalm.phar
if: matrix.psalm != 'skip'
if: matrix.db-version != 'MariaDB' && matrix.psalm != 'skip'

- name: Run style fixer
env:
PHP_CS_FIXER_IGNORE_ENV: 1
run: vendor/bin/php-cs-fixer --diff --dry-run -v fix
if: runner.os != 'Windows' && matrix.style-fix != 'none'
if: runner.os != 'Windows' && matrix.db-version != 'MariaDB' && matrix.style-fix != 'none'
58 changes: 58 additions & 0 deletions test/MariaDbUuidTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php declare(strict_types=1);

namespace Amp\Mysql\Test;

use Amp\Mysql\MysqlConnection;
use Amp\Mysql\SocketMysqlConnector;

/**
* Exercises the prepared-statement parameter encoding path against MariaDB's native UUID column type.
* Regresses if VarString is not chosen for string-family targets (see #142).
*/
class MariaDbUuidTest extends MysqlTestCase
{
private const FIXTURE_UUID = '550e8400-e29b-41d4-a716-446655440000';

private MysqlConnection $db;

protected function setUp(): void
{
parent::setUp();

$version = $this->getDbVersion();

// Native UUID column type landed in MariaDB 10.7.
if (\preg_match('/^(\d+)\.(\d+)/', $version, $matches) !== 1
|| \version_compare($matches[1] . '.' . $matches[2], '10.7', '<')
) {
self::markTestSkipped('Requires MariaDB >= 10.7 for native UUID column (got: ' . $version . ')');
}

$this->db = (new SocketMysqlConnector())->connect($this->getConfig());
$this->db->query('DROP TABLE IF EXISTS uuid_test');
$this->db->query('CREATE TABLE uuid_test (id UUID PRIMARY KEY, label VARCHAR(64))');
}

protected function tearDown(): void
{
$this->db->query('DROP TABLE IF EXISTS uuid_test');
$this->db->close();

parent::tearDown();
}

public function testPreparedInsertRoundTripsNativeUuid(): void
{
$statement = $this->db->prepare('INSERT INTO uuid_test (id, label) VALUES (?, ?)');
$statement->execute([self::FIXTURE_UUID, 'fixture']);

$rows = [];
foreach ($this->db->query('SELECT id, label FROM uuid_test') as $row) {
$rows[] = $row;
}

self::assertCount(1, $rows);
self::assertSame(self::FIXTURE_UUID, $rows[0]['id']);
self::assertSame('fixture', $rows[0]['label']);
}
}
8 changes: 8 additions & 0 deletions test/MysqlDataTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public function provideDataAndTypes(): array
*/
public function testDateType(int|float|string|null $expected, string $type): void
{
if ($type === 'YEAR' && $this->isMariaDb()) {
self::markTestSkipped('MariaDB does not support CAST(... AS YEAR); covered by storage-column tests.');
}

$result = $this->connection->execute("SELECT CAST(:expected AS $type) AS data", ['expected' => $expected]);

foreach ($result as $row) {
Expand Down Expand Up @@ -110,6 +114,10 @@ public function provideJsonData(): array
*/
public function testJson(mixed $json): void
{
if ($this->isMariaDb()) {
self::markTestSkipped('MariaDB has no native JSON type; JSON is aliased to LONGTEXT and CAST(... AS JSON) is unsupported.');
}

$result = $this->connection->execute("SELECT CAST(? AS JSON) AS data", [$json]);

foreach ($result as $row) {
Expand Down
40 changes: 22 additions & 18 deletions test/MysqlLinkTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,24 +201,28 @@ public function testPrepared(): void
new MysqlColumnDefinition(...\array_merge($base, ["name" => "c", "originalName" => "c", "type" => MysqlDataType::Datetime, "length" => 19, "flags" => 128])),
], $stmt->getColumnDefinitions());

$base = [
"name" => "?",
"catalog" => "def",
"schema" => "",
"table" => "",
"originalTable" => "",
"originalName" => "",
"charset" => 63,
"length" => 21,
"flags" => 0,
"decimals" => 0,
];

$this->assertEquals([
new MysqlColumnDefinition(...\array_merge($base, ["type" => MysqlDataType::LongLong, "flags" => 128])),
new MysqlColumnDefinition(...\array_merge($base, ["type" => MysqlDataType::Datetime, "length" => 104, "decimals" => 6, "charset" => MysqlConfig::BIN_CHARSET])),
new MysqlColumnDefinition(...\array_merge($base, ["type" => MysqlDataType::VarString, "length" => 65532, "decimals" => 31, "charset" => MysqlConfig::BIN_CHARSET])),
], $stmt->getParameterDefinitions());
if (!$this->isMariaDb()) {
// MariaDB returns MYSQL_TYPE_NULL for parameter placeholders rather than
// the resolved column types. See https://mariadb.com/kb/en/com_stmt_prepare/
$base = [
"name" => "?",
"catalog" => "def",
"schema" => "",
"table" => "",
"originalTable" => "",
"originalName" => "",
"charset" => 63,
"length" => 21,
"flags" => 0,
"decimals" => 0,
];

$this->assertEquals([
new MysqlColumnDefinition(...\array_merge($base, ["type" => MysqlDataType::LongLong, "flags" => 128])),
new MysqlColumnDefinition(...\array_merge($base, ["type" => MysqlDataType::Datetime, "length" => 104, "decimals" => 6, "charset" => MysqlConfig::BIN_CHARSET])),
new MysqlColumnDefinition(...\array_merge($base, ["type" => MysqlDataType::VarString, "length" => 65532, "decimals" => 31, "charset" => MysqlConfig::BIN_CHARSET])),
], $stmt->getParameterDefinitions());
}

$stmt->bind("data", 'd');
$result = $stmt->execute([0 => 5, 'date' => self::EPOCH]);
Expand Down
17 changes: 17 additions & 0 deletions test/MysqlTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
namespace Amp\Mysql\Test;

use Amp\Mysql\MysqlConfig;
use Amp\Mysql\SocketMysqlConnector;
use Amp\PHPUnit\AsyncTestCase;

abstract class MysqlTestCase extends AsyncTestCase
{
private static ?bool $isMariaDb = null;

protected function getConfig(bool $useCompression = false): MysqlConfig
{
$config = MysqlConfig::fromAuthority(DB_HOST, DB_USER, DB_PASS, 'test');
Expand All @@ -16,4 +19,18 @@ protected function getConfig(bool $useCompression = false): MysqlConfig

return $config;
}

protected function isMariaDb(): bool
{
return self::$isMariaDb ??= \str_contains($this->getDbVersion(), 'MariaDB');
}

protected function getDbVersion(): string
{
$db = (new SocketMysqlConnector())->connect($this->getConfig());
$version = $db->query('SELECT VERSION() AS v')->fetchRow()['v'] ?? '';
$db->close();

return $version;
}
}