飞道的博客

基于JDBC实现VPD:SQL解析篇

250人阅读  评论(0)

接着之前的文章《浅谈基于JDBC实现虚拟专用数据库(VPD)》的内容,今天我们重点来说一下SQL解析的问题。

从架构上我们可以看出来,如果要基于JDBC做VPD,不能绕开的一个问题,就是要解析SQL,那么如何解析SQL呢?其实可供选择的方案还是很多的,比如JSqlParser、Saprk的Catalyst,亦或是直接使用Antlr,不过这里我还是更推荐使用Apache的Calcite。

首先,我们需要构建一个解析器,这里为了方便,使用Mysql语法


   
  1. SqlParser.Config config = SqlParser.configBuilder()
  2. .setLex(Lex.MYSQL) //使用mysql 语法
  3. .build();
  4. String sql = "select id,name,age FROM orders";
  5. SqlParser sqlParser = SqlParser
  6. .create(sql, config);

然后,构建一颗AST树

SqlNode sqlNode = sqlParser.parseStmt();

接下来,就需要各种分支判断,来对这个语法树进行遍历,举个简单的例子,我们将标示,以及select项打印出来。


   
  1. if(SqlKind.SELECT.equals(sqlNode.getKind())){
  2. SqlSelect sqlSelect = (SqlSelect) sqlNode;
  3. SqlNode from=sqlSelect.getFrom();
  4. SqlNode where=sqlSelect.getWhere();
  5. SqlNodeList selectList=sqlSelect.getSelectList();
  6. if(SqlKind.IDENTIFIER.equals(from.getKind())){
  7. System.out.println(from.toString());
  8. }
  9. selectList.getList(). forEach(x->{
  10. System.out.println( "==> "+x);
  11. });
  12. }

所有的SQL语法都会被转换,我们的demo使用select语句,类似的,还有SqlInsert,SqlUpdate,SqlJoin等,解析Sql是一个非常细致的工作,有兴趣的同学也可以读一下Antlr的Sql语法文件,也很有意思。

解析Sql只是整个VPD中的一环,我们还需要进行Sql的构建。举个简单,我们来构建一个简单的sql查询


   
  1. SqlParserPos sqlParserPos = new SqlParserPos( 1, 1);
  2. SqlIdentifier all = new SqlIdentifier( "*", null, sqlParserPos);
  3. SqlIdentifier o = new SqlIdentifier( "o", null, sqlParserPos);
  4. SqlNodeList snl = new SqlNodeList(sqlParserPos);
  5. snl.add(all);
  6. SqlSelect sqls = new SqlSelect(sqlParserPos, null,snl,o, null, null, null, null, null, null, null);
  7. System.out.println(sqls);

完整代码如下:


   
  1. package cn.flinkhub.bigdata;
  2. import org.apache.calcite.config.Lex;
  3. import org.apache.calcite.sql.*;
  4. import org.apache.calcite.sql.parser.SqlParseException;
  5. import org.apache.calcite.sql.parser.SqlParser;
  6. import org.apache.calcite.sql.parser.SqlParserPos;
  7. public class VPDDemo {
  8. public static void main(String[] args) {
  9. SqlParser.Config config = SqlParser.configBuilder()
  10. .setLex(Lex.MYSQL) //使用mysql 语法
  11. .build();
  12. String sql = "select id,name,age FROM orders";
  13. SqlParser sqlParser = SqlParser
  14. .create(sql, config);
  15. SqlNode sqlNode = null;
  16. try {
  17. System.out.println( "sql = "+ sql);
  18. sqlNode = sqlParser.parseStmt();
  19. if(SqlKind.SELECT.equals(sqlNode.getKind())){
  20. SqlSelect sqlSelect = (SqlSelect) sqlNode;
  21. SqlNode from=sqlSelect.getFrom();
  22. SqlNode where=sqlSelect.getWhere();
  23. SqlNodeList selectList=sqlSelect.getSelectList();
  24. if(SqlKind.IDENTIFIER.equals(from.getKind())){
  25. System.out.println(from.toString());
  26. }
  27. selectList.getList(). forEach(x->{
  28. System.out.println( "==> "+x);
  29. });
  30. }
  31. } catch (SqlParseException e) {
  32. throw new RuntimeException( "", e);
  33. }
  34. SqlParserPos sqlParserPos = new SqlParserPos( 1, 1);
  35. SqlIdentifier all = new SqlIdentifier( "*", null, sqlParserPos);
  36. SqlIdentifier o = new SqlIdentifier( "o", null, sqlParserPos);
  37. SqlNodeList snl = new SqlNodeList(sqlParserPos);
  38. snl.add(all);
  39. SqlSelect sqls = new SqlSelect(sqlParserPos, null,snl,o, null, null, null, null, null, null, null);
  40. System.out.println(sqls);
  41. }
  42. }

好了,今天就写到这了,希望对大家能有所启发,如果你对Calcite有兴趣,可以与我讨论,接下来,也许会进一步说说构建Sql的事...

作为延伸阅读,推荐大家读读王蒙大神的BLOG。非常有帮助,我以前也转过他的文章

Apache Calcite 处理流程详解(一)

Apache Calcite 优化器详解(二)

Apache Calcite 优化器详解(三)


转载:https://blog.csdn.net/dafei1288/article/details/104289881
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场