diff --git a/src/Query/Grammars/PostgresGrammar.php b/src/Query/Grammars/PostgresGrammar.php index e195616..79fe396 100644 --- a/src/Query/Grammars/PostgresGrammar.php +++ b/src/Query/Grammars/PostgresGrammar.php @@ -43,12 +43,20 @@ class PostgresGrammar extends Grammar */ public function compileUpdate(string $table, array $state, array $values): string { - $table = $this->wrapTable($table); - $set = implode(', ', array_map( - fn(string $col) => $this->wrapColumn($col) . ' = ?', - array_keys($values), - )); + $table = $this->wrapTable($table); + $setParts = []; + + foreach ($values as $col => $val) { + $wrapped = $this->wrapColumn((string) $col); + // RawExpression (e.g. increment/decrement) — embed directly, no placeholder. + if ($val instanceof \Foxdb\Query\RawExpression) { + $setParts[] = "{$wrapped} = {$val->value}"; + } else { + $setParts[] = "{$wrapped} = ?"; + } + } + $set = implode(', ', $setParts); $sql = "UPDATE {$table} SET {$set}"; $where = $this->compileWheres($state); diff --git a/tests/Unit/GrammarTest.php b/tests/Unit/GrammarTest.php index 5db00f1..f7a5548 100644 --- a/tests/Unit/GrammarTest.php +++ b/tests/Unit/GrammarTest.php @@ -325,6 +325,41 @@ public function test_pgsql_update_strips_limit_and_order(): void $this->assertStringNotContainsString('ORDER BY', $sql); } + /** + * Regression: PostgresGrammar::compileUpdate() was using array_map on + * array_keys() which always produced "col = ?" — even for RawExpression + * values (used by increment/decrement). This caused a binding count + * mismatch: PostgreSQL received a ? placeholder with no bound value. + */ + public function test_pgsql_update_embeds_raw_expression_without_placeholder(): void + { + $raw = new \Foxdb\Query\RawExpression('"score" + 10'); + $sql = $this->pgsql->compileUpdate( + 'users', + $this->state(['wheres' => [$this->where('id')]]), + ['score' => $raw], + ); + + // RawExpression must be embedded directly — no ? placeholder for it. + $this->assertSame( + 'UPDATE "users" SET "score" = "score" + 10 WHERE "id" = ?', + $this->norm($sql), + ); + } + + public function test_pgsql_update_mixes_raw_and_normal_values(): void + { + $raw = new \Foxdb\Query\RawExpression('"score" + 5'); + $sql = $this->pgsql->compileUpdate( + 'users', + $this->state(['wheres' => [$this->where('id')]]), + ['score' => $raw, 'name' => 'Ali'], + ); + + $this->assertStringContainsString('"score" = "score" + 5', $sql); + $this->assertStringContainsString('"name" = ?', $sql); + } + // ----------------------------------------------------------------------- // PostgreSQL — RETURNING // ----------------------------------------------------------------------- @@ -352,4 +387,4 @@ public function test_parameters_placeholder(): void $this->assertSame('?, ?, ?', $this->mysql->parameters(3)); $this->assertSame('?', $this->mysql->parameters(1)); } -} +} \ No newline at end of file