phpMyAdmin的程式主要使用php和javascript開發,它的安裝使用都比較簡單而且已有很多相關介紹,今天來自騰訊雲資料庫團隊的高級開發工程師在此給大家介紹一下——源碼中的一個核心組件sql-parser ...
phpMyAdmin是一款基於Web端運行的開源資料庫管理工具,支持管理MySQL和MariaDB兩種資料庫。 phpMyAdmin的程式主要使用php和javascript開發,它的安裝使用都比較簡單而且已有很多相關介紹不再重覆,今天要介紹的是源碼中的一個核心組件sql-parser。
sql-parser簡介
sql-parser組件的主要用途是對SQL語句進行詞法分析、語法分析,繼而可以實現對SQL語句的解構、加工、替換、再組裝等需求,另外也可以對SQL進行highlight等處理。sql-parser由純PHP語言實現,同時也是整個phpMyAdmin源碼中為數不多的代碼架構比較清晰且符合當前PHP界PSR標準規範的模塊。
sql-parser組件安裝
需事先安裝好php,git客戶端,以及composer php包管理工具
margin@margin-MB1:~/tmp$ sudo git clone https://github.com/phpmyadmin/sql-parser.git
margin@margin-MB1:~/tmp$ cd sql-parser && sudo composer install
組件安裝完畢,下麵介紹具體的調用
解析普通語句
<?php
require_once '../sql-parser/vendor/autoload.php';
use SqlParser\Parser;
$query = 'SELECT * FROM t1 LEFT JOIN (t2, t3, t4) '
. 'ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)';
$parser = new Parser($query);
$stmt = $parser->statements[0];
echo json_encode($stmt);
運行結果中$parser
變數是一個大對象,裡面存儲有對$query
語句的詞法分析結果$query->list
,語法分析結果$query-statements
,以及錯誤信息等。 其中$query-statements
的結構如下:
{"expr":
[{"database":null,"table":null,"column":null,"expr":"*","alias":null,"function":n
ull,"subquery":null}],"from":
[{"database":null,"table":"t1","column":null,"expr":"t1","alias":null,"function":
null,"subquery":null}],"partition":null,"where":null,"group":null,"having":null,"
order":null,"limit":null,"procedure":null,"into":null,"join":
[{"type":"LEFT","expr":{"database":null,"table":null,"column":null,"expr":"(t2,
t3, t4)","alias":null,"function":null,"subquery":null},"on":[{"identifiers":
["t2","a","t1"],"isOperator":false,"expr":"(t2.a=t1.a"},{"identifiers":
[],"isOperator":true,"expr":"AND"},{"identifiers":
["t3","b","t1"],"isOperator":false,"expr":"t3.b=t1.b"},{"identifiers":
[],"isOperator":true,"expr":"AND"},{"identifiers":
["t4","c","t1"],"isOperator":false,"expr":"t4.c=t1.c)"}],"using":null}],"union":
[],"options":{"options":[]},"first":0,"last":50}
解析事務
require_once '../sql-parser/vendor/autoload.php';
use SqlParser\Parser;
$query = 'START TRANSACTION;' .
'SELECT @A:=SUM(salary) FROM table1 WHERE type=1;' .
'UPDATE table2 SET summary=@A WHERE type=1;' .
'COMMIT;';
$parser = new Parser($query);
$stmt = $parser->statements[0];
echo json_encode($stmt);
輸出結果:
{"type":1,"statements":[{"expr":
[{"database":null,"table":null,"column":null,"expr":"@A:=SUM(salary)","alias":nul
l,"function":"SUM","subquery":null}],"from":
[{"database":null,"table":"table1","column":null,"expr":"table1","alias":null,"fu
nction":null,"subquery":null}],"partition":null,"where":[{"identifiers":
["type"],"isOperator":false,"expr":"type=1"}],"group":null,"having":null,"order":
null,"limit":null,"procedure":null,"into":null,"join":null,"union":[],"options":
{"options":[]},"first":1,"last":19},{"tables":
[{"database":null,"table":"table2","column":null,"expr":"table2","alias":null,"fu
nction":null,"subquery":null}],"set":[{"column":"summary","value":"@A"}],"where":
[{"identifiers":
["type"],"isOperator":false,"expr":"type=1"}],"order":null,"limit":null,"options"
:{"options":[]},"first":20,"last":35}],"end":
{"type":2,"statements":null,"end":null,"options":{"options":
{"1":"COMMIT"}},"first":36,"last":37},"options":{"options":{"1":"START
TRANSACTION"}},"first":0,"last":0}
除以上兩種語句之外,sql-parser還支持解析存儲過程等幾乎所有MySQL語法,不再一一舉例。下麵是其SQL構造器的用法舉例。
組裝SQL語句
組裝select語句:
<?php
require_once '../sql-parser/vendor/autoload.php';
use SqlParser\Components\OptionsArray;
use SqlParser\Components\Expression;
use SqlParser\Components\Condition;
use SqlParser\Components\Limit;
use SqlParser\Statements\SelectStatement;
$stmt = new SelectStatement();
$stmt->options = new OptionsArray(array('DISTINCT'));
$stmt->expr[] = new Expression('sakila', 'film', 'film_id', 'fid');
$stmt->expr[] = new Expression('COUNT(film_id)');
$stmt->from[] = new Expression('', 'film', '');
$stmt->from[] = new Expression('', 'actor', '');
$stmt->where[] = new Condition('film_id > 10');
$stmt->where[] = new Condition('OR');
$stmt->where[] = new Condition('actor.age > 25');
$stmt->limit = new Limit(1, 10);
var_dump($stmt->build());
輸出結果:
margin@margin-MB1:~/code/parserTest$ php build.php
string(137) "SELECT DISTINCT `sakila`.`film`.`film_id` AS `fid`, COUNT(film_id)
FROM `film`, `actor` WHERE film_id > 10 OR actor.age > 25 LIMIT 10, 1 "
組裝觸發器語句:
<?php
require_once '../sql-parser/vendor/autoload.php';
use SqlParser\Components\Expression;
use SqlParser\Components\OptionsArray;
use SqlParser\Statements\CreateStatement;
$stmt = new CreateStatement();
$stmt->options = new OptionsArray(array('TRIGGER'));
$stmt->name = new Expression('ins_sum');
$stmt->entityOptions = new OptionsArray(array('BEFORE', 'INSERT'));
$stmt->table = new Expression('account');
$stmt->body = 'SET @sum = @sum + NEW.amount';
var_dump($stmt->build());
輸出結果:
margin@margin-MB1:~/code/parserTest$ php build.php
string(89) "CREATE TRIGGER ins_sum BEFORE INSERT ON account FOR EACH ROW SET @sum
= @sum + NEW.amount"
SQL再加工
多條語句一起加工處理:
<?php
require_once '../sql-parser/vendor/autoload.php';
use SqlParser\Parser;
use SqlParser\Components\Expression;
$query = <<<STR
ALTER TABLE `tbl` CHANGE `uid` `uid` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT;
ALTER TABLE `tbl` CHANGE `field_1` `field_2` INT( 10 ) UNSIGNED NOT NULL;
select * from tbl3 where id = 3
STR;
$parser = new Parser($query);
//處理第一條語句
$statement_0 = $parser->statements[0];
$statement_0->table = new Expression(
'db2', 'tb2', ''
);
var_dump($statement_0->build());
//處理第二條語句
$statement_1 = $parser->statements[1];
$statement_1->table = new Expression(
'db3', 'tb3', ''
);
var_dump($statement_1->build());
輸出結果:
margin@margin-MB1:~/code/parserTest$ php build.php
string(85) "ALTER TABLE `db2`.`tb2` CHANGE `uid` `uid` INT( 10 ) UNSIGNED NOT
NULL AUTO_INCREMENT"
string(78) "ALTER TABLE `db3`.`tb3` CHANGE `field_1` `field_2` INT( 10 ) UNSIGNED
NOT NULL"
以上是sql-parser組件一些基本的用法示例,phpMyAdmin的sql-parser組件功能比較豐富和完備,本文限了篇幅不能詳盡,有興趣的讀者可以通過閱讀源碼來瞭解更多高級的用法。
相關推薦
什麼是雲資料庫MySQL?
存儲總量達20T的MySQL實例,如何完成遷移?
CDB for MySQL相關文檔
此文已由作者授權騰訊雲技術社區發佈,轉載請註明文章出處,獲取更多雲計算技術乾貨,可請前往騰訊雲技術社區
歡迎大家關註騰訊雲技術社區-博客園官方主頁,我們將持續在博客園為大家推薦技術精品文章哦~