Skip to content

Commit 55a4995

Browse files
committed
Add index hints support for update and delete queries
1 parent a57d4ba commit 55a4995

File tree

3 files changed

+186
-10
lines changed

3 files changed

+186
-10
lines changed

src/Illuminate/Database/Query/Grammars/Grammar.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,8 @@ protected function compileUpdateColumns(Builder $query, array $values)
12911291
*/
12921292
protected function compileUpdateWithoutJoins(Builder $query, $table, $columns, $where)
12931293
{
1294+
$table = $this->compileTableWithIndex($query, $table);
1295+
12941296
return "update {$table} set {$columns} {$where}";
12951297
}
12961298

@@ -1307,6 +1309,8 @@ protected function compileUpdateWithJoins(Builder $query, $table, $columns, $whe
13071309
{
13081310
$joins = $this->compileJoins($query, $query->joins);
13091311

1312+
$table = $this->compileTableWithIndex($query, $table);
1313+
13101314
return "update {$table} {$joins} set {$columns} {$where}";
13111315
}
13121316

@@ -1373,6 +1377,8 @@ public function compileDelete(Builder $query)
13731377
*/
13741378
protected function compileDeleteWithoutJoins(Builder $query, $table, $where)
13751379
{
1380+
$table = $this->compileTableWithIndex($query, $table);
1381+
13761382
return "delete from {$table} {$where}";
13771383
}
13781384

@@ -1390,6 +1396,8 @@ protected function compileDeleteWithJoins(Builder $query, $table, $where)
13901396

13911397
$joins = $this->compileJoins($query, $query->joins);
13921398

1399+
$table = $this->compileTableWithIndex($query, $table);
1400+
13931401
return "delete {$alias} from {$table} {$joins} {$where}";
13941402
}
13951403

@@ -1574,4 +1582,22 @@ public function getBitwiseOperators()
15741582
{
15751583
return $this->bitwiseOperators;
15761584
}
1585+
1586+
/**
1587+
* Compile table name with index hint.
1588+
*
1589+
* @param \Illuminate\Database\Query\Builder $query
1590+
* @param string $table
1591+
* @return string
1592+
*/
1593+
protected function compileTableWithIndex(Builder $query, $table)
1594+
{
1595+
if (! isset($query->indexHint)) {
1596+
return $table;
1597+
}
1598+
1599+
$index = $this->compileIndexHint($query, $query->indexHint);
1600+
1601+
return $index !== '' ? $table.' '.$index : $table;
1602+
}
15771603
}

src/Illuminate/Database/Query/Grammars/MySqlGrammar.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,13 @@ public function prepareBindingsForUpdate(array $bindings, array $values)
462462
*/
463463
protected function compileDeleteWithoutJoins(Builder $query, $table, $where)
464464
{
465-
$sql = parent::compileDeleteWithoutJoins($query, $table, $where);
465+
if (isset($query->indexHint)) {
466+
$alias = last(explode(' as ', $table));
467+
$table = $this->compileTableWithIndex($query, $table);
468+
$sql = "delete {$alias} from {$table} {$where}";
469+
} else {
470+
$sql = parent::compileDeleteWithoutJoins($query, $table, $where);
471+
}
466472

467473
// When using MySQL, delete statements may contain order by statements and limits
468474
// so we will compile both of those here. Once we have finished compiling this

tests/Database/DatabaseQueryBuilderTest.php

Lines changed: 153 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6717,69 +6717,213 @@ public function testFromQuestionMarkOperatorOnPostgres()
67176717
$this->assertSame('select * from "users" where "roles" ??& ?', $builder->toSql());
67186718
}
67196719

6720-
public function testUseIndexMySql()
6720+
public function testUseIndexMySqlSelect()
67216721
{
67226722
$builder = $this->getMySqlBuilder();
67236723
$builder->select('foo')->from('users')->useIndex('test_index');
67246724
$this->assertSame('select `foo` from `users` use index (test_index)', $builder->toSql());
67256725
}
67266726

6727-
public function testForceIndexMySql()
6727+
public function testForceIndexMySqlSelect()
67286728
{
67296729
$builder = $this->getMySqlBuilder();
67306730
$builder->select('foo')->from('users')->forceIndex('test_index');
67316731
$this->assertSame('select `foo` from `users` force index (test_index)', $builder->toSql());
67326732
}
67336733

6734-
public function testIgnoreIndexMySql()
6734+
public function testIgnoreIndexMySqlSelect()
67356735
{
67366736
$builder = $this->getMySqlBuilder();
67376737
$builder->select('foo')->from('users')->ignoreIndex('test_index');
67386738
$this->assertSame('select `foo` from `users` ignore index (test_index)', $builder->toSql());
67396739
}
67406740

6741-
public function testUseIndexSqlite()
6741+
public function testUseIndexSqliteSelect()
67426742
{
67436743
$builder = $this->getSQLiteBuilder();
67446744
$builder->select('foo')->from('users')->useIndex('test_index');
67456745
$this->assertSame('select "foo" from "users"', $builder->toSql());
67466746
}
67476747

6748-
public function testForceIndexSqlite()
6748+
public function testForceIndexSqliteSelect()
67496749
{
67506750
$builder = $this->getSQLiteBuilder();
67516751
$builder->select('foo')->from('users')->forceIndex('test_index');
67526752
$this->assertSame('select "foo" from "users" indexed by test_index', $builder->toSql());
67536753
}
67546754

6755-
public function testIgnoreIndexSqlite()
6755+
public function testIgnoreIndexSqliteSelect()
67566756
{
67576757
$builder = $this->getSQLiteBuilder();
67586758
$builder->select('foo')->from('users')->ignoreIndex('test_index');
67596759
$this->assertSame('select "foo" from "users"', $builder->toSql());
67606760
}
67616761

6762-
public function testUseIndexSqlServer()
6762+
public function testUseIndexSqlServerSelect()
67636763
{
67646764
$builder = $this->getSqlServerBuilder();
67656765
$builder->select('foo')->from('users')->useIndex('test_index');
67666766
$this->assertSame('select [foo] from [users]', $builder->toSql());
67676767
}
67686768

6769-
public function testForceIndexSqlServer()
6769+
public function testForceIndexSqlServerSelect()
67706770
{
67716771
$builder = $this->getSqlServerBuilder();
67726772
$builder->select('foo')->from('users')->forceIndex('test_index');
67736773
$this->assertSame('select [foo] from [users] with (index(test_index))', $builder->toSql());
67746774
}
67756775

6776-
public function testIgnoreIndexSqlServer()
6776+
public function testIgnoreIndexSqlServerSelect()
67776777
{
67786778
$builder = $this->getSqlServerBuilder();
67796779
$builder->select('foo')->from('users')->ignoreIndex('test_index');
67806780
$this->assertSame('select [foo] from [users]', $builder->toSql());
67816781
}
67826782

6783+
public function testUseIndexMySqlUpdate()
6784+
{
6785+
$builder = $this->getMySqlBuilder();
6786+
$builder->getConnection()->shouldReceive('update')->once()->with('update `users` use index (test_index) set `email` = ?, `name` = ?', ['foo', 'bar'])->andReturn(1);
6787+
$result = $builder->from('users')->useIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6788+
$this->assertEquals(1, $result);
6789+
}
6790+
6791+
public function testForceIndexMySqlUpdate()
6792+
{
6793+
$builder = $this->getMySqlBuilder();
6794+
$builder->getConnection()->shouldReceive('update')->once()->with('update `users` force index (test_index) set `email` = ?, `name` = ?', ['foo', 'bar'])->andReturn(1);
6795+
$result = $builder->from('users')->forceIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6796+
$this->assertEquals(1, $result);
6797+
}
6798+
6799+
public function testIgnoreIndexMySqlUpdate()
6800+
{
6801+
$builder = $this->getMySqlBuilder();
6802+
$builder->getConnection()->shouldReceive('update')->once()->with('update `users` ignore index (test_index) set `email` = ?, `name` = ?', ['foo', 'bar'])->andReturn(1);
6803+
$result = $builder->from('users')->ignoreIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6804+
$this->assertEquals(1, $result);
6805+
}
6806+
6807+
public function testUseIndexSqliteUpdate()
6808+
{
6809+
$builder = $this->getSQLiteBuilder();
6810+
$builder->getConnection()->shouldReceive('update')->once()->with('update "users" set "email" = ?, "name" = ?', ['foo', 'bar'])->andReturn(1);
6811+
$result = $builder->from('users')->useIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6812+
$this->assertEquals(1, $result);
6813+
}
6814+
6815+
public function testForceIndexSqliteUpdate()
6816+
{
6817+
$builder = $this->getSQLiteBuilder();
6818+
$builder->getConnection()->shouldReceive('update')->once()->with('update "users" indexed by test_index set "email" = ?, "name" = ?', ['foo', 'bar'])->andReturn(1);
6819+
$result = $builder->from('users')->forceIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6820+
$this->assertEquals(1, $result);
6821+
}
6822+
6823+
public function testIgnoreIndexSqliteUpdate()
6824+
{
6825+
$builder = $this->getSQLiteBuilder();
6826+
$builder->getConnection()->shouldReceive('update')->once()->with('update "users" set "email" = ?, "name" = ?', ['foo', 'bar'])->andReturn(1);
6827+
$result = $builder->from('users')->ignoreIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6828+
$this->assertEquals(1, $result);
6829+
}
6830+
6831+
public function testUseIndexSqlServerUpdate()
6832+
{
6833+
$builder = $this->getSqlServerBuilder();
6834+
$builder->getConnection()->shouldReceive('update')->once()->with('update [users] set [email] = ?, [name] = ?', ['foo', 'bar'])->andReturn(1);
6835+
$result = $builder->from('users')->useIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6836+
$this->assertEquals(1, $result);
6837+
}
6838+
6839+
public function testForceIndexSqlServerUpdate()
6840+
{
6841+
$builder = $this->getSqlServerBuilder();
6842+
$builder->getConnection()->shouldReceive('update')->once()->with('update [users] with (index(test_index)) set [email] = ?, [name] = ?', ['foo', 'bar'])->andReturn(1);
6843+
$result = $builder->from('users')->forceIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6844+
$this->assertEquals(1, $result);
6845+
}
6846+
6847+
public function testIgnoreIndexSqlServerUpdate()
6848+
{
6849+
$builder = $this->getSqlServerBuilder();
6850+
$builder->getConnection()->shouldReceive('update')->once()->with('update [users] set [email] = ?, [name] = ?', ['foo', 'bar'])->andReturn(1);
6851+
$result = $builder->from('users')->ignoreIndex('test_index')->update(['email' => 'foo', 'name' => 'bar']);
6852+
$this->assertEquals(1, $result);
6853+
}
6854+
6855+
public function testUseIndexMySqlDelete()
6856+
{
6857+
$builder = $this->getMySqlBuilder();
6858+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete `users` from `users` use index (test_index) where `name` = ?', ['bar'])->andReturn(1);
6859+
$result = $builder->from('users')->useIndex('test_index')->where('name', 'bar')->delete();
6860+
$this->assertEquals(1, $result);
6861+
}
6862+
6863+
public function testForceIndexMySqlDelete()
6864+
{
6865+
$builder = $this->getMySqlBuilder();
6866+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete `users` from `users` force index (test_index) where `name` = ?', ['bar'])->andReturn(1);
6867+
$result = $builder->from('users')->forceIndex('test_index')->where('name', 'bar')->delete();
6868+
$this->assertEquals(1, $result);
6869+
}
6870+
6871+
public function testIgnoreIndexMySqlDelete()
6872+
{
6873+
$builder = $this->getMySqlBuilder();
6874+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete `users` from `users` ignore index (test_index) where `name` = ?', ['bar'])->andReturn(1);
6875+
$result = $builder->from('users')->ignoreIndex('test_index')->where('name', 'bar')->delete();
6876+
$this->assertEquals(1, $result);
6877+
}
6878+
6879+
public function testUseIndexSqliteDelete()
6880+
{
6881+
$builder = $this->getSQLiteBuilder();
6882+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete from "users" where "name" = ?', ['bar'])->andReturn(1);
6883+
$result = $builder->from('users')->useIndex('test_index')->where('name', 'bar')->delete();
6884+
$this->assertEquals(1, $result);
6885+
}
6886+
6887+
public function testForceIndexSqliteDelete()
6888+
{
6889+
$builder = $this->getSQLiteBuilder();
6890+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete from "users" indexed by test_index where "name" = ?', ['bar'])->andReturn(1);
6891+
$result = $builder->from('users')->forceIndex('test_index')->where('name', 'bar')->delete();
6892+
$this->assertEquals(1, $result);
6893+
}
6894+
6895+
public function testIgnoreIndexSqliteDelete()
6896+
{
6897+
$builder = $this->getSQLiteBuilder();
6898+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete from "users" where "name" = ?', ['bar'])->andReturn(1);
6899+
$result = $builder->from('users')->ignoreIndex('test_index')->where('name', 'bar')->delete();
6900+
$this->assertEquals(1, $result);
6901+
}
6902+
6903+
public function testUseIndexSqlServerDelete()
6904+
{
6905+
$builder = $this->getSqlServerBuilder();
6906+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete from [users] where [name] = ?', ['bar'])->andReturn(1);
6907+
$result = $builder->from('users')->useIndex('test_index')->where('name', 'bar')->delete();
6908+
$this->assertEquals(1, $result);
6909+
}
6910+
6911+
public function testForceIndexSqlServerDelete()
6912+
{
6913+
$builder = $this->getSqlServerBuilder();
6914+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete from [users] with (index(test_index)) where [name] = ?', ['bar'])->andReturn(1);
6915+
$result = $builder->from('users')->forceIndex('test_index')->where('name', 'bar')->delete();
6916+
$this->assertEquals(1, $result);
6917+
}
6918+
6919+
public function testIgnoreIndexSqlServerDelete()
6920+
{
6921+
$builder = $this->getSqlServerBuilder();
6922+
$builder->getConnection()->shouldReceive('delete')->once()->with('delete from [users] where [name] = ?', ['bar'])->andReturn(1);
6923+
$result = $builder->from('users')->ignoreIndex('test_index')->where('name', 'bar')->delete();
6924+
$this->assertEquals(1, $result);
6925+
}
6926+
67836927
public function testClone()
67846928
{
67856929
$builder = $this->getBuilder();

0 commit comments

Comments
 (0)