最近发现一款功能非常强大的解析SQL语句的引擎,GSP(全称General SQL Parser)。这是一款专业的SQL引擎,适用于市面上流行的各种数据库,同时他也支持了马哈鱼分析器对SQL的分析。这是他的官网:
https://www.sqlparser.com/
我们可以使用他对SQL的语法解析,格式化,提取关键字属性,获取数据库metadata等,下面用一些case来介绍下GSP的其中一个功能。
首先去他的官网下载试用版本:
https://sqlparser.com/download.php
下载解压后,src是一些实例,javadoc是Java帮助文档,还有UserGuide帮助手册,external_lib下是gsp所依赖的一些包,最重要的lib下的gsp.jar就是我们要build path到工程中的sdk。
有下面这样一个SQL
select yb_stage.widetabletest2
from info_yb_stage yb_stage
where pk_id = 206041839059439594
and yb_stage.r9 = 1000
如果我想要动态修改where条件中的r9的值,只能通过正则的方式获取到r9的值再替换,写起来很麻烦并且不易维护,但使用GSP来完成这个工作就很轻松了,如下:
public void testModifySQL() {
String sql = "select yb_stage.widetabletest2 \n" +
"from info_yb_stage yb_stage\n" +
"where pk_id = 206041839059439594\n" +
"and yb_stage.r9 = 1000";
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvpostgresql);
parser.sqltext = sql;
int ret = parser.parse();
if (ret != 0) {
System.err.println("Error parsing:" + parser.getErrormessage());
return;
}
TSelectSqlStatement statement = (TSelectSqlStatement) parser.getSqlstatements().get(0);
TExpression rightOperand = statement.getWhereClause().getCondition().getRightOperand();
//update value
rightOperand.getRightOperand().setString("2000");
System.out.println(statement.toString());
}
只需要上面几行代码即可完成修改。
其中 parser.parse()
是关键,GSP会对整个SQL进行解析同时分析语法的正确性,返回一个结果,如果不为0则表示有语法错误返回错误信息。
整个select语句被解析成TSelectSqlStatement对象,其中where条件是TSelectSqlStatement对象中的WhereClause,其中的条件通过getCondition()方法拿到,yb_stage.r9 = 1000
条件在左边通过getRightOperand()方法获取,再getRightOperand()获取最终要修改的1000
,通过setString方法修改,这样整个SQL就完成了修改,这样整个解析修改过程都很清晰明了,并且可维护。
上面是一个比较简单的case,下面介绍修改存储工程中sql:
create or replace procedure yb_stage.transfer()
language plpgsql
as $$
begin
update yb_stage.widetabletest2
set r9 = 1000
where pk_id = 206041839059439594;
end;
$$
上面这个是postgresql数据库的一个存储过程,对其中r9赋的值1000进行修改:
public void testModifyBody() {
String sql = "create or replace procedure yb_stage.transfer()\n" +
"language plpgsql \n" +
"as $$\n" +
"begin\n" +
" update yb_stage.widetabletest2 \n" +
" set r9 = 1000\n" +
" where pk_id = 206041839059439594;\n" +
"end;\n" +
"$$";
TGSqlParser parser = new TGSqlParser(EDbVendor.dbvpostgresql);
parser.sqltext = sql;
int ret = parser.parse();
if (ret != 0) {
System.err.println("Error parsing:" + parser.getErrormessage());
}
TCustomSqlStatement tCustomSqlStatement = parser.getSqlstatements().get(0);
TCreateProcedureStmt stmt = (TCreateProcedureStmt) tCustomSqlStatement;
TStatementList bodyStatements = stmt.getBodyStatements();
TUpdateSqlStatement statement = (TUpdateSqlStatement) bodyStatements.get(0);
TResultColumn resultColumn = statement.getResultColumnList().getResultColumn(0);
TExpression expr = resultColumn.getExpr();
String oldBody = statement.toString();
//update value
expr.getRightOperand().setString("2000");
//Replace sqltext in ${sqltext}$
String newSql = tCustomSqlStatement.toString().replace(oldBody, statement.toString());
System.out.println(newSql);
}
首先一样的通过 parser.parse()
解析SQL,SQL被解析成TCreateProcedureStmt对象,从TCreateProcedureStmt对象中拿到TStatementList获取其中的TUpdateSqlStatement对象,这个就是整个存储过程中被解析出来的body数据,即:
update yb_stage.widetabletest2
set r9 = 1000
where pk_id = 206041839059439594;
接下来就是对r9的值修改,首先获取r9的值,通过getResultColumnList()拿到结果集,getRightOperand()找到具体的r9,再通过setString方法修改。
因为这个存储过程中有$$
符号,GSP无法像对简单SQL的处理一样对存储过程整体SQL修改,所以具体替换其中被修改后的body,如下:
//Replace sqltext in ${sqltext}$
String newSql = tCustomSqlStatement.toString().replace(oldBody, statement.toString());
这样就完成了修改。
以上就是对GSP对SQL动态修改的介绍,关于GSP的等多功能,请参考下面链接:
GSP官网: https://www.sqlparser.com/
GSP文档:http://support.sqlparser.com/
版权归属古都香港科技有限公司