Skip to content

Commit 11756e6

Browse files
committed
Add handling of index hints on join clauses too. Fixes #593 and #497.
1 parent b14fd66 commit 11756e6

File tree

2 files changed

+83
-5
lines changed

2 files changed

+83
-5
lines changed

src/Components/JoinKeyword.php

+22-5
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,29 @@ class JoinKeyword extends Component
7272
*/
7373
public $using;
7474

75+
/**
76+
* Index hints
77+
*
78+
* @var IndexHint[]
79+
*/
80+
public $indexHints = [];
81+
7582
/**
7683
* @see JoinKeyword::$JOINS
7784
*
78-
* @param string $type Join type
79-
* @param Expression $expr join expression
80-
* @param Condition[] $on join conditions
81-
* @param ArrayObj $using columns joined
85+
* @param string $type Join type
86+
* @param Expression $expr join expression
87+
* @param Condition[] $on join conditions
88+
* @param ArrayObj $using columns joined
89+
* @param IndexHint[] $indexHints index hints
8290
*/
83-
public function __construct($type = null, $expr = null, $on = null, $using = null)
91+
public function __construct($type = null, $expr = null, $on = null, $using = null, $indexHints = [])
8492
{
8593
$this->type = $type;
8694
$this->expr = $expr;
8795
$this->on = $on;
8896
$this->using = $using;
97+
$this->indexHints = $indexHints;
8998
}
9099

91100
/**
@@ -110,6 +119,7 @@ public static function parse(Parser $parser, TokensList $list, array $options =
110119
*
111120
* 1 -----------------------[ expr ]----------------------> 2
112121
*
122+
* 2 -------------------[ index_hints ]-------------------> 2
113123
* 2 ------------------------[ ON ]-----------------------> 3
114124
* 2 -----------------------[ USING ]---------------------> 4
115125
*
@@ -163,6 +173,12 @@ public static function parse(Parser $parser, TokensList $list, array $options =
163173
case 'USING':
164174
$state = 4;
165175
break;
176+
case 'USE':
177+
case 'IGNORE':
178+
case 'FORCE':
179+
// Adding index hint on the JOIN clause.
180+
$expr->indexHints = IndexHint::parse($parser, $list);
181+
break;
166182
default:
167183
if (empty(static::$JOINS[$token->keyword])) {
168184
/* Next clause is starting */
@@ -210,6 +226,7 @@ public static function build($component, array $options = [])
210226
$ret = [];
211227
foreach ($component as $c) {
212228
$ret[] = array_search($c->type, static::$JOINS) . ' ' . $c->expr
229+
. ($c->indexHints !== [] ? ' ' . IndexHint::build($c->indexHints) : '')
213230
. (! empty($c->on)
214231
? ' ON ' . Condition::build($c->on) : '')
215232
. (! empty($c->using)

tests/Builder/SelectStatementTest.php

+61
Original file line numberDiff line numberDiff line change
@@ -353,4 +353,65 @@ public function testBuilderSurroundedByParanthesisWithLimit(): void
353353
$stmt->build()
354354
);
355355
}
356+
357+
public function testBuilderSelectFromWithForceIndex(): void
358+
{
359+
$query = 'SELECT *'
360+
. ' FROM uno FORCE INDEX (id)';
361+
$parser = new Parser($query);
362+
$stmt = $parser->statements[0];
363+
364+
self::assertSame($query, $stmt->build());
365+
}
366+
367+
/**
368+
* Ensures issue #497 is fixed.
369+
*/
370+
public function testBuilderSelectFromJoinWithForceIndex(): void
371+
{
372+
$query = 'SELECT *'
373+
. ' FROM uno'
374+
. ' JOIN dos FORCE INDEX (two_id) ON dos.id = uno.id';
375+
$parser = new Parser($query);
376+
$stmt = $parser->statements[0];
377+
378+
self::assertSame($query, $stmt->build());
379+
}
380+
381+
/**
382+
* Ensures issue #593 is fixed.
383+
*/
384+
public function testBuilderSelectFromInnerJoinWithForceIndex(): void
385+
{
386+
$query = 'SELECT a.id, a.name, b.order_id, b.total'
387+
. ' FROM customers a'
388+
. ' INNER JOIN orders b FORCE INDEX (idx_customer_id)'
389+
. ' ON a.id = b.customer_id'
390+
. " WHERE a.status = 'active'";
391+
392+
$parser = new Parser($query);
393+
$stmt = $parser->statements[0];
394+
395+
$expectedQuery = 'SELECT a.id, a.name, b.order_id, b.total'
396+
. ' FROM customers AS `a`'
397+
. ' INNER JOIN orders AS `b` FORCE INDEX (idx_customer_id)'
398+
. ' ON a.id = b.customer_id'
399+
. " WHERE a.status = 'active'";
400+
401+
self::assertSame($expectedQuery, $stmt->build());
402+
}
403+
404+
public function testBuilderSelectAllFormsOfIndexHints(): void
405+
{
406+
$query = 'SELECT *'
407+
. ' FROM one USE INDEX (col1) IGNORE INDEX (col1, col2) FORCE INDEX (col1, col2, col3)'
408+
. ' INNER JOIN two USE INDEX (col3) IGNORE INDEX (col2, col3) FORCE INDEX (col1, col2, col3)'
409+
. ' ON one.col1 = two.col2'
410+
. ' WHERE 1 = 1';
411+
412+
$parser = new Parser($query);
413+
$stmt = $parser->statements[0];
414+
415+
self::assertSame($query, $stmt->build());
416+
}
356417
}

0 commit comments

Comments
 (0)