Skip to content

Commit 53bea8f

Browse files
authored
Merge pull request #14 from Javakky-pxv/feature/show-index
Supports SHOW INDEX syntax
2 parents 514e9b9 + b695b92 commit 53bea8f

File tree

7 files changed

+232
-10
lines changed

7 files changed

+232
-10
lines changed

src/FakePdoStatementTrait.php

+11
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ function ($row) {
243243

244244
break;
245245

246+
case Query\ShowIndexQuery::class:
247+
$this->result = self::processResult(
248+
$this->conn,
249+
Processor\ShowIndexProcessor::process(
250+
$this->conn,
251+
new Processor\Scope(array_merge($params ?? [], $this->boundValues)),
252+
$parsed_query
253+
)
254+
);
255+
break;
256+
246257
default:
247258
throw new \UnexpectedValueException('Unsupported operation type ' . $sql);
248259
}

src/Parser/SQLParser.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
namespace Vimeo\MysqlEngine\Parser;
33

44
use Vimeo\MysqlEngine\TokenType;
5-
use Vimeo\MysqlEngine\Query\{
6-
SelectQuery,
5+
use Vimeo\MysqlEngine\Query\{SelectQuery,
76
DeleteQuery,
7+
ShowIndexQuery,
88
TruncateQuery,
99
InsertQuery,
1010
UpdateQuery,
1111
DropTableQuery,
12-
ShowTablesQuery
13-
};
12+
ShowTablesQuery};
1413

1514
final class SQLParser
1615
{
@@ -142,10 +141,11 @@ final class SQLParser
142141
'TABLES' => true,
143142
];
144143

144+
/** @var array<SelectQuery|InsertQuery|UpdateQuery|TruncateQuery|DeleteQuery|DropTableQuery|ShowTablesQuery|ShowIndexQuery> */
145145
private static $cache = [];
146146

147147
/**
148-
* @return SelectQuery|InsertQuery|UpdateQuery|TruncateQuery|DeleteQuery|DropTableQuery|ShowTablesQuery
148+
* @return SelectQuery|InsertQuery|UpdateQuery|TruncateQuery|DeleteQuery|DropTableQuery|ShowTablesQuery|ShowIndexQuery
149149
*/
150150
public static function parse(string $sql)
151151
{
@@ -157,7 +157,7 @@ public static function parse(string $sql)
157157
}
158158

159159
/**
160-
* @return SelectQuery|InsertQuery|UpdateQuery|TruncateQuery|DeleteQuery|DropTableQuery|ShowTablesQuery
160+
* @return SelectQuery|InsertQuery|UpdateQuery|TruncateQuery|DeleteQuery|DropTableQuery|ShowTablesQuery|ShowIndexQuery
161161
*/
162162
private static function parseImpl(string $sql)
163163
{

src/Parser/ShowParser.php

+47-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?php
2+
23
namespace Vimeo\MysqlEngine\Parser;
34

5+
use Vimeo\MysqlEngine\Query\ShowIndexQuery;
46
use Vimeo\MysqlEngine\TokenType;
57
use Vimeo\MysqlEngine\Query\ShowTablesQuery;
68

@@ -33,18 +35,33 @@ public function __construct(array $tokens, string $sql)
3335
$this->sql = $sql;
3436
}
3537

36-
public function parse() : ShowTablesQuery
38+
/**
39+
* @return ShowTablesQuery|ShowIndexQuery
40+
* @throws ParserException
41+
*/
42+
public function parse()
3743
{
3844
if ($this->tokens[$this->pointer]->value !== 'SHOW') {
3945
throw new ParserException("Parser error: expected SHOW");
4046
}
4147

4248
$this->pointer++;
4349

44-
if ($this->tokens[$this->pointer]->value !== 'TABLES') {
45-
throw new ParserException("Parser error: expected SHOW TABLES");
50+
switch ($this->tokens[$this->pointer]->value) {
51+
case 'TABLES':
52+
return $this->parseShowTables();
53+
case 'INDEX':
54+
case 'INDEXES':
55+
case 'KEYS':
56+
return $this->parseShowIndex();
57+
default:
58+
throw new ParserException("Parser error: expected SHOW TABLES");
4659
}
4760

61+
}
62+
63+
private function parseShowTables(): ShowTablesQuery
64+
{
4865
$this->pointer++;
4966

5067
if ($this->tokens[$this->pointer]->value !== 'LIKE') {
@@ -61,4 +78,31 @@ public function parse() : ShowTablesQuery
6178

6279
return new ShowTablesQuery($token->value, $this->sql);
6380
}
81+
82+
private function parseShowIndex(): ShowIndexQuery
83+
{
84+
$this->pointer++;
85+
86+
if ($this->tokens[$this->pointer]->value !== 'FROM') {
87+
throw new ParserException("Parser error: expected SHOW INDEX FROM");
88+
}
89+
$this->pointer++;
90+
$token = $this->tokens[$this->pointer];
91+
if ($token->type !== TokenType::IDENTIFIER) {
92+
throw new ParserException("Expected table name after FROM");
93+
}
94+
95+
$query = new ShowIndexQuery($token->value, $this->sql);
96+
$this->pointer++;
97+
98+
if ($this->pointer < count($this->tokens)) {
99+
if ($this->tokens[$this->pointer]->value !== 'WHERE') {
100+
throw new ParserException("Parser error: expected SHOW INDEX FROM [TABLE_NAME] WHERE");
101+
}
102+
$expression_parser = new ExpressionParser($this->tokens, $this->pointer);
103+
list($this->pointer, $expression) = $expression_parser->buildWithPointer();
104+
$query->whereClause = $expression;
105+
}
106+
return $query;
107+
}
64108
}

src/Processor/ShowIndexProcessor.php

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
4+
namespace Vimeo\MysqlEngine\Processor;
5+
6+
7+
use Vimeo\MysqlEngine\FakePdoInterface;
8+
use Vimeo\MysqlEngine\Query\ShowIndexQuery;
9+
use Vimeo\MysqlEngine\Schema\Column;
10+
use function PHPUnit\Framework\assertIsArray;
11+
12+
class ShowIndexProcessor extends Processor
13+
{
14+
public static function process(
15+
FakePdoInterface $conn,
16+
Scope $scope,
17+
ShowIndexQuery $stmt
18+
): QueryResult {
19+
[$database, $table] = Processor::parseTableName($conn, $stmt->table);
20+
$table_definition = $conn->getServer()->getTableDefinition(
21+
$database,
22+
$table
23+
);
24+
if (!$table_definition) {
25+
return new QueryResult([], []);
26+
}
27+
$columns = [
28+
'Table' => new Column\Varchar(255),
29+
'Non_unique' => new Column\TinyInt(true, 1),
30+
'Key_name' => new Column\Varchar(255),
31+
'Seq_in_index' => new Column\IntColumn(true, 4),
32+
'Column_name' => new Column\Varchar(255),
33+
'Collation' => new Column\Char(1),
34+
'Cardinality' => new Column\IntColumn(true, 4),
35+
'Sub_part' => new Column\IntColumn(true, 4),
36+
'Packed' => new Column\TinyInt(true, 1),
37+
'Null' => new Column\Varchar(3),
38+
'Index_type' => new Column\Varchar(5),
39+
'Comment' => new Column\Varchar(255),
40+
'Index_comment' => new Column\Varchar(255)
41+
];
42+
$rows = [];
43+
foreach ($table_definition->indexes as $name => $index) {
44+
foreach ($index->columns as $i => $column) {
45+
$rows[] = [
46+
'Table' => $table_definition->name,
47+
'Non_unique' => $index->type === 'INDEX' ? 1 : 0,
48+
'Key_name' => $name,
49+
'Seq_in_index' => 1 + (int) $i,
50+
'Column_name' => $column,
51+
// because Index does not have "direction" (in the $cols of CreateIndex)
52+
'Collation' => null,
53+
/*
54+
* https://dev.mysql.com/doc/refman/8.0/en/analyze-table.html
55+
* because ANALYZE TABLE is not implemented
56+
*/
57+
'Cardinality' => null,
58+
// because Index does not have "length" (in the $cols of CreateIndex)
59+
'Sub_part' => null,
60+
// because PACK_KEYS is not implemented
61+
'Packed' => null,
62+
'Null' => $table_definition->columns[$column]->isNullable ? 'YES' : '',
63+
// because Index does not have $mode (in the CreateIndex)
64+
'Index_type' => null,
65+
// because DISABLE KEYS is not implemented
66+
'Comment' => '',
67+
// because INDEX COMMENT is skipped in CREATE TABLE
68+
'Index_comment' => ''
69+
];
70+
}
71+
}
72+
$result = self::applyWhere($conn, $scope, $stmt->whereClause, new QueryResult($rows, $columns));
73+
return new QueryResult(array_merge($result->rows), $result->columns);
74+
}
75+
}

src/Query/ShowIndexQuery.php

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
namespace Vimeo\MysqlEngine\Query;
3+
4+
use Vimeo\MysqlEngine\Query\Expression\Expression;
5+
6+
final class ShowIndexQuery
7+
{
8+
/**
9+
* @var ?Expression
10+
*/
11+
public $whereClause = null;
12+
13+
/**
14+
* @var string
15+
*/
16+
public $table;
17+
18+
/**
19+
* @var string
20+
*/
21+
public $sql;
22+
23+
public function __construct(string $table, string $sql)
24+
{
25+
$this->table = $table;
26+
$this->sql = $sql;
27+
}
28+
}

src/Schema/Index.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ class Index
99
public $type;
1010

1111
/**
12-
* @var array
12+
* @var array<string>
1313
*/
1414
public $columns;
1515

1616
/**
1717
* @param 'INDEX'|'UNIQUE'|'PRIMARY'|'FULLTEXT'|'SPATIAL' $type
18+
* @param array<string> $columns
1819
*/
1920
public function __construct(
2021
string $type,

tests/ShowIndexParseTest.php

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace Vimeo\MysqlEngine\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
use Vimeo\MysqlEngine\Parser\SQLParser;
7+
use Vimeo\MysqlEngine\Query\SelectQuery;
8+
use Vimeo\MysqlEngine\Query\ShowIndexQuery;
9+
10+
class ShowIndexParseTest extends TestCase
11+
{
12+
public function testSimpleParse()
13+
{
14+
$query = 'SHOW INDEX FROM `foo`';
15+
16+
$show_query = SQLParser::parse($query);
17+
18+
$this->assertInstanceOf(ShowIndexQuery::class, $show_query);
19+
$this->assertSame('foo', $show_query->table);
20+
}
21+
22+
public function testIndexesParse()
23+
{
24+
$query = 'SHOW INDEXES FROM `foo`';
25+
26+
$show_query = SQLParser::parse($query);
27+
28+
$this->assertInstanceOf(ShowIndexQuery::class, $show_query);
29+
$this->assertSame('foo', $show_query->table);
30+
}
31+
32+
public function testKeysParse()
33+
{
34+
$query = 'SHOW KEYS FROM `foo`';
35+
36+
$show_query = SQLParser::parse($query);
37+
38+
$this->assertInstanceOf(ShowIndexQuery::class, $show_query);
39+
$this->assertSame('foo', $show_query->table);
40+
}
41+
42+
public function testParseInvalid()
43+
{
44+
$query = 'SHOW INDEX FROM `foo';
45+
46+
$this->expectException(\Vimeo\MysqlEngine\Parser\LexerException::class);
47+
48+
$select_query = \Vimeo\MysqlEngine\Parser\SQLParser::parse($query);
49+
50+
$this->assertInstanceOf(SelectQuery::class, $select_query);
51+
}
52+
53+
public function testWhereParse()
54+
{
55+
$query = "SHOW INDEX FROM `foo` WHERE `Key_name` = 'PRIMARY'";
56+
57+
$show_query = SQLParser::parse($query);
58+
59+
$this->assertInstanceOf(ShowIndexQuery::class, $show_query);
60+
$this->assertSame('foo', $show_query->table);
61+
}
62+
63+
}

0 commit comments

Comments
 (0)