Apache Calcite教程-SQL解析-Calcite SQL解析

Github

Calcite SQL解析

代码目录

如图:
在这里插入图片描述

config.fmpp

calcite 模板配置

Parser.jj

JavaCC解析器

parserImpls.ftl/compoundIdentifier.ftl

自定义JavaCC语法格式的解析SQL代码

生成解析器的流程

如图:
在这里插入图片描述

Sql解析使用

解析示例代码

public class SqlParserSample {
    public static void main(String[] args) throws SqlParseException {
        // Sql语句
        String sql = "select * from emps where id = 1";
        // 解析配置
        SqlParser.Config mysqlConfig = SqlParser.configBuilder().setLex(Lex.MYSQL).build();
        // 创建解析器
        SqlParser parser = SqlParser.create(sql, mysqlConfig);
        // 解析sql
        SqlNode sqlNode = parser.parseQuery();
        // 还原某个方言的SQL
        System.out.println(sqlNode.toSqlString(OracleSqlDialect.DEFAULT));
    }
}

解析流程

  1. 首先生成SQL解析器SqlParser.Config,SqlParser.Config中存在获取解析工厂类SqlParser.Config#parserFactory()方法,可以在SqlParser.configBuilder()配置类中设置解析工厂
  2. SqlParserImplFactory解析工厂中调用getParser方法获取解析器
  3. SqlAbstractParserImpl抽象解析器,JavaCC中生成的解析器的父类,Calcite中默认的解析类名为SqlParserImpl
  4. SqlParserImpl中,有静态字段FACTORY,主要是实现SqlParserImplFactory,并创建解析器
  5. SqlParser调用create方法,从SqlParser.Config中获取工厂SqlParserImplFactory,并创建解析器
  6. 调用SqlParser#parseQuery方法,解析SQL,最终调用SqlAbstractParserImpl(默认实现类SqlParserImpl)的parseSqlStmtEof或者parseSqlExpressionEof方法,获取解析后的抽象语法树SqlNode

Parser.jj 解析简单介绍

  1. 调用SqlParserImplFactorySqlAbstractParserImpl getParser(Reader stream);方法,解析获取解器,
    或者,直接调用SqlParser#parseQuery传入sql语句,解析器重新传入sqlparser.ReInit(new StringReader(sql));
  2. 解析器入口类SqlAbstractParserImpl#parseSqlExpressionEof或者SqlAbstractParserImpl#parseSqlStmtEof
  3. Parser.jj解析SQL语句入口SqlStmtEof() 解析SQL语句,直到文件结束符,SqlStmtEof()调用SqlStmt()
  4. SqlStmt()中定义各个类型的解析,例如 SqlExplain()(explain语句),OrderedQueryOrExpr()(select语句),之后解析各个关键字

常用类

Span

Span
SqlParserPos的建造者
具体使用还不太清楚

SqlAbstractParserImpl

SqlAbstractParserImpl
抽象解析器,Calcite所有的解析的父类,主要是设置一些解析的配置信息

SqlParseException

SqlParseException
SQL解析异常

SqlParser

SqlParser
解析SQL语句

SqlParserImplFactory

SqlParserImplFactory
解析器的工厂类接口,可以自定义解析工厂

SqlParserPos

SqlParserPos
表示SQL语句文本中已解析标记的位置

SqlParserUtil

SqlParserUtil
SQL解析工具类

SqlNode

SQL解析树,是所有解析的节点的父类
SqlNode

SqlCall

SqlCall

SqlCall是对操作符的调用.
操作符可以用来描述任何语法结构,因此在实践中,SQL解析树中的每个非叶节点都是某种类型的SqlCall

常用类子类

// update语句
SqlUpdate (org.apache.calcite.sql)
// insert语句
SqlInsert (org.apache.calcite.sql)
// case语句
SqlCase (org.apache.calcite.sql.fun)
// explain语句
SqlExplain (org.apache.calcite.sql)
// delete语句
SqlDelete (org.apache.calcite.sql)
// with 列语句,mysql不支持,oracle支持
SqlWithItem (org.apache.calcite.sql)
// merge语法,mysql不支持,oracle支持
SqlMerge (org.apache.calcite.sql)
// ddl语句中的check语句
SqlCheckConstraint (org.apache.calcite.sql.ddl)
// 保存所有的操作
SqlBasicCall (org.apache.calcite.sql)
// 模式匹配
SqlMatchRecognize (org.apache.calcite.sql)
// alter语句
SqlAlter (org.apache.calcite.sql)
// UNIQUE,PRIMARY KEY,FOREIGN KEY解析
SqlKeyConstraint (org.apache.calcite.sql.ddl)
// with语句
SqlWith (org.apache.calcite.sql)
// order by 语句
SqlOrderBy (org.apache.calcite.sql)
// DESCRIBE SCHEMA 语句
SqlDescribeSchema (org.apache.calcite.sql)
// ddl语句
SqlDdl (org.apache.calcite.sql)
// join语句
SqlJoin (org.apache.calcite.sql)
// window语句
SqlWindow (org.apache.calcite.sql)
// select语句
SqlSelect (org.apache.calcite.sql)
// 
SqlAttributeDefinition (org.apache.calcite.sql.ddl)
// DESCRIBE TABLE 语句
SqlDescribeTable (org.apache.calcite.sql)
// UNIQUE,PRIMARY KEY,FOREIGN KEY解析
SqlColumnDeclaration (org.apache.calcite.sql.ddl)
SqlLiteral

SqlLiteral

常量,表示输入的常量,需要返回值,则调用public Object getValue()方法,或者public <T> T getValueAs(Class<T> clazz)获取字段值

常用子类

INTERVAL '1' SECOND
INTERVAL '1:00:05.345' HOUR
INTERVAL '3:4' YEAR TO MONTH
SqlIdentifier

SqlIdentifier
Sql中的Id标示符

SqlNodeList

SqlNodeList
SqlNode的集合

SqlDataTypeSpec

SqlDataTypeSpec
SQL数据类型规范.

目前,它只支持简单的数据类型,如CHAR、VARCHAR和DOUBLE

SqlDynamicParam

SqlDynamicParam
表示SQL语句中的动态参数标记

SqlIntervalQualifier

SqlIntervalQualifier

标示区间定义

Examples include:

INTERVAL '1:23:45.678' HOUR TO SECOND
INTERVAL '1 2:3:4' DAY TO SECOND
INTERVAL '1 2:3:4' DAY(4) TO SECOND(4)

SqlKind

SqlKind
SqlNode类型

SqlOperator

SqlOperator
Sql解析的节点类型,包括:函数,操作符(=),语法结构(case)等操作

SqlOperatorTable

SqlOperatorTable
定义了一个用于枚举和查找SQL运算符(=)和函数(cast)的目录接口。

SqlStdOperatorTable

SqlStdOperatorTable
包含标准运算符和函数的SqlOperatorTable的实现

OracleSqlOperatorTable

OracleSqlOperatorTable
仅包含Oracle特定功能和运算符的运算符表

SqlParser.Config 配置信息

配置项

public interface Config {
    /** 默认配置. */
    Config DEFAULT = configBuilder().build();

    /**
     * 最大字段长度
     */
    int identifierMaxLength();

    /**
     * 转义内 大小写转换
     */
    Casing quotedCasing();

    /**
     * 转义字符外 大小写转换
     */
    Casing unquotedCasing();

    /**
     * 转义字符符号
     */
    Quoting quoting();

    /**
     * 大小写匹配 - 在planner内生效
     */
    boolean caseSensitive();

    /**
     * sql模式
     */
    SqlConformance conformance();
    
    @Deprecated // to be removed before 2.0
    boolean allowBangEqual();

    /**
     * 解析工厂类
     */
    SqlParserImplFactory parserFactory();
}

默认配置项

public static class ConfigBuilder {
    // Casing.UNCHANGED
    private Casing quotedCasing = Lex.ORACLE.quotedCasing;
    // Quoting.DOUBLE_QUOTE
    private Casing unquotedCasing = Lex.ORACLE.unquotedCasing;
    // Casing.TO_UPPER
    private Quoting quoting = Lex.ORACLE.quoting;
    // 128
    private int identifierMaxLength = DEFAULT_IDENTIFIER_MAX_LENGTH;
    // true
    private boolean caseSensitive = Lex.ORACLE.caseSensitive;
    // Calcite's default SQL behavior.
    private SqlConformance conformance = SqlConformanceEnum.DEFAULT;
    // 解析工厂类
    private SqlParserImplFactory parserFactory = SqlParserImpl.FACTORY;
}

代码示例

https://github.com/quxiucheng/apache-calcite-tutorial/tree/master/calcite-tutorial-2-parser/parser-3-calcite-tutorial

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache Calcite是一个灵活的SQL解析器框架,可以用于解析和优化SQL查询语句,支持多种数据库,包括MySQL、Oracle、SQL Server、PostgreSQL等。下面是Apache Calcite使用方法: 1. 引入依赖 在项目的pom.xml文件中添加Apache Calcite的依赖: ```xml <dependency> <groupId>org.apache.calcite</groupId> <artifactId>calcite-core</artifactId> <version>1.26.0</version> </dependency> ``` 2. 创建SQL解析使用Apache CalciteSQL解析器,可以将SQL语句解析成AST(抽象语法树)。AST是一种用于表示SQL语句结构的数据结构,可以用于进一步分析和优化SQL查询语句。 ```java import org.apache.calcite.sql.*; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserConfig; import org.apache.calcite.sql.parser.SqlParserImplFactory; public class SqlParserDemo { public static void main(String[] args) throws SqlParseException { String sql = "SELECT * FROM my_table WHERE id = 1"; SqlParserConfig config = SqlParser.configBuilder() .setParserFactory(new SqlParserImplFactory()) .build(); SqlParser parser = SqlParser.create(sql, config); SqlNode node = parser.parseQuery(); System.out.println(node.getClass().getSimpleName()); } } ``` 以上代码演示了如何创建一个SQL解析器,解析一个SELECT语句,并输出AST的类型。 3. 访问AST AST是一个树形结构,可以使用Visitor模式来访问AST的节点。Apache Calcite提供了许多访问AST节点的Visitor类,可以方便地遍历AST的节点。 ```java import org.apache.calcite.sql.*; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserConfig; import org.apache.calcite.sql.parser.SqlParserImplFactory; public class SqlParserDemo { public static void main(String[] args) throws SqlParseException { String sql = "SELECT * FROM my_table WHERE id = 1"; SqlParserConfig config = SqlParser.configBuilder() .setParserFactory(new SqlParserImplFactory()) .build(); SqlParser parser = SqlParser.create(sql, config); SqlNode node = parser.parseQuery(); node.accept(new SqlBasicVisitor<Void>() { @Override public Void visit(SqlIdentifier id) { System.out.println(id.getName()); return null; } }); } } ``` 以上代码演示了如何访问AST的节点,使用SqlBasicVisitor类来访问SqlIdentifier节点,并输出节点的名称。 4. 优化查询 AST可以用于进一步优化SQL查询语句。Apache Calcite提供了许多优化器,可以根据AST的结构进行优化,例如选择最优的执行计划、推导查询条件、消除冗余计算等。 ```java import org.apache.calcite.adapter.java.JavaTypeFactory; import org.apache.calcite.plan.*; import org.apache.calcite.prepare.CalcitePrepareImpl; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.schema.SchemaPlus; import org.apache.calcite.sql.*; import org.apache.calcite.sql.parser.SqlParseException; import org.apache.calcite.sql.parser.SqlParser; import org.apache.calcite.sql.parser.SqlParserConfig; import org.apache.calcite.sql.parser.SqlParserImplFactory; import org.apache.calcite.sql2rel.SqlToRelConverter; import org.apache.calcite.tools.*; import org.apache.calcite.util.Util; public class SqlParserDemo { public static void main(String[] args) throws SqlParseException { String sql = "SELECT * FROM my_table WHERE id = 1"; SchemaPlus schema = Frameworks.createRootSchema(true); FrameworkConfig config = Frameworks.newConfigBuilder() .defaultSchema(schema) .parserConfig(SqlParser.configBuilder() .setParserFactory(new SqlParserImplFactory()) .build()) .build(); Planner planner = Frameworks.getPlanner(config); SqlNode node = planner.parse(sql); SqlValidator validator = planner.getValidator(); SqlNode validatedNode = validator.validate(node); RelDataTypeFactory typeFactory = planner.getTypeFactory(); JavaTypeFactory javaTypeFactory = new JavaTypeFactoryImpl(typeFactory); SqlToRelConverter.Config converterConfig = SqlToRelConverter.configBuilder() .withTrimUnusedFields(false) .build(); SqlToRelConverter converter = new SqlToRelConverter( new CalcitePrepareImpl.PlannerImpl(planner, converterConfig), validator, schema, javaTypeFactory, converterConfig); RelNode relNode = converter.convertQuery(validatedNode, false, true); RelOptPlanner optPlanner = relNode.getCluster().getPlanner(); optPlanner.setRoot(relNode); RelTraitSet traitSet = optPlanner.emptyTraitSet().plus(RelCollations.EMPTY); RelNode optimizedNode = optPlanner.findBestExp(traitSet, relNode); System.out.println(Util.toLinux(optimizedNode.toString())); } } ``` 以上代码演示了如何使用Apache Calcite进行SQL查询语句的优化。首先创建一个Planner对象,然后使用Planner解析和验证SQL语句。接着使用SqlToRelConverter将SQL语句转换为RelNode对象,最后使用RelOptPlanner进行优化,得到最优的执行计划。 以上就是Apache Calcite使用方法,你可以根据需要使用它来解析和优化SQL查询语句。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值