Skip to content

Commit 56bb6ea

Browse files
authored
fix(flow-php/postgresql): lower BulkInsert upsert with empty update set to ON CONFLICT DO NOTHING (#2452)
- prevents silent degradation to plain INSERT when all columns are conflict columns
1 parent ab928a3 commit 56bb6ea

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public function onConflictDoUpdate(ConflictTarget $target, ?array $updateColumns
7676
$assignments[$column] = 'EXCLUDED."' . $column . '"';
7777
}
7878

79+
if ($assignments === []) {
80+
return new self($this->table, $this->columns, $this->rowCount, $target, true, []);
81+
}
82+
7983
return new self($this->table, $this->columns, $this->rowCount, $target, false, $assignments);
8084
}
8185

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,51 @@ public function test_on_conflict_do_update_with_all_non_conflict_columns(): void
149149
);
150150
}
151151

152+
public function test_on_conflict_do_update_with_all_columns_as_conflict_target_emits_do_nothing(): void
153+
{
154+
$query = BulkInsert::into('t', ['a', 'b'], 1)->onConflictDoUpdate(ConflictTarget::columns(['a', 'b']));
155+
156+
static::assertSame(
157+
'INSERT INTO "t" ("a", "b") VALUES ($1, $2) ON CONFLICT ("a", "b") DO NOTHING',
158+
$query->toSql(),
159+
);
160+
}
161+
162+
public function test_on_conflict_do_update_with_constraint_and_empty_update_columns_emits_do_nothing(): void
163+
{
164+
$query = BulkInsert::into('t', ['a', 'b'], 1)->onConflictDoUpdate(ConflictTarget::constraint('t_pkey'), []);
165+
166+
static::assertSame(
167+
'INSERT INTO "t" ("a", "b") VALUES ($1, $2) ON CONFLICT ON CONSTRAINT "t_pkey" DO NOTHING',
168+
$query->toSql(),
169+
);
170+
}
171+
172+
public function test_on_conflict_do_update_with_empty_update_columns_emits_do_nothing(): void
173+
{
174+
$query = BulkInsert::into('users', ['email', 'name'], 1)->onConflictDoUpdate(
175+
ConflictTarget::columns(['email']),
176+
[],
177+
);
178+
179+
static::assertSame(
180+
'INSERT INTO "users" ("email", "name") VALUES ($1, $2) ON CONFLICT ("email") DO NOTHING',
181+
$query->toSql(),
182+
);
183+
}
184+
185+
public function test_on_conflict_do_update_with_subset_target_still_emits_do_update(): void
186+
{
187+
$query = BulkInsert::into('users', ['email', 'name'], 1)->onConflictDoUpdate(ConflictTarget::columns([
188+
'email',
189+
]));
190+
191+
static::assertSame(
192+
'INSERT INTO "users" ("email", "name") VALUES ($1, $2) ON CONFLICT ("email") DO UPDATE SET "name" = EXCLUDED."name"',
193+
$query->toSql(),
194+
);
195+
}
196+
152197
public function test_on_conflict_do_update_with_constraint(): void
153198
{
154199
$query = BulkInsert::into('users', ['email', 'name'], 1)->onConflictDoUpdate(

0 commit comments

Comments
 (0)