likes
comments
collection
share

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

作者站长头像
站长
· 阅读数 19

前言

  • 你有没有想过 idea 是如何做到sql 关键字语法高亮的?毫无疑问需要识别出sql 的关键字。

antlr

  • antlr 就是这么一个工具,他能够解析sql ,下面我们通过他来实现表名的获取

安装

antlr-tools

  • 首先我们下载上面的antlr 工具 , 然后再通过工具分析每种sql 的语法,每种sql的语法需要我们额外准备,你可以自己将sql 的语法编写好,这里我就直接使用官方提供的语法了。

sql语法

 git clone https://github.com/antlr/grammars-v4.git
  • 在开始sql解析之前,我们先将焦点移到antlrantlr 是一个语法解析器工具,sql只是其中一个解析,所以我们先开始一段简单的语法解析吧。

安装文档

windows安装

  • 上方文档我们移动到windows章节,首先antlr需要java环境,然后将上方我们下载antlr-4.11.1-complete.jar配置到环境变量中。官网也提到了配置环境变量可以在终端中临时配置也可以在系统环境变量中永久配置。

临时配置环境变量

  • 在终端中执行 SET CLASSPATH=.;C:\Javalib\antlr-4.11.1-complete.jar;%CLASSPATH% 即可在终端中临时设置了变量。

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

永久配置环境变量

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 这样配置只要是新打开的终端都是可以获取到CLASSPATH 这个环境变量的。

小结

  • 这里需要注意的是,在配置CLASSPATH这个环境变量时必须配置 . , 如果不配置在执行到grun命令时会报错Can't load Hello as lexer or parser

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

antlr4&&grun

  • 因为antrl4基于java包,每次运行要从java调用,为了方便使用写一个批处理文件(.bat文件)放在antlr-4.11.1-complete.jar同一文件夹下,自己命名,我命名为antlr4.bat
  • 为了能够访问我们的自定义脚本,这里我们需要将antlr-4.11.1-complete.jar所在目录配置成环境变量。我这里是E:/study/antlr/antlr-4.11.1-complete.jar

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 然后我们就可以在E:\study\antlr的目录下新建一个脚本antlr4.bat , 内容如下
 doskey antlr4=java org.antlr.v4.Tool $*
 doskey grun=java org.antlr.v4.gui.TestRig $*
  • 这样我们可以执行antlr4.bat命令后就可以在终端执行antlr4&&grun命令了。官网也介绍到我们可以分别为antlr4grun创建脚本

antlr4.bat

 java org.antlr.v4.Tool %*

grun.bat

 @ECHO OFF
 SET TEST_CURRENT_DIR=%CLASSPATH:.;=%
 if "%TEST_CURRENT_DIR%" == "%CLASSPATH%" ( SET CLASSPATH=.;%CLASSPATH% )
 @ECHO ON
 java org.antlr.v4.gui.TestRig %*

测试

  • 到了这里我们的antlr4已经安装完成了,那么我们该如何进行语法测试呢?
 grammar Hello;               // 1、定义文法的名字
 ​
 s  : 'hello' ID ;            // 3、匹配关键字hello和标志符
 ID : [a-z]+ ;                // 标志符由小写字母组成
 WS : [ \t\r\n]+ -> skip ;    // 4、跳过空格、制表符、回车符和换行符
  • 下面针对语法进行相关解释:
  1. 定义了 grammar 的名字,名字需要与文件名对应
  2. s定义的语法,会使用到下方定义的正则表达式词法
  3. 定义了空白字符,后面的 skip 是一个特殊的标记,标记空白字符会被忽略。
 grammar Hello;
 r  : 'hello' ID ;
 ID : [a-z]+ ;
 WS : [ \t\r\n]+ -> skip ;

打开终端

  • 针对新打开的终端我们执行antlr4 就会执行我们配置的E:\study\antlr\antlr4.bat 脚本。执行完成之后就可以执行内部命令了。

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 通过antlr4 Hello.g4进行语法翻译

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 会生成一些Java类,这些类就是我们用来解析相关文本的工具类。为了能够执行这些Java 我们先 javac编译一下
 javac Hello*.java

grun解析

  • 下面我们通过grun进行demo解析
 grun Hello r -tree
  • 如下命令就会进行等待我们输入文本。Hello.g4的语法就是 hello [a-z]+ 这个正则,也就是所有的hello开头的文本,中间一个空格后面跟着由小写字母组成的字符的整个文本就会被解析出来。

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

(注意:^D在 Unix 上表示 control-D 并表示“输入结束”;^Z在 Windows 上使用。)

Linux安装

  • windows是大多数人使用的系统,但是Linux才是最终的服务环境,加之我本身就是Linux作为开发环境,所以Linux安装对于我而言很重要。
  • 因为antlr本事就是jar ,得以与java的跨平台所以这里资源两个系统是可以通用的。
  • linux上配置环境变量更方便,我们只需要在~/.bashrc或者~/.zshrc中配置即可
 export CLASSPATH=".:/home/zxhtom/zxh/antlr/antlr-4.11.1-complete.jar:$CLASSPATH"
  • 在终端中给命令创建别名
 alias antlr4='java -Xmx500M -cp "/home/zxhtom/zxh/antlr/antlr-4.11.1-complete.jar:$CLASSPATH" org.antlr.v4.Tool'
 alias grun='java -Xmx500M -cp "/home/zxhtom/zxh/antlr/antlr-4.11.1-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig'
  • 或者我们也可以按照windows方式的命令,其实最终都是执行相同的类
 alias antlr4='java org.antlr.v4.Tool '
 alias grun='java org.antlr.v4.gui.TestRig'
  • export和alias可以同时配置在~/.zshrc中。

可视化

  • TestRig充当一款调试工具,官网建议我们将它重命名为grun

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 直接输入grun可以看到其支持的参数。
参数功能
-tokens打印出词法符号流
-treeLISP格式打印分析树,啥叫LISP?
-gui可视化打印分析树
-ps fiels.ps以PostScript格式生成可视化语法分析树
-trace打印规则的名字以及进入和离开该规则时的语法符号
  • 不管是linux还是windows我们都可以通过 -gui的方式进行可视化

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

自定义解析

  • 4.11开始,antlr大约支持10种语言进行语法解析,上面案列中我使用的是Java 语言的解析工具,只需要javac编译一次即可,或者直接将相关的Java代码拷贝到项目中进行调用。下面我们看看如何生成Python语言的解析代码吧。

python

 pip3 install antlr4-python3-runtime
  • 因为是测试python的语法生成,这里就不配置快捷命令了,所以这里使用全命令java -jar ../antlr-4.11.1-complete.jar -Dlanguage=Python3 Hello.g4
 import sys
 from antlr4 import *
 from HelloLexer import HelloLexer
 from HelloParser import HelloParser
 ​
 ​
 def main(argv):
     input = FileStream(argv[1])
     lexer = HelloLexer(input)
     stream = CommonTokenStream(lexer)
     parser = HelloParser(stream)
     tree = parser.r()
     print(tree.toStringTree(recog=parser))
 ​
 if __name__ == '__main__':
     main(sys.argv)
 ​
  • 上述代码就是我们对antlr生成的解析代码的使用,这样我们可以进行自定义的处理。

解析Mysql

 <dependency>
     <groupId>org.antlr</groupId>
     <artifactId>antlr4</artifactId>
     <version>4.11.1</version>
 </dependency>
  • 版本需要保持一致。
  • 上一章节中我们通过一个简单的Hello.g4语法进行Javapython等语言的解析代码的生成。上章节也提到antlr是一个语法解析工具,并不仅仅是解析sql , 理论上他能解析所有的语法,比如你自己有一套语法如何让antlr解析呢?你只需要按照antlr的规则用antlr的语言表达出你自己的语法,目前比较规范的就是https://github.com/antlr/grammars-v4.git这个仓库提供的语法解析树了,本次对mysql解析也是使用这个仓库下提供的g4 文件。

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 这个仓库给我们提供了MySqlLexer.g4MySqlParser.g4两个文件,前者是Mysql的关键词,后者就是Mysql的语法配置。examples是作者给我们提供的Mysql相关的sql 。 我们可以用来测试用。
  • 为了方便测试,这里我们将这两个g4文件拷贝到其他目录下执行生成Java解析代码
 antlr4 MySqlParser.g4 MySqlLexer.g4
  • 两个文件没有先后顺序区别,但是要注意的是不能缺少。笔者就是一开始认为只需要MysqlParser.g4一再在报错。MySqlParser.g4:2595:37: cannot create implicit token for string literal in non-combined grammar: '|'
  • 执行完上述命令后,我们就可以看到我们的Java代码了.

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

  • 这样的代码是没有包名的,好在antlr在生成代码时支持指定包名。antlr4 MySqlParser.g4 MySqlLexer.g4 -package com.github.zxhtom.mysql

antlr实现解析sql语法树-检测sql是否与数据库字段匹配

点赞收藏,下次直接查找,不丢失