jsqlparser(一):基于抽象语法树(AST)遍历SQL语句的语法元素

4 篇文章 0 订阅

jsqlparser是一个java的SQL语句解析器,基于它可以实现很多之前无法完成的工作。

		<!-- maven 依赖库引用 -->
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>4.5</version>
        </dependency

比如如下的SQL语句:

SELECT person.id,person.name,group.name  FROM person JOIN group ON person.group_id = group.id WHERE person.birthdate > '1980-01-01'

在MySQL中执行没有任何问题,但是如果用phoenix在HBase数据库中执行,语法是过不去的。因为phoenix中默认字段名,表名都是大写的,如果指定小写的字段和表名,需要加双引号.

SELECT "person"."id","person"."name","group"."name"  FROM "person" JOIN "group" ON "person"."group_id" = "group"."id" WHERE "person"."birthdate" > '1980-01-01'

对于一个SQL语句如何能根据数据库的要求为字段名和表名自动加引号或双引号,就需要用到jsqlparser这个利器。

jsqlparser解析一个SQL语句后会生成一个抽象语法树(AST-- Abstract Syntax Tree)对象SimpleNode,并提供了用于遍历AST的接口CCJSqlParserVisitor,应用层只要实现这个接口我们就可以通过接口方法得到想要的SQL语法元素节点对象,比如ColumnTable。当然还可以根据实际需要干点别的。
以下就以为字段名和表名加双引号为例,说明如何用CCJSqlParserVisitor来遍历所有AST节点

	@Test
	public void test10ParseVisitor() throws ParseException {
	    String sql = "SELECT person.id,person.name,group.name  FROM person JOIN group ON person.group_id = group.id WHERE person.birthdat > '1980-01-01'";
		/** 创建SQL语句解析器实例 */
		CCJSqlParser parser = CCJSqlParserUtil.newParser(sql);
		/** 解析SQL语句 */
        Statement stmt = parser.Statement();
		/** 使用 LogVisiter对象遍历AST的所有节点 */
        parser.getASTRoot().jjtAccept(new LogVisitor(), null);
		
		System.out.printf("sql--> %s",stmt);
	}
	
	/**
	 * 遍历所有节点的{@link net.sf.jsqlparser.parser.CCJSqlParserVisitor} 接口实现类
	 * @author guyadong
	 *
	 */
	static class LogVisitor extends CCJSqlParserDefaultVisitor{
        @Override
        public Object visit(SimpleNode node, Object data) {
            Object value = node.jjtGetValue();
            /** 根据节点类型找出表名和字段名节点,对名字加上双引号 */
            if (node.getId() == CCJSqlParserTreeConstants.JJTCOLUMN) {            	
                System.out.printf("column %s",value.toString());
                Column column = (Column)value;
                column.setColumnName("\"" + column.getColumnName() + "\"");
                Table table = column.getTable();
                if(null != table){
                    table.setName("\"" + table.getName() + "\"");
                }
            } else if (node.getId() == CCJSqlParserTreeConstants.JJTTABLE) {
                System.out.printf("table %s",value.toString());
                Table table = (Table)value;
                if(null != table){
                    table.setName("\"" + table.getName() + "\"");
                }
            }else if(null != value){
            	/** 其他类型节点输出节点类型值,Java类型和节点值 */
                System.out.printf("%d %s %s",node.getId(),value.getClass().getSimpleName(),value.toString());
            }
            return super.visit(node, data);
        }
    }

输出:

6 PlainSelect SELECT person.id, person.name, group.name FROM person JOIN group ON person.group_id = group.id WHERE person.birthdat > ‘1980-01-01’
9 SelectExpressionItem person.id
column person.id
9 SelectExpressionItem person.name
column person.name
9 SelectExpressionItem group.name
column group.name
table person
10 Join JOIN group ON person.group_id = group.id
table group
14 EqualsTo person.group_id = group.id
column person.group_id
column group.id
14 GreaterThan person.birthdat > ‘1980-01-01’
column person.birthdat
20 StringValue ‘1980-01-01’
sql–> SELECT “person”.“id”, “person”.“name”, “group”.“name” FROM “person” JOIN “group” ON “person”.“group_id” = “group”.“id” WHERE “person”.“birthdat” > ‘1980-01-01’

从上面最后一行输出可以看到,jsqlparser已经精确的将SQL语句中所有表名和字段名都自动加了双引号。

参考资料

《Parsing table and column names from SQL/HQL Java》

jsqlparser系列文章

《jsqlparser(一):基于抽象语法树(AST)遍历SQL语句的语法元素》
《jsqlparser(二):实现基于SQL语法分析的SQL注入攻击检查》
《jsqlparser(三):基于语法分析实现SQL中的CAST函数替换》
《jsqlparser(四):实现MySQL 函数DATE_FORMAT到Phoenix函数TO_CHAR的替换》
《jsqlparser(五):修改语法定义(JSqlParserCC.jjt)实现UPSERT支持Phoenix语法ON DUPLICATE KEY IGNORE》

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
jsqlparser可以用来识别SQL语句中的函数。具体来说,可以使用以下步骤来实现: 1. 创建一个实现ExpressionVisitor接口的类,用于访问SQL语句中的各种表达式。 2. 使用CCJSqlParserManager类中的parse方法来解析SQL语句,将其转换为Statement对象。 3. 使用Statement对象中的accept方法,将上面创建的ExpressionVisitor对象传递给它,然后调用该方法以开始遍历SQL语句的各个部分。 4. 在ExpressionVisitor类中覆盖visit方法,以处理不同类型的表达式,包括函数。在visit方法中,您可以检查当前表达式是否是函数,并从中提取所需的信息。 下面是一个简单的示例,演示如何在SQL语句中识别函数: ```java import java.io.StringReader; import net.sf.jsqlparser.expression.Function; import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.select.Select; import net.sf.jsqlparser.statement.select.PlainSelect; public class SqlFunctionParser { public static void main(String[] args) throws JSQLParserException { String sql = "SELECT COUNT(*) FROM mytable WHERE myfunc(col1) > 5"; CCJSqlParserManager parserManager = new CCJSqlParserManager(); Statement statement = parserManager.parse(new StringReader(sql)); Select select = (Select) statement; PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); plainSelect.getWhere().accept(new ExpressionVisitorAdapter() { @Override public void visit(Function function) { System.out.println("Found function: " + function.getName()); System.out.println("Function parameters: " + function.getParameters()); } }); } } ``` 在上面的示例中,我们解析了一个包含函数的SQL语句,并使用ExpressionVisitorAdapter类来访问WHERE子句中的表达式。在visit方法中,我们检查每个表达式是否是函数,并打印出其名称和参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

10km

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值