JAVA使用Apcahe Calcite 解析sql

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: JAVA使用Apcahe Calcite 解析sql

Apcahe Calcite 简介

Apcahe Calcite是一个基于SQL语法的查询引擎,可以使用sql语句查询多种数据源,例如csv,mongodb,redis等等,

主要功能

  • 标准SQL解析和校验:行业标准的 SQL 解析器、验证器和 JDBC 驱动程序。
  • 查询优化:在关系代数中表示查询,使用计划规则进行转换,并根据成本模型进行优化。
  • 任何数据,任务地方:连接到第三方数据源,浏览元数据,并通过将计算推送到数据进行优化。
Calcite是一个sql引擎,通常使用是使用对应的工具包例如calcite-redis,calcite-mongodb用于异构数据源sql查询支持。sql解析只是其中一个部分,下面的代码仅仅是解析sql部分的demo。

sql解析示例

        String sqlStr = "SELECT\n" +
                "\tsu.dept_id `deptId`,\n" +
                "\tsu.user_id,\n" +
                "\tsr.role_id,\n" +
                "\tsu.user_name,\n" +
                "\tsd.dept_name,\n" +
                "\tsr.role_name\n" +
                "FROM\n" +
                "\tsys_user AS su\n" +
                "JOIN sys_dept sd ON su.dept_id = sd.dept_id\n" +
                "JOIN sys_user_role sur ON sur.user_id = su.user_id\n" +
                "JOIN sys_role sr ON sur.role_id = sr.role_id\n" +
                "WHERE\n" +
                "\tsd.dept_name = '研发部门'\n" +
                "\tand su.user_name = 'admin'\n" +
                "\tand su.dept_id = 103\n" +
                "\tor sr.role_name = '超级管理员'\n" +
                "ORDER BY\n" +
                "\tsd.create_time DESC";
        SqlNode sqlNode = SqlParser.create(sqlStr, SqlParser.config().withLex(Lex.MYSQL)).parseQuery();
        sqlNode.accept(new SqlBasicVisitor<String>() {
            public String visit(SqlCall call) {
                if (call.getKind().equals(SqlKind.SELECT)) {
                    SqlSelect select = (SqlSelect) call;
                    log.info("--------------查询列名----------------------------------------");
                    select.getSelectList().forEach(colum -> {
                        if (SqlKind.AS.equals(colum.getKind())) {
                            SqlBasicCall basicCall = (SqlBasicCall) colum;
                            log.info("{} as {}", basicCall.getOperandList().get(0).toString(), basicCall.getOperandList().get(1).toString());
                        } else if (SqlKind.IDENTIFIER.equals(colum.getKind())) {
                            log.info(colum.toString());
                        }
                    });
                    log.info("--------------From Table Info----------------------------------------");
                    select.getFrom().accept(new SqlBasicVisitor<String>() {
                        public String visit(SqlCall call) {
                            if (call.getKind().equals(SqlKind.JOIN)) {
                                SqlJoin join = (SqlJoin) call;
                                log.info("join.getRight:{},join.getCondition{}", join.getRight().toString(), join.getCondition().toString());
                                if (!join.getLeft().getKind().equals(SqlKind.JOIN)) {
                                    log.info("join.getLeft:{}", join.getLeft().toString());
                                }
                            }
                            return call.getOperator().acceptCall(this, call);
                        }
                    });
                    log.info("--------------Where  Info-----------------------------------------");
                    select.getWhere().accept(new SqlBasicVisitor<String>() {
                        public String visit(SqlCall call) {
                            if (call.getKind().equals(SqlKind.AND) || call.getKind().equals(SqlKind.OR)) {
                                SqlBasicCall sql = (SqlBasicCall) call;
                                SqlBasicCall left = (SqlBasicCall) sql.getOperandList().get(0);
                                SqlBasicCall right = (SqlBasicCall) sql.getOperandList().get(1);
                                log.info("kind:{},right:{}", sql.getKind(), right);
                                if (!left.getKind().equals(SqlKind.AND) && !left.getKind().equals(SqlKind.OR)) {
                                    log.info("left:{}", left);
                                }
                            }
                            return call.getOperator().acceptCall(this, call);
                        }
                    });
                    log.info("--------------增加查询条件----------------------------------------");
                    try {
                        SqlNode condition = SqlParser.create("1=1").parseExpression();
                        SqlNode where = SqlUtil.andExpressions(select.getWhere(),condition);
                        select.setWhere(where);
                    } catch (SqlParseException e) {
                        throw new RuntimeException(e);
                    }
                    log.info("语句:{}", select);
                }
                return call.getOperator().acceptCall(this, call);
            }
        });
  • SqlUtil.andExpressions:拼接查询条件。
  • SqlParser:sql转换器,将sql字符串转换为sql语法树
  • SqlNode:sql语法树基础元素

    • SqlParserPos:为当前元素在sql语法树中位置
    • SqlKind:节点类型
  • SqlCall:语句节点,用于判断语句类型
  • SqlBasicCall:最小单位的完整sql节点例如AS,JOIN,AND等
  • SqlBasicVisitor:访问器,泛型为返回值,直接返回即获得指定元素,包含多个访问器其中参数为SqlCall的可以访问完整元素所以使用此方法。

    • T visit(SqlCall call):访问SqlCall元素,返回值call.getOperator().acceptCall(this, call)递归调用。

参考资料

https://calcite.apache.org/docs/tutorial.html

目录
相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
7天前
|
Java
轻松上手Java字节码编辑:IDEA插件VisualClassBytes全方位解析
本插件VisualClassBytes可修改class字节码,包括class信息、字段信息、内部类,常量池和方法等。
52 6
|
5天前
|
存储 算法 Java
Java Set深度解析:为何它能成为“无重复”的代名词?
Java的集合框架中,Set接口以其“无重复”特性著称。本文解析了Set的实现原理,包括HashSet和TreeSet的不同数据结构和算法,以及如何通过示例代码实现最佳实践。选择合适的Set实现类和正确实现自定义对象的hashCode()和equals()方法是关键。
18 4
|
8天前
|
Java 编译器 数据库连接
Java中的异常处理机制深度解析####
本文深入探讨了Java编程语言中异常处理机制的核心原理、类型及其最佳实践,旨在帮助开发者更好地理解和应用这一关键特性。通过实例分析,揭示了try-catch-finally结构的重要性,以及如何利用自定义异常提升代码的健壮性和可读性。文章还讨论了异常处理在大型项目中的最佳实践,为提高软件质量提供指导。 ####
|
8天前
|
SQL 监控 安全
员工上网行为监控软件:SQL 在数据查询监控中的应用解析
在数字化办公环境中,员工上网行为监控软件对企业网络安全和管理至关重要。通过 SQL 查询和分析数据库中的数据,企业可以精准了解员工的上网行为,包括基础查询、复杂条件查询、数据统计与分析等,从而提高网络管理和安全防护的效率。
20 0
|
SQL Java 关系型数据库
V$SQLAREA解析
V$SQLAREA lists statistics on shared SQL area and contains one row per SQL string.
817 0
|
2月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
4月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
111 13
|
4月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
4月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
60 6

推荐镜像

更多