SQL解析调研
概述
在做大数据产品时,经常遇到的一个需求,页面上有一个输入框,可以输入SQL语句,然后获得执行结果。如adhoc。
注:本文局限于Java语言。
调研
Druid
阿里的Druid,开源作者推广时,称其为最强大的,性能最佳的数据库连接池。但是benchmark实验下来,好像不如HikariCP,可参考JDBC与数据库连接池。
但是这并不妨碍国产的开源产品被广泛使用,Druid的数据库监控功能,SQL Parser,即SQL解析就很有应用场景。
解析代码片段:
public List<String> getAllQuery(String sql, String dbType) {
List<SQLStatement> stmtList = SQLUtils.parseStatements(sql, dbType);
SQLASTOutputVisitor.defaultPrintStatementAfterSemi = false;
List<String> result = stmtList.stream().map(SQLStatement::toString).collect(Collectors.toList());
SQLASTOutputVisitor.defaultPrintStatementAfterSemi = null;
return result;
}
对于Sql Server如下语句:
exec bi..sp_iData_user_role;
select 1 as a;
解析报错:
java.lang.ClassCastException: com.alibaba.druid.sql.visitor.SQLASTOutputVisitor cannot be cast to com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor
解决方法:
List<String> result = stmtList.stream().map(x -> SQLUtils.toSQLString(x, dbType)).collect(Collectors.toList());
缺点:支持对Hive SQL的解析,但是不支持Impala SQL的解析。
有人针对Impala SQL解析这一潜在功能支持问题,提过pull request,但是未被采纳。
antlr
很底层的技术,Sharding Sphere就用到此技术。不仅仅可以用于SQL解析。
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
</dependency>
gsqlparser
https://www.sqlparser.com/download.php
https://github.com/sqlparser/gsp_demo_java
Maven仓库找不到这个jar,需要自己上传。有功能缺陷,不建议使用
impala-frontend
使用Impala parser解析SQL
https://github.com/apache/impala
https://mvnrepository.com/artifact/org.apache.impala/impala-frontend
但是根据上面的文章使用Impala parser解析SQL,程序运行失败,报错信息:
java.lang.RuntimeException: Failed to load libfesupport.so from any candidate location:
缺失一个libfesupport.so
文件。
Apache Calcite
SQL Parser
官网:SQL Parser
SQL Advisor
GitHub,美团点评开源。
Sharding Sphere
国产开源数据库中间件。Sharding Sphere前身是Sharding-JDBC,后进入Apache孵化项目,并孵化成功。开源维护者已开始创业,基于此在做一个庞大的数据库生态系统。组件可插拔,包括SQL解析模块。
部分参考资料,详见:sql-parser
dt-sql-parser
node js包
https://www.npmjs.com/package/dt-sql-parser/v/2.0.11
实现
判断是否为查询语句
/**
* 判断是否为查询语句
*/
public static boolean isSelect(String sql, String jdbcType) {
SQLStatementParser parser = SQLParserUtils.createSQLStatementParser(sql, jdbcType);
Token token = parser.getExprParser().getLexer().token();
return token.equals(Token.SELECT);
}
作为一个SQL new boy,以为只有select查询查询语句。
直到遇到下面这种SQL(经过简化):
with mingxi as
(select *
from (select a.call_system
, row_number()
over (partition by a.asp_tn_seqnum order by (unix_timestamp(b.createtime) - unix_timestamp(a.call_start_time))) rnd
from edw.d_cs_cdr_dly a
where a.call_system = "aspect_tieniu") x1
where rnd = 1)
select call_system
from mingxi;
关于With As查询语句,可参考WITH AS查询
获取查询字段
内容较多,另起一篇,参考SQL自动生成字段功能实现
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2018-10-24 JDBC与数据库连接池