Skip to content

Commit 71f12fd

Browse files
committed
Restore SqlFragment fluent chain, inline concatenation was slower
The array+implode approach in SqlFragment calculates total length and does one allocation. Repeated string .= copies the growing string each iteration — measurably slower on the complex select benchmark (19μs → 28μs regression). Restore the fluent chain while keeping the Quantifier simplification and Table::prepare direct field access. Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
1 parent d7ba187 commit 71f12fd

File tree

4 files changed

+63
-57
lines changed

4 files changed

+63
-57
lines changed

src/Sql/Delete.php

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PhpDb\Adapter\Driver\DriverInterface;
99
use PhpDb\Adapter\ParameterContainer;
1010
use PhpDb\Adapter\Platform\PlatformInterface;
11+
use PhpDb\Sql\Part\SqlFragment;
1112
use PhpDb\Sql\Part\SqlProcessor;
1213
use PhpDb\Sql\Part\From;
1314
use PhpDb\Sql\Part\Where as WherePart;
@@ -89,15 +90,9 @@ public function buildSqlString(
8990
$processor->setParamPrefix($this->processInfo['paramPrefix']);
9091
$sqlPlatform?->getTypeDecorator($this)?->prepare($this, $processor);
9192

92-
$sql = $this->getStatementKeyword();
93-
if (($part = $this->table->toSql($processor)) !== null) {
94-
$sql .= ' ' . $part;
95-
}
96-
if (($part = $this->where?->toSql($processor)) !== null) {
97-
$sql .= ' ' . $part;
98-
}
99-
100-
return $sql;
93+
return (string) SqlFragment::of($this->getStatementKeyword())
94+
->part($this->table->toSql($processor))
95+
->part($this->where?->toSql($processor));
10196
}
10297

10398
/**

src/Sql/Part/SqlFragment.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDb\Sql\Part;
6+
7+
use function implode;
8+
9+
final class SqlFragment
10+
{
11+
private array $parts = [];
12+
13+
public static function of(string $keyword): self
14+
{
15+
$f = new self();
16+
$f->parts[] = $keyword;
17+
return $f;
18+
}
19+
20+
public function part(?string $part): self
21+
{
22+
if ($part !== null) {
23+
$this->parts[] = $part;
24+
}
25+
return $this;
26+
}
27+
28+
public function wrap(?string $suffix): self
29+
{
30+
if ($suffix !== null) {
31+
$this->parts = ['( ' . implode(' ', $this->parts) . ' )', $suffix];
32+
}
33+
return $this;
34+
}
35+
36+
public function __toString(): string
37+
{
38+
return implode(' ', $this->parts);
39+
}
40+
}

src/Sql/Select.php

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PhpDb\Sql\Part\Offset;
1616
use PhpDb\Sql\Part\OrderBy;
1717
use PhpDb\Sql\Part\Quantifier;
18+
use PhpDb\Sql\Part\SqlFragment;
1819
use PhpDb\Sql\Part\SqlProcessor;
1920
use PhpDb\Sql\Part\Table;
2021
use PhpDb\Sql\Part\Where as WherePart;
@@ -386,41 +387,18 @@ public function buildSqlString(
386387
$sqlPlatform?->getTypeDecorator($this)?->prepare($this, $processor);
387388
$this->table->prepare($processor);
388389

389-
$sql = 'SELECT';
390-
391-
if (($part = $this->quantifier?->toSql($processor)) !== null) {
392-
$sql .= ' ' . $part;
393-
}
394-
$sql .= ' ' . $this->table->columns()->toSql($processor);
395-
if (($part = $this->table->from()->toSql($processor)) !== null) {
396-
$sql .= ' ' . $part;
397-
}
398-
if (($part = $this->table->joins()?->toSql($processor)) !== null) {
399-
$sql .= ' ' . $part;
400-
}
401-
if (($part = $this->where?->toSql($processor)) !== null) {
402-
$sql .= ' ' . $part;
403-
}
404-
if (($part = $this->groupBy?->toSql($processor)) !== null) {
405-
$sql .= ' ' . $part;
406-
}
407-
if (($part = $this->having?->toSql($processor)) !== null) {
408-
$sql .= ' ' . $part;
409-
}
410-
if (($part = $this->orderBy?->toSql($processor)) !== null) {
411-
$sql .= ' ' . $part;
412-
}
413-
if (($part = $this->limit?->toSql($processor)) !== null) {
414-
$sql .= ' ' . $part;
415-
}
416-
if (($part = $this->offset?->toSql($processor)) !== null) {
417-
$sql .= ' ' . $part;
418-
}
419-
if (($part = $this->combine?->toSql($processor)) !== null) {
420-
$sql = '( ' . $sql . ' ) ' . $part;
421-
}
422-
423-
return $sql;
390+
return (string) SqlFragment::of('SELECT')
391+
->part($this->quantifier?->toSql($processor))
392+
->part($this->table->columns()->toSql($processor))
393+
->part($this->table->from()->toSql($processor))
394+
->part($this->table->joins()?->toSql($processor))
395+
->part($this->where?->toSql($processor))
396+
->part($this->groupBy?->toSql($processor))
397+
->part($this->having?->toSql($processor))
398+
->part($this->orderBy?->toSql($processor))
399+
->part($this->limit?->toSql($processor))
400+
->part($this->offset?->toSql($processor))
401+
->wrap($this->combine?->toSql($processor));
424402
}
425403

426404
/**

src/Sql/Update.php

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PhpDb\Adapter\Platform\PlatformInterface;
1111
use PhpDb\Sql\Part\Joins as JoinsPart;
1212
use PhpDb\Sql\Part\Set as SetPart;
13+
use PhpDb\Sql\Part\SqlFragment;
1314
use PhpDb\Sql\Part\SqlProcessor;
1415
use PhpDb\Sql\Part\From;
1516
use PhpDb\Sql\Part\Where as WherePart;
@@ -135,19 +136,11 @@ public function buildSqlString(
135136
$processor->setParamPrefix($this->processInfo['paramPrefix']);
136137
$sqlPlatform?->getTypeDecorator($this)?->prepare($this, $processor);
137138

138-
$sql = $this->getStatementKeyword();
139-
$sql .= ' ' . $this->table->renderTable($processor);
140-
if (($part = $this->joins?->toSql($processor)) !== null) {
141-
$sql .= ' ' . $part;
142-
}
143-
if (($part = $this->set->toSql($processor)) !== null) {
144-
$sql .= ' ' . $part;
145-
}
146-
if (($part = $this->where?->toSql($processor)) !== null) {
147-
$sql .= ' ' . $part;
148-
}
149-
150-
return $sql;
139+
return (string) SqlFragment::of($this->getStatementKeyword())
140+
->part($this->table->renderTable($processor))
141+
->part($this->joins?->toSql($processor))
142+
->part($this->set->toSql($processor))
143+
->part($this->where?->toSql($processor));
151144
}
152145

153146
/**

0 commit comments

Comments
 (0)