版权声明:本文由陈苗原创文章,转载请注明出处: 
文章原文链接:https://www.qcloud.com/community/article/206

来源:腾云阁 https://www.qcloud.com/community

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包管理工具

  1. margin@margin-MB1:~/tmp$ sudo git clone https://github.com/phpmyadmin/sql-parser.git
  2. margin@margin-MB1:~/tmp$ cd sql-parser && sudo composer install

组件安装完毕,下面介绍具体的调用

解析普通语句

  1. <?php
  2. require_once '../sql-parser/vendor/autoload.php';
  3. use SqlParser\Parser;
  4. $query = 'SELECT * FROM t1 LEFT JOIN (t2, t3, t4) '
  5. . 'ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)';
  6. $parser = new Parser($query);
  7. $stmt = $parser->statements[0];
  8. echo json_encode($stmt);

运行结果中$parser变量是一个大对象,里面存储有对$query语句的词法分析结果$query->list,语法分析结果$query-statements,以及错误信息等。
其中$query-statements的结构如下:

  1. {"expr":
  2. [{"database":null,"table":null,"column":null,"expr":"*","alias":null,"function":n
  3. ull,"subquery":null}],"from":
  4. [{"database":null,"table":"t1","column":null,"expr":"t1","alias":null,"function":
  5. null,"subquery":null}],"partition":null,"where":null,"group":null,"having":null,"
  6. order":null,"limit":null,"procedure":null,"into":null,"join":
  7. [{"type":"LEFT","expr":{"database":null,"table":null,"column":null,"expr":"(t2,
  8. t3, t4)","alias":null,"function":null,"subquery":null},"on":[{"identifiers":
  9. ["t2","a","t1"],"isOperator":false,"expr":"(t2.a=t1.a"},{"identifiers":
  10. [],"isOperator":true,"expr":"AND"},{"identifiers":
  11. ["t3","b","t1"],"isOperator":false,"expr":"t3.b=t1.b"},{"identifiers":
  12. [],"isOperator":true,"expr":"AND"},{"identifiers":
  13. ["t4","c","t1"],"isOperator":false,"expr":"t4.c=t1.c)"}],"using":null}],"union":
  14. [],"options":{"options":[]},"first":0,"last":50}

解析事务

  1. require_once '../sql-parser/vendor/autoload.php';
  2. use SqlParser\Parser;
  3. $query = 'START TRANSACTION;' .
  4. 'SELECT @A:=SUM(salary) FROM table1 WHERE type=1;' .
  5. 'UPDATE table2 SET summary=@A WHERE type=1;' .
  6. 'COMMIT;';
  7. $parser = new Parser($query);
  8. $stmt = $parser->statements[0];
  9. echo json_encode($stmt);

输出结果:

  1. {"type":1,"statements":[{"expr":
  2. [{"database":null,"table":null,"column":null,"expr":"@A:=SUM(salary)","alias":nul
  3. l,"function":"SUM","subquery":null}],"from":
  4. [{"database":null,"table":"table1","column":null,"expr":"table1","alias":null,"fu
  5. nction":null,"subquery":null}],"partition":null,"where":[{"identifiers":
  6. ["type"],"isOperator":false,"expr":"type=1"}],"group":null,"having":null,"order":
  7. null,"limit":null,"procedure":null,"into":null,"join":null,"union":[],"options":
  8. {"options":[]},"first":1,"last":19},{"tables":
  9. [{"database":null,"table":"table2","column":null,"expr":"table2","alias":null,"fu
  10. nction":null,"subquery":null}],"set":[{"column":"summary","value":"@A"}],"where":
  11. [{"identifiers":
  12. ["type"],"isOperator":false,"expr":"type=1"}],"order":null,"limit":null,"options"
  13. :{"options":[]},"first":20,"last":35}],"end":
  14. {"type":2,"statements":null,"end":null,"options":{"options":
  15. {"1":"COMMIT"}},"first":36,"last":37},"options":{"options":{"1":"START
  16. TRANSACTION"}},"first":0,"last":0}

除以上两种语句之外,sql-parser还支持解析存储过程等几乎所有MySQL语法,不再一一举例。下面是其SQL构造器的用法举例。

组装SQL语句

组装select语句:

  1. <?php
  2. require_once '../sql-parser/vendor/autoload.php';
  3. use SqlParser\Components\OptionsArray;
  4. use SqlParser\Components\Expression;
  5. use SqlParser\Components\Condition;
  6. use SqlParser\Components\Limit;
  7. use SqlParser\Statements\SelectStatement;
  8. $stmt = new SelectStatement();
  9. $stmt->options = new OptionsArray(array('DISTINCT'));
  10. $stmt->expr[] = new Expression('sakila', 'film', 'film_id', 'fid');
  11. $stmt->expr[] = new Expression('COUNT(film_id)');
  12. $stmt->from[] = new Expression('', 'film', '');
  13. $stmt->from[] = new Expression('', 'actor', '');
  14. $stmt->where[] = new Condition('film_id > 10');
  15. $stmt->where[] = new Condition('OR');
  16. $stmt->where[] = new Condition('actor.age > 25');
  17. $stmt->limit = new Limit(1, 10);
  18. var_dump($stmt->build());

输出结果:

  1. margin@margin-MB1:~/code/parserTest$ php build.php
  2. string(137) "SELECT DISTINCT `sakila`.`film`.`film_id` AS `fid`, COUNT(film_id)
  3. FROM `film`, `actor` WHERE film_id > 10 OR actor.age > 25 LIMIT 10, 1 "

组装触发器语句:

  1. <?php
  2. require_once '../sql-parser/vendor/autoload.php';
  3. use SqlParser\Components\Expression;
  4. use SqlParser\Components\OptionsArray;
  5. use SqlParser\Statements\CreateStatement;
  6. $stmt = new CreateStatement();
  7. $stmt->options = new OptionsArray(array('TRIGGER'));
  8. $stmt->name = new Expression('ins_sum');
  9. $stmt->entityOptions = new OptionsArray(array('BEFORE', 'INSERT'));
  10. $stmt->table = new Expression('account');
  11. $stmt->body = 'SET @sum = @sum + NEW.amount';
  12. var_dump($stmt->build());

输出结果:

  1. margin@margin-MB1:~/code/parserTest$ php build.php
  2. string(89) "CREATE TRIGGER ins_sum BEFORE INSERT ON account FOR EACH ROW SET @sum
  3. = @sum + NEW.amount"

SQL再加工

多条语句一起加工处理:

  1. <?php
  2. require_once '../sql-parser/vendor/autoload.php';
  3. use SqlParser\Parser;
  4. use SqlParser\Components\Expression;
  5. $query = <<<STR
  6. ALTER TABLE `tbl` CHANGE `uid` `uid` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT;
  7. ALTER TABLE `tbl` CHANGE `field_1` `field_2` INT( 10 ) UNSIGNED NOT NULL;
  8. select * from tbl3 where id = 3
  9. STR;
  10. $parser = new Parser($query);
  11. //处理第一条语句
  12. $statement_0 = $parser->statements[0];
  13. $statement_0->table = new Expression(
  14. 'db2', 'tb2', ''
  15. );
  16. var_dump($statement_0->build());
  17. //处理第二条语句
  18. $statement_1 = $parser->statements[1];
  19. $statement_1->table = new Expression(
  20. 'db3', 'tb3', ''
  21. );
  22. var_dump($statement_1->build());

输出结果:

  1. margin@margin-MB1:~/code/parserTest$ php build.php
  2. string(85) "ALTER TABLE `db2`.`tb2` CHANGE `uid` `uid` INT( 10 ) UNSIGNED NOT
  3. NULL AUTO_INCREMENT"
  4. string(78) "ALTER TABLE `db3`.`tb3` CHANGE `field_1` `field_2` INT( 10 ) UNSIGNED
  5. NOT NULL"

以上是sql-parser组件一些基本的用法示例,phpMyAdmin的sql-parser组件功能比较丰富和完备,本文限了篇幅不能详尽,有兴趣的读者可以通过阅读源码来了解更多高级的用法。

phpMyAdmin中sql-parser组件的使用的更多相关文章

  1. 在phpmyadmin中执行sql语句出现的错误:Unknown storage engine 'InnoDB'

    在phpmyadmin中执行sql语句出现的错误:Unknown storage engine 'InnoDB' 解决方法:解决方法:             1.关闭MySQL数据库       2 ...

  2. SSIS中执行SQL任务组件参数传递的问题

    原文:SSIS中执行SQL任务组件参数传递的问题 症状: 执行SQL任务,传递参数到子查询中,执行报错. 错误: 失败,错误如下:"无法从使用 sub-select 查询的 SQL 语句中派 ...

  3. 使用phpmyadmin导入SQL数据报错:#1062 - Duplicate entry '...

    使用phpmyadmin导入SQL数据报错: MySQL 返回: #1062 - Duplicate entry '0' for key 'PRIMARY' 出现此错误的原因是数据的主键重复了,错误信 ...

  4. hive中sql解析出对应表和字段的调查

    ---恢复内容开始--- .阿里的druid中的sql parser有各种关系数据库sql的解析,但hive的不支持. druid初期的版本中是包含hive的,将以前版本中的hive dialect对 ...

  5. phpMyAdmin中mysql的创建数据库时的编码的问题

    转载自新浪博客    Sean 一. mysql中utf8编码的utf8_bin,utf8_general_cs,utf8_general_ci的区别 utf8_general_ci 不区分大小写,这 ...

  6. SSIS中循环遍历组件[Foreach Loop Container]

    背景 每月给业务部门提取数据,每个分公司都要提取一般,先跑SQL,再粘贴到Excel中,然后发邮件给相关的人员.费时费力,还容易粘贴错位.因此,需要通过一个程序完成这些步骤.我首先想到的是通过SSIS ...

  7. sql parser

    最近在整理很多SQL代码, 需要分析出每个SQL的目标表和源表各有哪些, 网上没有找到工作具, 打算写个工具. Java调研结果:1. 商业组件包 sqlparser 有试用版组件, 限制SQL少于1 ...

  8. [转]页游开发中的 Python 组件与模式Presentation Transcript

    转: 页游开发中的 Python 组件与模式Presentation Transcript 1. 页游开发中的 Python 组件与模式 赖勇浩( http://laiyonghao.com ) 20 ...

  9. 【spring boot】集成了druid后,同样的mybatis模糊查询语句出错Caused by: com.alibaba.druid.sql.parser.ParserException: syntax error, error in :'name LIKE '%' ? '%'

    druid版本是 <!-- https://mvnrepository.com/artifact/com.alibaba/druid 数据库连接池--> <dependency> ...

  10. 利用 druid 的 sql parser 模块解析 sql 语句

    druid 是阿里开源在 github 上面的数据库连接池,里面有一个专门解析 sql 语句的模块   源码位置: https://github.com/alibaba/druid SQL Parse ...

随机推荐

  1. Linux 常见的trouble shooting故障排错

    Linux 常见的trouble shooting故障排错 备份开机所必须运行的程序对一个运维人员来说是非常有必要的.在实际生产环境中,系统和数据基本都是安装在不同的硬盘上面,因为企业最关心的还是数据 ...

  2. C#json 解析

    Json样例一: string jsonText= {Code)\/)\/"}}} JObject jo = JObject.Parse(jsonText); string strCode= ...

  3. SqlSever基础 len函数 计算前后都有空格的字符串的长度时

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  4. BZOJ 3564 信号增幅仪

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3564 题意:给出平面上n个点,画出一个椭圆,椭圆的长轴是短轴的p倍,且长轴的方向为x轴逆时 ...

  5. oracle 快照

    select count(*) from atzserreportb drop snapshot atzserreportb Create snapshot atzserreportb as sele ...

  6. CodeForces 131A cAPS lOCK

    cAPS lOCK Time Limit:500MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit St ...

  7. 当插入数据失败时,防止mysql自增长字段的自增长的方法

    问题描述: 当mysql设置了自增长字段时(注意:一个表中只能设置一个自增长字段,可以不是主键,但必须是键 ),如果插入数据失败,那么自增长字段仍然会占用这个自增长值,再次成功插入数据时就会造成断层. ...

  8. CVE-2015-7547

    危险漏洞补丁修复通知 漏洞编号 漏洞编号为CVE-2015-7547 漏洞说明: Google安全团队近日发现glibc存在的溢出漏洞. glibc的DNS客户端解析器中存在基于栈的缓冲区溢出漏洞.当 ...

  9. 购买vps创建账号后无法登录ftp

    购买了vps,并在后台已经开通了ftp账号,但是前台无法登录.错误提示530.解决方法是: 请检查您ftp账号密码是否输入正确,若确认正确,请您ssh登陆服务器,然后执行sh /www/wdlinux ...

  10. CALayer总结(二)

    1.CATransaction 事务: UIView有两个方法,+beginAnimations:context:和+commitAnimations,和CATransaction的+begin 和+ ...