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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## 2.0.1 under development

- Enh #477: Improve performance of `ArrayParser::parse()` method (@Tigrov)
- Enh #477, #478: Improve performance of `ArrayParser::parse()` method (@Tigrov)
- Enh #478: Improve performance of `StructuredParser::parse()` method (@Tigrov)

## 2.0.0 December 05, 2025

Expand Down
4 changes: 2 additions & 2 deletions src/Data/ArrayParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use function preg_match;
use function strcspn;
use function stripcslashes;
use function stripslashes;
use function strlen;
use function substr;

Expand Down Expand Up @@ -71,7 +71,7 @@ private function parseQuotedString(string $value, int &$i): string
preg_match('/(?>[^"\\\\]+|\\\\.)*/', $value, $matches, 0, $i + 1);
$i += strlen($matches[0]) + 2;

return stripcslashes($matches[0]);
return stripslashes($matches[0]);
}

/**
Expand Down
28 changes: 12 additions & 16 deletions src/Data/StructuredParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

namespace Yiisoft\Db\Pgsql\Data;

use function in_array;
use function preg_match;
use function strcspn;
use function stripslashes;
use function strlen;
use function substr;

/**
* Structured type representation to PHP array parser for PostgreSQL Server.
Expand Down Expand Up @@ -58,29 +62,21 @@ private function parseComposite(string $value): array
*/
private function parseQuotedString(string $value, int &$i): string
{
for ($result = '', ++$i;; ++$i) {
if ($value[$i] === '\\') {
++$i;
} elseif ($value[$i] === '"') {
++$i;
return $result;
}
preg_match('/(?>[^"\\\\]+|\\\\.)*/', $value, $matches, 0, $i + 1);
$i += strlen($matches[0]) + 2;

$result .= $value[$i];
}
return stripslashes($matches[0]);
}

/**
* Parses unquoted string.
*/
private function parseUnquotedString(string $value, int &$i): string
{
for ($result = '';; ++$i) {
if (in_array($value[$i], [',', ')'], true)) {
return $result;
}
$length = strcspn($value, ',)', $i);
$result = substr($value, $i, $length);
$i += $length;

$result .= $value[$i];
}
return $result;
}
}
52 changes: 38 additions & 14 deletions tests/StructuredParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Db\Pgsql\Tests;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Yiisoft\Db\Pgsql\Data\StructuredParser;

Expand All @@ -12,21 +13,44 @@
*/
final class StructuredParserTest extends TestCase
{
public function testParser(): void
public static function parserProvider(): iterable
{
$parser = new StructuredParser();

$this->assertSame([null], $parser->parse('()'));
$this->assertSame([0 => null, 1 => null], $parser->parse('(,)'));
$this->assertSame([0 => '10.0', 1 => 'USD'], $parser->parse('(10.0,USD)'));
$this->assertSame([0 => '1', 1 => '-2', 2 => null, 3 => '42'], $parser->parse('(1,-2,,42)'));
$this->assertSame([0 => ''], $parser->parse('("")'));
$this->assertSame(
[0 => '[",","null",true,"false","f"]'],
$parser->parse('("[\",\",\"null\",true,\"false\",\"f\"]")'),
);

yield [[null], '()'];
yield [[''], '("")'];
yield [[null, null], '(,)'];
yield [
["a\nb"],
"(\"a\nb\")",
];
yield [
['10.0', 'USD'],
'(10.0,USD)',
];
yield [
['1', '-2', null, '42'],
'(1,-2,,42)',
];
yield [
[',', ')', '"', '\\', '"\\,)', 'NULL', 't', 'f'],
'(",",")","\\"","\\\\","\\"\\\\,)",NULL,t,f)',
];
yield [
['[",","null",true,"false","f"]'],
'("[\",\",\"null\",true,\"false\",\"f\"]")',
];
// Multibyte strings
yield [
['我', '👍🏻', 'multibyte строка我👍🏻', 'נטשופ צרכנות'],
'(我,👍🏻,"multibyte строка我👍🏻","נטשופ צרכנות")',
];
// Default values can have any expressions
$this->assertSame(null, $parser->parse("'(10.0,USD)::structured_type'"));
yield [null, "'(10.0,USD)::structured_type'"];
}

#[DataProvider('parserProvider')]
public function testParser(?array $expected, string $value): void
{
$parser = new StructuredParser();
$this->assertSame($expected, $parser->parse($value));
}
}
Loading