Skip to content

Commit 4b672f8

Browse files
authored
fix(flow-php/postgresql): quote schema-qualified table per identifier part in BulkInsert (#2428)
1 parent 4139e8a commit 4b672f8

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

src/lib/postgresql/src/Flow/PostgreSql/QueryBuilder/Insert/BulkInsert.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Flow\PostgreSql\QueryBuilder\Insert;
66

77
use Flow\PostgreSql\QueryBuilder\Clause\ConflictTarget;
8+
use Flow\PostgreSql\QueryBuilder\QualifiedIdentifier;
89
use Flow\PostgreSql\QueryBuilder\Sql;
910
use InvalidArgumentException;
1011

@@ -96,7 +97,7 @@ public function toSql(): string
9697
$rows[] = '(' . implode(', ', $placeholders) . ')';
9798
}
9899

99-
$sql = sprintf('INSERT INTO "%s" (%s) VALUES %s', $this->table, $quotedColumns, implode(', ', $rows));
100+
$sql = sprintf('INSERT INTO %s (%s) VALUES %s', $this->quotedTable(), $quotedColumns, implode(', ', $rows));
100101

101102
if ($this->doNothing) {
102103
$sql .= ' ON CONFLICT';
@@ -125,6 +126,14 @@ public function toSql(): string
125126
return $sql;
126127
}
127128

129+
private function quotedTable(): string
130+
{
131+
return implode('.', array_map(
132+
static fn(string $part): string => '"' . $part . '"',
133+
QualifiedIdentifier::parse($this->table)->parts(),
134+
));
135+
}
136+
128137
private function formatConflictTarget(ConflictTarget $target): string
129138
{
130139
$constraint = $target->getConstraint();

src/lib/postgresql/tests/Flow/PostgreSql/Tests/Unit/QueryBuilder/Insert/BulkInsertTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ public function test_immutability_on_conflict_do_update(): void
4848
static::assertStringContainsString('DO UPDATE', $query2->toSql());
4949
}
5050

51+
public function test_insert_into_schema_qualified_table(): void
52+
{
53+
$query = BulkInsert::into('enriched.production', ['a', 'b'], 1);
54+
55+
static::assertSame('INSERT INTO "enriched"."production" ("a", "b") VALUES ($1, $2)', $query->toSql());
56+
}
57+
58+
public function test_insert_into_three_part_qualified_table(): void
59+
{
60+
$query = BulkInsert::into('db.enriched.production', ['a'], 1);
61+
62+
static::assertSame('INSERT INTO "db"."enriched"."production" ("a") VALUES ($1)', $query->toSql());
63+
}
64+
65+
public function test_insert_into_already_quoted_qualified_table(): void
66+
{
67+
$query = BulkInsert::into('enriched."my.table"', ['a'], 1);
68+
69+
static::assertSame('INSERT INTO "enriched"."my.table" ("a") VALUES ($1)', $query->toSql());
70+
}
71+
72+
public function test_schema_qualified_table_with_on_conflict_do_update(): void
73+
{
74+
$query = BulkInsert::into(
75+
'enriched.production',
76+
['email', 'name'],
77+
1,
78+
)->onConflictDoUpdate(ConflictTarget::columns(['email']));
79+
80+
static::assertSame(
81+
'INSERT INTO "enriched"."production" ("email", "name") VALUES ($1, $2) ON CONFLICT ("email") DO UPDATE SET "name" = EXCLUDED."name"',
82+
$query->toSql(),
83+
);
84+
}
85+
5186
public function test_insert_with_many_columns(): void
5287
{
5388
$query = BulkInsert::into('products', ['id', 'name', 'price', 'category', 'stock'], 2);

0 commit comments

Comments
 (0)