SQL解析调研

概述

在做大数据产品时,如ad hoc查询平台:页面上有一个输入框,可输入SQL语句,支持各种不同的数据源,包括传统的关系型数据库(如MySQL、Oracle、SQL Server等)和非关系型数据库(如ClickHouse、Impala、Hive),可点击执行,获得并展示执行结果。

很可能会遇到的需求:在SQL语句提交到数据源执行之前,对SQL进行分析,是否有标点符号问题,语法问题,获取查询的表名,获取查询的字段名(进而做字段映射、以及数据推送)等。

注:本文局限于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,但是未被采纳。

Antlr4

很底层的技术,Sharding Sphere就用到此技术。不仅仅可以用于SQL解析。

<dependency>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4</artifactId>
</dependency>

Apache Calcite

一款开源的动态数据管理框架,具备SQL解析、SQL校验、查询优化、SQL生成以及数据连接查询等功能,常用于为大数据工具提供SQL能力,如Hive、Flink等。

Calcite对标准SQL支持良好,但是对传统的关系型数据方言支持度较差。

JSqlParser

General SQL Parser官网

JSqlParser,是基于JavaCC的开源SQL Parser,是General SQL Parser的Java实现版本。

上手容易,操作简单,只能对sql语句进行拆分解析,和数据库无关。只支持关系型数据库,不支持NoSQL和大数据计算引擎等,

另起一篇,参考JSqlParser

fdb-sql-parser

FoundationDB在被Apple收购前开源的SQL Parser,目前已无人维护。

Maven依赖如下:

<dependency>
	<groupId>com.foundationdb</groupId>
	<artifactId>fdb-sql-parser</artifactId>
	<version>1.6.1</version>
</dependency>

最后一次发布时间停留在Feb 03, 2015。

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文件。

SQL Advisor

GitHub,美团点评开源。

Sharding Sphere

国产开源数据库中间件。Sharding Sphere前身是Sharding-JDBC,后进入Apache孵化项目,并孵化成功。开源维护者已开始创业,基于此在做一个庞大的数据库生态系统。组件可插拔,包括SQL解析模块。
部分参考资料,详见:sql-parser

gsqlparser

https://www.sqlparser.com/download.php
https://github.com/sqlparser/gsp_demo_java
Maven仓库找不到这个jar,需要自己上传。有功能缺陷,不建议使用。

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自动生成字段功能实现

获取依赖表

推荐文章

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

johnny233

晚饭能不能加鸡腿就靠你了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值