1、JSqlParser
gtihub 地址: https://github.com/JSQLParser/JSqlParser.git
使用方法:
/**
*
* @Package: com.yonyou.splice
* @author: caozq
* @date: 2018年6月26日 下午12:03:52
*/
package com.yonyou.splice;
import java.io.StringReader;
import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
/**
* @ClassName: JsqlparserDemo
* @Description: TODO
* @author: caozq
* @date: 2018年6月26日 下午12:03:52
*/
public class JsqlparserDemo {
public static void main(String[] args) throws JSQLParserException {
insertIntoDemo();
}
public static void insertIntoDemo() throws JSQLParserException {
CCJSqlParserManager pm = new CCJSqlParserManager();
StringBuffer stringBuffer = new StringBuffer();
//insert into metrics_03 select pk,money,0 from metrics_01
//stringBuffer.append("insert into tbl_name1(col1,col2) select col3,col4 from tbl_name2");
// stringBuffer.append(" INSERT INTO FAE_CFG_CRI_AMOUNTTYPE (")
// .append(" PK_AMOUNTTYPECRITERION,")
// .append(" PK_AMOUNTTYPE,")
// .append(" AMOUNTTYPE_CODE")
// .append(" )")
// .append(" SELECT")
// .append(" B.PK_AMOUNTTYPECRITERION,")
// .append(" C.PK_AMOUNTTYPE,C.CODE AMOUNTTYPE_CODE")
// .append(" FROM FAE_AMOUNTTYPECRITERION_B A INNER JOIN FAE_AMOUNTTYPECRITERION B")
// .append(" ON A.PK_AMOUNTTYPECRITERION=B.PK_AMOUNTTYPECRITERION")
// .append(" LEFT JOIN FAE_AMOUNTTYPE C")
// .append(" ON A.PK_AMOUNTTYPE=C.PK_AMOUNTTYPE")
// .append(" WHERE NVL(A.DR,0)=0")
// .append(" AND NVL(B.ISENABLE,'Y')='Y' AND NVL(B.DR,0)=0")
// .append(" AND NVL(C.ISENABLE,'Y')='Y' AND NVL(C.DR,0)=0");
stringBuffer.append(" INSERT INTO FAE_VOUCHER_B")
.append(" PK_AMOUNTTYPECRITERION,")
.append(" PK_AMOUNTTYPE,")
.append(" AMOUNTTYPE_CODE")
.append(" )")
.append(" WITH FAE_ASSFLOW_B_TEMP AS (")
.append(" SELECT")
.append(" T1.RECORD_DT ,")
.append(" T1.DEAL_DT ,")
.append(" T1.DEAL_CODE ")
.append(" CASE WHEN T1.CDFLAG='C' THEN DEAL_AMT")
.append(" WHEN T1.CDFLAG='D' THEN -DEAL_AMT")
.append(" ELSE 0 END DEAL_AMT")
.append(" ON A.PK_AMOUNTTYPE=C.PK_AMOUNTTYPE")
.append(" WHERE NVL(A.DR,0)=0")
.append(" AND NVL(B.ISENABLE,'Y')='Y' AND NVL(B.DR,0)=0")
.append(" AND NVL(C.ISENABLE,'Y')='Y' AND NVL(C.DR,0)=0");
Statement statement = pm.parse(new StringReader(stringBuffer.toString()));
if (statement instanceof Insert) {
// 获得Update对象
Insert istatement = (Insert) statement;
// 获得表名
System.out.println("table:" + istatement.getTable());
List columns = istatement.getColumns();
if(null == columns){
columns = null;//获取所有的表字段
}
//
Select sele = istatement.getSelect();
PlainSelect body = (PlainSelect) sele.getSelectBody();
String selectStr = body.toString();
System.out.println("-------");
// 获得where条件表达式
Expression where = null;
if(istatement.getSetExpressionList().size()!=0){
where = istatement.getSetExpressionList().get(0);
// 初始化接收获得到的字段信息
StringBuffer allColumnNames = new StringBuffer();
// BinaryExpression包括了整个where条件,
// 例如:AndExpression/LikeExpression/OldOracleJoinBinaryExpression
if (where instanceof BinaryExpression) {
allColumnNames = getColumnName((BinaryExpression) (where), allColumnNames);
System.out.println("allColumnNames:" + allColumnNames.toString());
}
}
}
}
public static void updateDemo() throws JSQLParserException {
CCJSqlParserManager pm = new CCJSqlParserManager();
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("update ac_operator op ");
stringBuffer.append("set op.errcount=(");
stringBuffer.append("(select case when op1.errcount is null then 0 else op1.errcount end as errcount ");
stringBuffer.append("from ac_operator op1 ");
stringBuffer.append("where op1.loginname = '中国' )+1");
stringBuffer.append("),lastlogin='中国' ");
stringBuffer.append("where PROCESS_ID=");
stringBuffer.append("(select distinct g.id from tempTable g where g.ID='中国')");
stringBuffer.append("and columnName2 = '890' and columnName3 = '678' and columnName4 = '456'");
Statement statement = pm.parse(new StringReader(stringBuffer.toString()));
if (statement instanceof Update) {
// 获得Update对象
Update updateStatement = (Update) statement;
// 获得表名
System.out.println("table:" + updateStatement.getTables().get(0).getName());
List columns = updateStatement.getColumns();
for (Column column : columns) {
System.out.println(column.getColumnName());
}
// 获得where条件表达式
Expression where = updateStatement.getWhere();
// 初始化接收获得到的字段信息
StringBuffer allColumnNames = new StringBuffer();
// BinaryExpression包括了整个where条件,
// 例如:AndExpression/LikeExpression/OldOracleJoinBinaryExpression
if (where instanceof BinaryExpression) {
allColumnNames = getColumnName((BinaryExpression) (where), allColumnNames);
System.out.println("allColumnNames:" + allColumnNames.toString());
}
}
}
/**
* 获得where条件字段中列名,以及对应的操作符 @Title: getColumnName @Description:
* TODO(这里用一句话描述这个方法的作用) @param @param expression @param @param
* allColumnNames @param @return 设定文件 @return StringBuffer 返回类型 @throws
*/
private static StringBuffer getColumnName(Expression expression, StringBuffer allColumnNames) {
String columnName = null;
if (expression instanceof BinaryExpression) {
// 获得左边表达式
Expression leftExpression = ((BinaryExpression) expression).getLeftExpression();
// 如果左边表达式为Column对象,则直接获得列名
if (leftExpression instanceof Column) {
// 获得列名
columnName = ((Column) leftExpression).getColumnName();
allColumnNames.append(columnName);
allColumnNames.append(":");
// 拼接操作符
allColumnNames.append(((BinaryExpression) expression).getStringExpression());
// allColumnNames.append("-");
}
// 否则,进行迭代
else if (leftExpression instanceof BinaryExpression) {
getColumnName((BinaryExpression) leftExpression, allColumnNames);
}
// 获得右边表达式,并分解
Expression rightExpression = ((BinaryExpression) expression).getRightExpression();
if (rightExpression instanceof BinaryExpression) {
Expression leftExpression2 = ((BinaryExpression) rightExpression).getLeftExpression();
if (leftExpression2 instanceof Column) {
// 获得列名
columnName = ((Column) leftExpression2).getColumnName();
allColumnNames.append("-");
allColumnNames.append(columnName);
allColumnNames.append(":");
// 获得操作符
allColumnNames.append(((BinaryExpression) rightExpression).getStringExpression());
}
}
}
return allColumnNames;
}
}
2 Apache Calcite(以Mysql为例)
public static String convertMySql(String sql)
throws SQLException, SqlParseException, ValidationException, RelConversionException {
Connection aConnection = JDBCConnection.getInstance().getConnection();
try{
SqlDialectFactory aSqlDialectFactory = new SqlDialectFactoryImpl();
SqlDialect aSqlDialect = aSqlDialectFactory.create(aConnection.getMetaData());
SqlDialect.DatabaseProduct aDatabaseProduct =
SqlDialect.getProduct(aConnection.getMetaData().getDatabaseProductName(), "UNUSED");
String schemaName = getSchemaName(aDatabaseProduct, aConnection);
String catalog = aConnection.getCatalog();
FrameworkConfig aConfig = createConfig(dataSource, aDatabaseProduct, catalog, schemaName);
Planner aPlanner = Frameworks.getPlanner(aConfig);
SqlNode aQuery = aPlanner.parse(sql);
aQuery = aPlanner.validate(aQuery);
RelNode aRelNode = aPlanner.rel(aQuery).project();
RelToSqlConverter aSqlConverter = new RelToSqlConverter(aSqlDialect);
SqlNode aSqlNode = aSqlConverter.visitChild(0, aRelNode).asStatement();
System.out.println(sql);
System.out.println(aQuery);
System.out.println(RelOptUtil.toString(aRelNode));
System.out.println(aSqlNode);
return sql;
}catch(Exception e){
e.getStackTrace();
}
return null;
}
3 JavaCC
JavaCC 是一个词法分析生成器和语法分析生成器。 词法分析和语法分析是处理输入字符序列的软件构件, 编译器和解释器协同词法分析和语法分析来“解密” 程序文件。
使用递归下降语法解析,LL(k)。其中,第一个L表示从左到右扫描输入;第二个L表示每次都进行最左推导(在推导语法树的过程中每次都替换句型中最左的非终结符为终结符。类似还有最右推导);k表示的是每次向前探索(lookahead)k个终结符
词法规则,语法规则定义在同一文件中,就是.jj文件。
jjTree可以帮助更好的语法分析(因为好像没用过,不好说啊)
可定制生成的行为,如对字母的大小写是否敏感。不如设计数据库sql语句的时候应该使用关键字大小写不敏感。
更向前一步解决移进规约。当文法本身存在二义性的时候有时候通过设置lookahead为k能解决问题,带来的问题就是增加编译时间,所以最好的方法是修改二义性文法为无二义性文法。
参考:https://blog.csdn.net/newpidian/article/details/52964017