腾讯云数据库团队:phpMyAdmin中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相关文档
此文已由作者授权腾讯云技术社区发布,转载请注明文章出处,获取更多云计算技术干货,可请前往腾讯云技术社区
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~
腾讯云数据库团队:phpMyAdmin中sql-parser组件的使用的更多相关文章
- 腾讯云数据库团队:浅谈如何对MySQL内核进行深度优化
作者介绍:简怀兵,腾讯云数据库团队高级工程师,负责腾讯云CDB内核及基础设施建设:先后供职于Thomson Reuters和YY等公司,PTimeDB作者,曾获一项发明专利:从事MySQL内核开发工作 ...
- 腾讯云数据库团队:MySQL AHI 实现解析
MySQL 定位用户记录的过程可以描述为:打开索引 -> 根据索引键值逐层查找 B+ 树 branch 结点 -> 定位到叶子结点,将 cursor 定位到满足条件的 rec 上:如果树高 ...
- 腾讯云数据库团队:MySQL数据库的高可用性分析
作者介绍:易固武,腾讯高级工程师,参与腾讯账号安全建设,腾讯数据仓库(TDW)优化改造,腾讯云数据库等项目,对大规模分布式存储和计算系统有浓厚的兴趣和经历 MySQL数据库是目前开源应用最大的关系型数 ...
- 腾讯云数据库团队:SQL Server 数据加密功能解析
数据加密是数据库被破解.物理介质被盗.备份被窃取的最后一道防线:数据加密,一方面解决数据被窃取安全问题,另一方面有关法律要求强制加密数据:SQL Server 的数据加密相较于其他数据库,功能相对完善 ...
- 腾讯云数据库团队:MySQL语句复制(SBR)的缺陷列举
作者介绍: 赵伟 腾讯云TDSQL数据库开发者 MySQL (这里的MySQL是指广义的mysql,包括oracle,mysql,percona,mariadb等)的Statement Based R ...
- 腾讯云数据库团队:MySQL5.7 JSON实现简单介绍
作者介绍:吴双桥 腾讯云project师 阅读原文.很多其它技术干货.请訪问fromSource=gwzcw.57435.57435.57435">腾云阁. 本文主要介绍在MySQL ...
- 腾讯云数据库团队:PostgreSQL TOAST技术理解
作者介绍:胡彬 腾讯云高级工程师 TOAST是"The Oversized-Attribute Storage Technique"的缩写,主要用于存储一个大字段的值.要理解TOA ...
- MySQL之父造访腾讯云 为腾讯云数据库开源点赞
近日,技术大牛 MariaDB 公司创始人兼CTO Michael Widenius(又名Monty).MariaDB 基金会主席 Kaj 来到中国,针对MariaDB与腾讯云的技术合作进行回访.去年 ...
- TDSQL|三篇论文入选国际顶会SIGMOD,厉害了腾讯云数据库
好消息!6月13日,腾讯云数据库三篇论文再次入选数据库行业顶会SIGMOD,被SIGMOD 2022 Research Full Paper(研究类长文)收录. 本次被收录的研究成果中,新型数据结构设 ...
随机推荐
- Cocos2d-x 详解坐标系统
这篇博文将介绍一下在cocos2dx中的一些坐标系统概念: 一. (1) OpenGL坐标系 Cocos2D-x以OpenGL和OpenGL ES为基础,所以自然支持OpenGL坐标系.该坐标系原点在 ...
- HTML5常用标签分类
1.行级元素标签:a.span.sup.sub.em.b.big.i.strong 2.块元素标签:div.p.h1~h6.ul.ol.li.table.form.article.footer.hea ...
- jquery 实现table的动态合并列
常见的table是一行一列的形式,当有时会遇到后台的数据在前台显示时, 需要显示多对一,eg: 这是后台初始的数据,现在我要显示为: 思路:将第3列的td的rowspan改为为行数, 删除第一行之外的 ...
- greenlet 详解
在前面的文章中提到python原生的generator是semicoroutine,而greenlet是 真 协程.本文内容主要来自对官网文档的翻译,在其中也加入了很多自己的理解和例子.主要包括以下内 ...
- Oracle RAC学习笔记01-集群理论
Oracle RAC学习笔记01-集群理论 1.集群相关理论概述 2.Oracle Clusterware 3.Oracle RAC 原理 写在前面: 最近一直在看张晓明的大话Oracle RAC,真 ...
- C++编程练习(3)----“实现简单的栈的顺序存储结构“
栈(stack)是限定仅在表尾进行插入和删除操作的线性表. 允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom). 栈又称为后进先出(Last In First Out)的线性表,简 ...
- js实现省市区联动
先来看看效果图吧,嘻嘻~~~~~~~~~~~~~~~~~~~· 代码在下面: 示例一: html: <!DOCTYPE html> <html> <head> &l ...
- DOM遍历
前面的话 DOM遍历模块定义了用于辅助完成顺序遍历DOM结构的类型:Nodeiterator和TreeWalker,它们能够基于给定的起点对DOM结构执行深度优先(depth-first)的遍历操作. ...
- 深入子元素的width与父元素的width关系
深入理解父元素与子元素的width关系 对于这一部分内容,如果理解准确,可以更容易控制布局,节省不必要的代码,这里将简单研究. 第一部分:父子元素都是内联元素 代码演示如下: <!DOCTYPE ...
- LINQ查询表达式和LAMBDA点标记方法基础
在上一篇文章中,我们介绍了LINQ的一些基本用法,这一篇我们来看下另一种更简洁更优雅的表达式,Lambda表达式,也可以叫做点标记方法. 相信大家在实际工作中都用到过这两种方式,下面我们还是用实例来看 ...