Skip to content

Commit 8a76dd6

Browse files
committed
feat: Skip FORCE INDEX for JOIN
1 parent eab6311 commit 8a76dd6

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

src/Parser/FromParser.php

+19
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,26 @@ private function buildJoin(string $left_table, Token $token)
295295
}
296296
}
297297

298+
/*
299+
* Unlike other clauses (e.g., FROM), the buildJoin advances the pointer to the specified keyword (e.g., FORCE).
300+
* Therefore, the pointer needs to be adjusted.
301+
* For instance, in "FROM a FORCE INDEX ...", processing for other clauses ends just before the identifier (a),
302+
* but for the JOIN clause, the pointer advances to "FORCE".
303+
* To address this issue, we adjusted the pointer before and after calling SQLParser::skipIndexHints(),
304+
* and modified the code to advance the pointer to the closing parenthesis ')' if necessary.
305+
*/
306+
$this->pointer--;
298307
$this->pointer = SQLParser::skipIndexHints($this->pointer, $this->tokens);
308+
$this->pointer++;
309+
if ($this->tokens[$this->pointer]->type === TokenType::SEPARATOR
310+
&& $this->tokens[$this->pointer]->value === ")") {
311+
$this->pointer++;
312+
}
313+
$next = $this->tokens[$this->pointer] ?? null;
314+
if ($next === null) {
315+
/** @psalm-suppress LessSpecificReturnStatement */
316+
return $table;
317+
}
299318

300319
if ($table['join_type'] === JoinType::NATURAL || $table['join_type'] === JoinType::CROSS) {
301320
return $table;

tests/EndToEndTest.php

+21
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,27 @@ public function testLeftJoinWithCount()
269269
);
270270
}
271271

272+
public function testLeftJoinSkipIndex()
273+
{
274+
$pdo = self::getConnectionToFullDB(false);
275+
276+
$query = $pdo->prepare(
277+
"SELECT `id`
278+
FROM `video_game_characters` FORCE INDEX (`PRIMARY`)
279+
LEFT JOIN `character_tags` FORCE INDEX (`PRIMARY`)
280+
ON `character_tags`.`character_id` = `video_game_characters`.`id`
281+
LIMIT 1"
282+
);
283+
$query->execute();
284+
285+
$this->assertSame(
286+
[
287+
['id' => 1]
288+
],
289+
$query->fetchAll(\PDO::FETCH_ASSOC)
290+
);
291+
}
292+
272293
public function testMaxValueAliasedToColumnName()
273294
{
274295
$pdo = self::getConnectionToFullDB(false);

0 commit comments

Comments
 (0)