初探jsqlparser
大数据处理中离不开SQL,如使用flink、查询各种数据库等场景。
用户提交sql后,系统处理往往需要知道用户提交的一些信息(查询or更新、表名、字段等),因此需要sql解析
jsqlparser介绍
jsqlparser是开源的sql解析器,是mybatis底层解析,有着较为活跃的社区支撑。地址如下:
https://github.com/JSQLParser/JSqlParser
但特定db的特色语句无法支持,如mysql的show语法;
jsqlparser把sql解析成对应的抽象语法树,并通过visitor模式对其中的数据进行访问或改写。
示例
判断sql中是否进行聚合操作(group by),并提取出表名
1.对sql进行解析
CCJSqlParserManager pm = new CCJSqlParserManager();
Statement statement = pm.parse(new StringReader(sql));
2.定义一个visitor,对语句中的group by节点进行访问判断
public class SqlElementFinder implements SelectVisitor, FromItemVisitor{
private boolean isGroupBy;
private List<String> tables;
public SqlElementFinder(){
isGroupBy = false;
tables = new ArrayList<>();
}
public boolean isGroupBy() {
return isGroupBy;
}
public List<String> getTables() {
return tables;
}
public boolean judge(Select select){
select.getSelectBody().accept(this);
return isGroupBy;
}
@Override
public void visit(PlainSelect plainSelect) {
if(plainSelect.getGroupBy() != null){
isGroupBy = true;
}
plainSelect.getFromItem().accept(this);
}
@Override
public void visit(Table table) {
tables.add(table.getName());
}
@Override
//考虑子查询情况
public void visit(SubSelect subSelect) {
subSelect.getSelectBody().accept(this);
}
}
3.判断是否为select语句,并处理
SqlElementFinder sqlElementFinder = new SqlElementFinder();
if(statement instanceof Select){
System.out.println("select");
sqlElementFinder.judge(((Select) statement));
System.out.println(sqlElementFinder.isGroupBy());
System.out.println(sqlElementFinder.getTables());
} else if (statement instanceof Insert) {
System.out.println("insert");
} else if (statement instanceof Update){
System.out.println("update");
}
4.结果
//语句
select cc from (select aa,bb,cc from tt1 where id = 1) group by cc;
//结果
select
true
[tt1]
进一步开发
考虑到jsqlparser不支持特定db的特色语句,由于jsqlparser基于javacc能力进行解析,可通过自行修改语法规则描述,并重新生成分析器,即可满足需求。
总结
jsqlparser作为开源的sql解析器,功能基本能满足我们对基本sql的解析,若需自定义语句解析,可利用javacc能力,对jsqlparser进行修改。