Skip to content

Commit e96a436

Browse files
authored
Merge pull request #2345 from flow-php/bug/bytea-converter
fix: postgresql bytea converter
2 parents 4779075 + 21a94f4 commit e96a436

8 files changed

Lines changed: 50 additions & 28 deletions

File tree

composer.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bridge/symfony/telemetry-bundle/tests/Flow/Bridge/Symfony/TelemetryBundle/Tests/Unit/Instrumentation/Doctrine/DBAL/TracingConnectionTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Flow\Bridge\Symfony\TelemetryBundle\Tests\Unit\Instrumentation\Doctrine\DBAL;
66

77
use Doctrine\DBAL\Driver\{Connection as ConnectionInterface, Result, Statement as DriverStatement};
8-
use Doctrine\DBAL\{ParameterType, VersionAwarePlatformDriver};
8+
use Doctrine\DBAL\ParameterType;
99
use Flow\Bridge\Symfony\TelemetryBundle\Instrumentation\Doctrine\DBAL\V4\TracingConnection;
1010
use Flow\Telemetry\Context\MemoryContextStorage;
1111
use Flow\Telemetry\Logger\LoggerProvider;
@@ -23,7 +23,7 @@ final class TracingConnectionTest extends TestCase
2323
{
2424
protected function setUp() : void
2525
{
26-
if (\interface_exists(VersionAwarePlatformDriver::class)) {
26+
if (\interface_exists('Doctrine\DBAL\VersionAwarePlatformDriver')) {
2727
self::markTestSkipped('Test requires Doctrine DBAL 4.x');
2828
}
2929
}

src/bridge/symfony/telemetry-bundle/tests/Flow/Bridge/Symfony/TelemetryBundle/Tests/Unit/Instrumentation/Doctrine/DBAL/TracingDriverTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Doctrine\DBAL\Driver\API\ExceptionConverter;
88
use Doctrine\DBAL\Driver\{Connection, Result, Statement};
9-
use Doctrine\DBAL\{Driver, ServerVersionProvider, VersionAwarePlatformDriver};
9+
use Doctrine\DBAL\{Driver, ServerVersionProvider};
1010
use Doctrine\DBAL\Platforms\{AbstractPlatform, DB2Platform, MariaDBPlatform, MySQL80Platform, OraclePlatform, PostgreSQLPlatform, SQLServerPlatform, SQLitePlatform};
1111
use Flow\Bridge\Symfony\TelemetryBundle\Instrumentation\Doctrine\DBAL\V4\TracingDriver;
1212
use Flow\Telemetry\Context\MemoryContextStorage;
@@ -25,7 +25,7 @@ final class TracingDriverTest extends TestCase
2525
{
2626
protected function setUp() : void
2727
{
28-
if (\interface_exists(VersionAwarePlatformDriver::class)) {
28+
if (\interface_exists('Doctrine\DBAL\VersionAwarePlatformDriver')) {
2929
self::markTestSkipped('Test requires Doctrine DBAL 4.x');
3030
}
3131
}

src/bridge/symfony/telemetry-bundle/tests/Flow/Bridge/Symfony/TelemetryBundle/Tests/Unit/Instrumentation/Doctrine/DBAL/V3/TracingConnectionTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace Flow\Bridge\Symfony\TelemetryBundle\Tests\Unit\Instrumentation\Doctrine\DBAL\V3;
66

77
use Doctrine\DBAL\Driver\{Connection as ConnectionInterface, Result, Statement as DriverStatement};
8-
use Doctrine\DBAL\{ParameterType, VersionAwarePlatformDriver};
8+
use Doctrine\DBAL\ParameterType;
99
use Flow\Bridge\Symfony\TelemetryBundle\Instrumentation\Doctrine\DBAL\V3\TracingConnection;
1010
use Flow\Telemetry\Context\MemoryContextStorage;
1111
use Flow\Telemetry\Logger\LoggerProvider;
@@ -23,7 +23,7 @@ final class TracingConnectionTest extends TestCase
2323
{
2424
protected function setUp() : void
2525
{
26-
if (!\interface_exists(VersionAwarePlatformDriver::class)) {
26+
if (!\interface_exists('Doctrine\DBAL\VersionAwarePlatformDriver')) {
2727
self::markTestSkipped('Test requires Doctrine DBAL 3.x');
2828
}
2929
}

src/bridge/symfony/telemetry-bundle/tests/Flow/Bridge/Symfony/TelemetryBundle/Tests/Unit/Instrumentation/Doctrine/DBAL/V3/TracingDriverTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66

77
use Doctrine\DBAL\Driver\API\ExceptionConverter;
88
use Doctrine\DBAL\Driver\{Connection, Result, Statement};
9-
use Doctrine\DBAL\{Driver, VersionAwarePlatformDriver};
10-
use Doctrine\DBAL\ParameterType;
9+
use Doctrine\DBAL\{Driver, ParameterType};
1110
use Doctrine\DBAL\Platforms\{AbstractPlatform, DB2Platform, MariaDBPlatform, MySQL80Platform, OraclePlatform, PostgreSQLPlatform, SQLServerPlatform, SqlitePlatform};
1211
use Doctrine\DBAL\Schema\AbstractSchemaManager;
1312
use Flow\Bridge\Symfony\TelemetryBundle\Instrumentation\Doctrine\DBAL\V3\TracingDriver;
@@ -27,7 +26,7 @@ final class TracingDriverTest extends TestCase
2726
{
2827
protected function setUp() : void
2928
{
30-
if (!\interface_exists(VersionAwarePlatformDriver::class)) {
29+
if (!\interface_exists('Doctrine\DBAL\VersionAwarePlatformDriver')) {
3130
self::markTestSkipped('Test requires Doctrine DBAL 3.x');
3231
}
3332
}

src/lib/postgresql/src/Flow/PostgreSql/Client/Types/Converter/ByteaConverter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public function toDatabase(mixed $value) : ?string
2121
}
2222

2323
if (\is_string($value)) {
24-
return $value;
24+
return '\x' . \bin2hex($value);
2525
}
2626

2727
throw ValueConversionException::cannotConvert($value, 'bytea');

src/lib/postgresql/tests/Flow/PostgreSql/Tests/Integration/Client/Types/Converter/ByteaConverterTest.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
namespace Flow\PostgreSql\Tests\Integration\Client\Types\Converter;
66

7-
use function Flow\PostgreSql\DSL\{cast, column_type_bytea, literal, param, select};
7+
use function Flow\PostgreSql\DSL\{cast, column_type_bytea, literal, param, select, typed};
8+
use Flow\PostgreSql\Client\Types\ValueType;
89
use Flow\PostgreSql\Tests\Integration\PostgreSqlTestCase;
910
use PHPUnit\Framework\Attributes\DataProvider;
1011

@@ -31,6 +32,17 @@ public static function provide_hex_bytea_values() : \Generator
3132
yield 'mixed case' => ['deadbeef', "\xde\xad\xbe\xef"];
3233
}
3334

35+
/**
36+
* @return \Generator<string, array{string}>
37+
*/
38+
public static function provide_typed_bytea_binary_values() : \Generator
39+
{
40+
yield 'leading null bytes' => ["\x00\x00\x00\x02\x11\x06value1"];
41+
yield 'embedded null bytes' => ["hello\x00world"];
42+
yield 'high bytes' => ["\x01\x02\x03\xff\xfe"];
43+
yield 'serialize output' => [\serialize(['greeting' => 'world', 'count' => 7])];
44+
}
45+
3446
public function test_binary_data_via_hex_literal() : void
3547
{
3648
$result = $this->pgsqlContext()->client()->fetchScalar(select(cast(literal('\\x00010203'), column_type_bytea())->as('val'))->toSql());
@@ -76,4 +88,15 @@ public function test_null_bytea() : void
7688

7789
self::assertNull($result);
7890
}
91+
92+
#[DataProvider('provide_typed_bytea_binary_values')]
93+
public function test_typed_bytea_round_trip_preserves_binary(string $input) : void
94+
{
95+
$result = $this->pgsqlContext()->client()->fetchScalar(
96+
select(cast(param(1), column_type_bytea())->as('val'))->toSql(),
97+
[typed($input, ValueType::BYTEA)],
98+
);
99+
100+
self::assertSame($input, $result);
101+
}
79102
}

src/lib/postgresql/tests/Flow/PostgreSql/Tests/Unit/Client/Types/Converter/ByteaConverterTest.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ public static function provide_invalid_values() : \Generator
2424

2525
public static function provide_valid_values() : \Generator
2626
{
27-
yield 'simple text' => ['simple text', 'simple text'];
28-
yield 'hello' => ['hello', 'hello'];
29-
yield 'empty string' => ['', ''];
30-
yield 'binary with null byte' => ["hello\x00world", "hello\x00world"];
31-
yield 'binary with special bytes' => ["\x01\x02\x03\xff\xfe", "\x01\x02\x03\xff\xfe"];
32-
yield 'unicode characters' => ['日本語テスト', '日本語テスト'];
33-
yield 'emoji' => ['Hello 🎉 World', 'Hello 🎉 World'];
34-
yield 'newlines and tabs' => ["line1\nline2\ttab", "line1\nline2\ttab"];
35-
yield 'backslash' => ['path\\to\\file', 'path\\to\\file'];
36-
yield 'single quote' => ["it's a test", "it's a test"];
37-
yield 'double quote' => ['say "hello"', 'say "hello"'];
27+
yield 'simple text' => ['simple text', '\x' . \bin2hex('simple text')];
28+
yield 'hello' => ['hello', '\x' . \bin2hex('hello')];
29+
yield 'empty string' => ['', '\x'];
30+
yield 'binary with null byte' => ["hello\x00world", '\x' . \bin2hex("hello\x00world")];
31+
yield 'binary with special bytes' => ["\x01\x02\x03\xff\xfe", '\x' . \bin2hex("\x01\x02\x03\xff\xfe")];
32+
yield 'unicode characters' => ['日本語テスト', '\x' . \bin2hex('日本語テスト')];
33+
yield 'emoji' => ['Hello 🎉 World', '\x' . \bin2hex('Hello 🎉 World')];
34+
yield 'newlines and tabs' => ["line1\nline2\ttab", '\x' . \bin2hex("line1\nline2\ttab")];
35+
yield 'backslash' => ['path\\to\\file', '\x' . \bin2hex('path\\to\\file')];
36+
yield 'single quote' => ["it's a test", '\x' . \bin2hex("it's a test")];
37+
yield 'double quote' => ['say "hello"', '\x' . \bin2hex('say "hello"')];
3838
}
3939

4040
#[DataProvider('provide_invalid_values')]

0 commit comments

Comments
 (0)