From abb989a9e90ffec9d99b3d50078aceebe172264e Mon Sep 17 00:00:00 2001 From: Ed Kim Date: Wed, 17 Jul 2019 14:28:56 -0700 Subject: [PATCH] Fix insert ignore to ignore the duplicate row --- src/Query/InsertQuery.php | 56 +++++++++++++++++++-------------------- tests/InsertQueryTest.php | 14 ++++++++++ 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/Query/InsertQuery.php b/src/Query/InsertQuery.php index 02602ef..a06db0a 100644 --- a/src/Query/InsertQuery.php +++ b/src/Query/InsertQuery.php @@ -45,34 +45,34 @@ public function execute(AsyncMysqlConnection $conn): int { // throw for nonexistent fields $row = DataIntegrity::coerceToSchema($row, $schema); - // check for unique key violations unless INSERT IGNORE was specified - if (!$this->ignoreDupes) { - - $unique_key_violation = DataIntegrity::checkUniqueConstraints($table, $row, $schema); - if ($unique_key_violation is nonnull) { - list($msg, $row_id) = $unique_key_violation; - // is this an "INSERT ... ON DUPLICATE KEY UPDATE?" - // if so, this is where we apply the updates - if (!C\is_empty($this->updateExpressions)) { - $existing_row = $table[$row_id]; - list($affected, $table) = $this->applySet( - $conn, - $database, - $table_name, - dict[$row_id => $existing_row], - $table, - $this->updateExpressions, - $schema, - $row, - ); - // MySQL always counts dupe inserts twice intentionally - $rows_affected += $affected * 2; - continue; - } else if (!QueryContext::$relaxUniqueConstraints) { - throw new SQLFakeUniqueKeyViolation($msg); - } else { - continue; - } + // check for unique key violations + $unique_key_violation = DataIntegrity::checkUniqueConstraints($table, $row, $schema); + if ($unique_key_violation is nonnull) { + list($msg, $row_id) = $unique_key_violation; + // is this an "INSERT ... ON DUPLICATE KEY UPDATE?" + // if so, this is where we apply the updates + if (!C\is_empty($this->updateExpressions)) { + $existing_row = $table[$row_id]; + list($affected, $table) = $this->applySet( + $conn, + $database, + $table_name, + dict[$row_id => $existing_row], + $table, + $this->updateExpressions, + $schema, + $row, + ); + // MySQL always counts dupe inserts twice intentionally + $rows_affected += $affected * 2; + continue; + } elseif ($this->ignoreDupes) { + // silently continue if INSERT IGNORE was specified + continue; + } elseif (!QueryContext::$relaxUniqueConstraints) { + throw new SQLFakeUniqueKeyViolation($msg); + } else { + continue; } } $table[] = $row; diff --git a/tests/InsertQueryTest.php b/tests/InsertQueryTest.php index fd76650..356b195 100644 --- a/tests/InsertQueryTest.php +++ b/tests/InsertQueryTest.php @@ -61,6 +61,13 @@ final class InsertQueryTest extends HackTest { expect(() ==> $conn->query("INSERT IGNORE INTO table1 (id, name) VALUES (1, 'test2')"))->notToThrow( SQLFakeUniqueKeyViolation::class, ); + $results = await $conn->query("SELECT * FROM table1"); + expect($results->rows())->toBeSame( + vec[dict[ + 'id' => 1, + 'name' => 'test', + ]], + ); } public async function testPKViolationWithinMultiInsert(): Awaitable { @@ -86,6 +93,13 @@ final class InsertQueryTest extends HackTest { expect(() ==> $conn->query("INSERT IGNORE INTO table1 (id, name) VALUES (2, 'test')"))->notToThrow( SQLFakeUniqueKeyViolation::class, ); + $results = await $conn->query("SELECT * FROM table1"); + expect($results->rows())->toBeSame( + vec[dict[ + 'id' => 1, + 'name' => 'test', + ]], + ); } public async function testPartialValuesList(): Awaitable {