diff --git a/src/Parser.php b/src/Parser.php index 759d58dcd..6168aff3a 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -43,6 +43,7 @@ class Parser extends Core 'BACKUP' => 'PhpMyAdmin\\SqlParser\\Statements\\BackupStatement', 'CHECK' => 'PhpMyAdmin\\SqlParser\\Statements\\CheckStatement', 'CHECKSUM' => 'PhpMyAdmin\\SqlParser\\Statements\\ChecksumStatement', + 'KILL' => 'PhpMyAdmin\\SqlParser\\Statements\\KillStatement', 'OPTIMIZE' => 'PhpMyAdmin\\SqlParser\\Statements\\OptimizeStatement', 'REPAIR' => 'PhpMyAdmin\\SqlParser\\Statements\\RepairStatement', 'RESTORE' => 'PhpMyAdmin\\SqlParser\\Statements\\RestoreStatement', @@ -210,6 +211,10 @@ class Parser extends Core 'class' => 'PhpMyAdmin\\SqlParser\\Components\\JoinKeyword', 'field' => 'join', ], + 'KILL' => [ + 'class' => 'PhpMyAdmin\\SqlParser\\Components\\Expression', + 'field' => 'processListId', + ], 'LEFT JOIN' => [ 'class' => 'PhpMyAdmin\\SqlParser\\Components\\JoinKeyword', 'field' => 'join', diff --git a/src/Statements/KillStatement.php b/src/Statements/KillStatement.php new file mode 100644 index 000000000..7040a0f3f --- /dev/null +++ b/src/Statements/KillStatement.php @@ -0,0 +1,43 @@ +> + * @psalm-var array 1, + 'QUERY' => 1, + ]; + + /** @var Expression|null */ + public $processListId = null; + + public function build(): string + { + $option = $this->options === null || $this->options->isEmpty() + ? '' + : ' ' . OptionsArray::build($this->options); + $expression = $this->processListId === null ? '' : ' ' . Expression::build($this->processListId); + + return trim('KILL' . $option . $expression); + } +} diff --git a/src/Utils/Query.php b/src/Utils/Query.php index f5b5320b7..283220e4d 100644 --- a/src/Utils/Query.php +++ b/src/Utils/Query.php @@ -18,6 +18,7 @@ use PhpMyAdmin\SqlParser\Statements\DropStatement; use PhpMyAdmin\SqlParser\Statements\ExplainStatement; use PhpMyAdmin\SqlParser\Statements\InsertStatement; +use PhpMyAdmin\SqlParser\Statements\KillStatement; use PhpMyAdmin\SqlParser\Statements\LoadStatement; use PhpMyAdmin\SqlParser\Statements\OptimizeStatement; use PhpMyAdmin\SqlParser\Statements\RenameStatement; @@ -65,7 +66,7 @@ * limit?: bool, * offset?: bool, * order?: bool, - * querytype: ('ALTER'|'ANALYZE'|'CALL'|'CHECK'|'CHECKSUM'|'CREATE'|'DELETE'|'DROP'|'EXPLAIN'|'INSERT'|'LOAD'|'OPTIMIZE'|'REPAIR'|'REPLACE'|'SELECT'|'SET'|'SHOW'|'UPDATE'|false), + * querytype: ('ALTER'|'ANALYZE'|'CALL'|'CHECK'|'CHECKSUM'|'CREATE'|'DELETE'|'DROP'|'EXPLAIN'|'INSERT'|'KILL'|'LOAD'|'OPTIMIZE'|'REPAIR'|'REPLACE'|'SELECT'|'SET'|'SHOW'|'UPDATE'|false), * reload?: bool, * select_from?: bool, * union?: bool @@ -431,6 +432,8 @@ public static function getFlags($statement, $all = false) $flags['is_affected'] = true; } elseif ($statement instanceof SetStatement) { $flags['querytype'] = 'SET'; + } elseif ($statement instanceof KillStatement) { + $flags['querytype'] = 'KILL'; } if ( diff --git a/tests/Parser/KillStatementTest.php b/tests/Parser/KillStatementTest.php new file mode 100644 index 000000000..99b81f758 --- /dev/null +++ b/tests/Parser/KillStatementTest.php @@ -0,0 +1,59 @@ +runParserTest($test); + } + + /** + * @return string[][] + */ + public function killProvider(): array + { + return [ + ['parser/parseKill'], + ['parser/parseKillConnection'], + ['parser/parseKillQuery'], + ]; + } + + /** + * @dataProvider buildKillProvider + */ + public function testBuildKill(string $sql): void + { + $parser = new Parser($sql); + $this->assertCount(1, $parser->statements); + $statement = $parser->statements[0]; + $this->assertInstanceOf(KillStatement::class, $statement); + $builtSql = $statement->build(); + $this->assertEquals($sql, $builtSql); + } + + /** + * @return array> + * @psalm-return list> + */ + public function buildKillProvider(): array + { + return [ + ['KILL (SELECT 3 + 4)'], + ['KILL QUERY 3'], + ['KILL CONNECTION 3'], + ['KILL'], + ]; + } +} diff --git a/tests/data/parser/parseKill.in b/tests/data/parser/parseKill.in new file mode 100644 index 000000000..a19d01f1a --- /dev/null +++ b/tests/data/parser/parseKill.in @@ -0,0 +1 @@ +KILL 1 \ No newline at end of file diff --git a/tests/data/parser/parseKill.out b/tests/data/parser/parseKill.out new file mode 100644 index 000000000..33e63ed8e --- /dev/null +++ b/tests/data/parser/parseKill.out @@ -0,0 +1,90 @@ +{ + "query": "KILL 1", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "KILL 1", + "len": 6, + "last": 6, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "KILL", + "value": "KILL", + "keyword": "KILL", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 4 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "1", + "value": 1, + "keyword": null, + "type": 6, + "flags": 0, + "position": 5 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 4, + "idx": 4 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\KillStatement", + "processListId": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": null, + "expr": "1", + "alias": null, + "function": null, + "subquery": null + }, + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "first": 0, + "last": 2 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file diff --git a/tests/data/parser/parseKillConnection.in b/tests/data/parser/parseKillConnection.in new file mode 100644 index 000000000..cbe01e0ff --- /dev/null +++ b/tests/data/parser/parseKillConnection.in @@ -0,0 +1 @@ +KILL CONNECTION 1 \ No newline at end of file diff --git a/tests/data/parser/parseKillConnection.out b/tests/data/parser/parseKillConnection.out new file mode 100644 index 000000000..8e45e1d1c --- /dev/null +++ b/tests/data/parser/parseKillConnection.out @@ -0,0 +1,110 @@ +{ + "query": "KILL CONNECTION 1", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "KILL CONNECTION 1", + "len": 17, + "last": 17, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "KILL", + "value": "KILL", + "keyword": "KILL", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 4 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "CONNECTION", + "value": "CONNECTION", + "keyword": "CONNECTION", + "type": 1, + "flags": 1, + "position": 5 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 15 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "1", + "value": 1, + "keyword": null, + "type": 6, + "flags": 0, + "position": 16 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 6, + "idx": 6 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\KillStatement", + "processListId": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": null, + "expr": "1", + "alias": null, + "function": null, + "subquery": null + }, + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "1": "CONNECTION" + } + }, + "first": 0, + "last": 4 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file diff --git a/tests/data/parser/parseKillQuery.in b/tests/data/parser/parseKillQuery.in new file mode 100644 index 000000000..1bab1d421 --- /dev/null +++ b/tests/data/parser/parseKillQuery.in @@ -0,0 +1 @@ +KILL QUERY 1 \ No newline at end of file diff --git a/tests/data/parser/parseKillQuery.out b/tests/data/parser/parseKillQuery.out new file mode 100644 index 000000000..2f95a3536 --- /dev/null +++ b/tests/data/parser/parseKillQuery.out @@ -0,0 +1,110 @@ +{ + "query": "KILL QUERY 1", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "KILL QUERY 1", + "len": 12, + "last": 12, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "KILL", + "value": "KILL", + "keyword": "KILL", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 4 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "QUERY", + "value": "QUERY", + "keyword": "QUERY", + "type": 1, + "flags": 1, + "position": 5 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 10 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "1", + "value": 1, + "keyword": null, + "type": 6, + "flags": 0, + "position": 11 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 6, + "idx": 6 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\KillStatement", + "processListId": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": null, + "expr": "1", + "alias": null, + "function": null, + "subquery": null + }, + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": { + "1": "QUERY" + } + }, + "first": 0, + "last": 4 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [] + } +} \ No newline at end of file