基于Java的SQL解析工具的比较与学习

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

 
 

你可能感兴趣的:(Calcite)