From 95c2939890f18031515b280dcbb0d764c80839b5 Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Mon, 8 Oct 2018 15:44:39 +0200 Subject: [PATCH] Use default INSERT INTO syntax for multiple records with SQLite (#25995) This bumps the version of SQLite dependency to 3.7.11, released March 2012. Using a default syntax for the INSERT INTO clause fixes an issue described in the bug #25262, but only when used with SQLite 3.8.8 (released January 2015) or newer. The DEFAULT VALUES case needs to be still handled though, just like in the PostgresGrammar. Closes #25262 --- .../Database/Query/Grammars/SQLiteGrammar.php | 39 ++----------------- tests/Database/DatabaseQueryBuilderTest.php | 8 ---- 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index 0d612aca17ee..8c0f22ad3705 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -159,46 +159,15 @@ protected function compileJsonLength($column, $operator, $value) } /** - * Compile an insert statement into SQL. - * - * @param \Illuminate\Database\Query\Builder $query - * @param array $values - * @return string + * {@inheritdoc} */ public function compileInsert(Builder $query, array $values) { - // Essentially we will force every insert to be treated as a batch insert which - // simply makes creating the SQL easier for us since we can utilize the same - // basic routine regardless of an amount of records given to us to insert. $table = $this->wrapTable($query->from); - if (! is_array(reset($values))) { - $values = [$values]; - } - - // If there is only one record being inserted, we will just use the usual query - // grammar insert builder because no special syntax is needed for the single - // row inserts in SQLite. However, if there are multiples, we'll continue. - if (count($values) === 1) { - return empty(reset($values)) - ? "insert into $table default values" - : parent::compileInsert($query, reset($values)); - } - - $names = $this->columnize(array_keys(reset($values))); - - $columns = []; - - // SQLite requires us to build the multi-row insert as a listing of select with - // unions joining them together. So we'll build out this list of columns and - // then join them all together with select unions to complete the queries. - foreach (array_keys(reset($values)) as $column) { - $columns[] = '? as '.$this->wrap($column); - } - - $columns = array_fill(0, count($values), implode(', ', $columns)); - - return "insert into $table ($names) select ".implode(' union all select ', $columns); + return empty($values) + ? "insert into {$table} DEFAULT VALUES" + : parent::compileInsert($query, $values); } /** diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 6bfa330a4ef2..c8e8bc16af96 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -1675,14 +1675,6 @@ public function testInsertMethod() $this->assertTrue($result); } - public function testSQLiteMultipleInserts() - { - $builder = $this->getSQLiteBuilder(); - $builder->getConnection()->shouldReceive('insert')->once()->with('insert into "users" ("email", "name") select ? as "email", ? as "name" union all select ? as "email", ? as "name"', ['foo', 'taylor', 'bar', 'dayle'])->andReturn(true); - $result = $builder->from('users')->insert([['email' => 'foo', 'name' => 'taylor'], ['email' => 'bar', 'name' => 'dayle']]); - $this->assertTrue($result); - } - public function testInsertGetIdMethod() { $builder = $this->getBuilder();