Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Calcite系列(六):执行流程-语法解析

Calcite系列(六):执行流程-语法解析

原创
作者头像
Yiwenwu
修改于 2024-05-12 09:00:33
修改于 2024-05-12 09:00:33
8210
举报
文章被收录于专栏:Calcite剖析Calcite剖析

解析流程

语法解析是SQL处理的第一步,主要由词法分析和语法分析两个步骤组成:

  • 词法分析:分词操作,基于生成工具(正则文法+有限状态自动机DFA)将SQL分词为Token(词法记号),并识别Token为关键字、标识符、标识符、字面量等
  • 语法分析:识别出AST的树状语法结构,可基于递归下降算法(自顶向下)构造,其中根节点(RootNode)可代表整个语法树

目前广泛使用的语法解析框架主要包括ANTLR、JavaCC和Yacc等。在大数据领域中,很多计算引擎都是基于ANTLR进行语法解析,例如 Hive、Spark和Presto等都基于ANTLR进行处理。然而,Calcite使用JavaCC编译器进行语法解析。

在Calcite中,Parser.jj是最核心的词法&语法分析文件。为了便于语法扩展,支持基于FMPP(Apache FreeMarker)模板动态生成Parser.jj,主要涉及以下三个文件:

  1. config.fmpp:FreeMarker配置文件,描述可扩展的解析配置,包括:解析包名/类名、类引用、keywords(关键字)、nonReservedKeywords(非保留关键字)等常见定义
  2. xxx.ftl:FreeMarker模板文件,描述Java生成类的结构和内容,包括:类定义、方法定义、变量定义等
  3. Parser.jj:JavaCC模板文件,可结合FreeMarker模板替换生成,最终通过JavaCC编译生成对应的解析器源码

解析流程如下图所示:基于FreeMarker作为模板,整合config.fmpp、xxxx.ftl、Parser.jj文件,生成JavaCC可识别的词法语法文件,JavaCC编译该文件生成对应的SQL解析器源码。

解析框架

JavaCC描述文件格式(Parser.jj模板文件)的定义格式如下:

代码语言:java
AI代码解释
复制
options {
    JavaCC的选项
}

PARSER_BEGIN(解析器类名) # 即是SqlAbstractParserImpl实现
package 包名;
import 库名;

public class 解析器类名 {
    任意的Java代码,解析类方法
}

PARSER_END(解析器类名)

词法分析器
语法分析器

Calcite中定义的核心解析类方法

  • parseSqlStmtEof:解析单个SQL Statement,获取Root AST Node (SqlNode)
  • parseSqlStmtList: 解析SQL Statement列表

词法分析器

词法分析器:定义Token解析器,基于正则文法匹配对应类型,分为四类:

  1. SKIP:词法解析忽略处理
  2. MORE:需继续读取下一个文本符
  3. TOKEN:匹配TOKEN
  4. SPECIAL_TOKEN:提前定义的字符,不参与解析操作,如结束符

示例如下所示:

代码语言:txt
AI代码解释
复制
SKIP : { " " }
SKIP : { "\n" | "\r" | "\r\n" }
TOKEN : { < PLUS : "+" > }
TOKEN : { < NUMBER : (["0"-"9"])+ > } #正则匹配数字

语法分析器

语法分析器:由BNF范式构成,定义TOKEN序列解析规则(推导规则),类似于Java方法,定义格式示例如下:

代码语言:java
AI代码解释
复制
SqlNodeList ParenthesizedKeyValueOptionCommaList() :
{
    # 定义方法常量
    final Span s;
    final List<SqlNode> list = new ArrayList<SqlNode>();
}
{
    # 方法调用
    { s = span(); }
    # TOKEN正则匹配
    <LPAREN>
    KeyValueOption(list)
    (
        <COMMA>
        KeyValueOption(list)
    )*    # 循环匹配处理
    <RPAREN> 
    # 返回处理结果
    {return new SqlNodeList(list, s.end(this));}
}

编译生成的Java代码如下:

代码语言:java
AI代码解释
复制
final public SqlNodeList ParenthesizedKeyValueOptionCommaList() throws ParseException {
  final Span s;
  final List<SqlNode> list = new ArrayList<SqlNode>();
  s = span();
  jj_consume_token(LPAREN);
  KeyValueOption(list);
  label_21:
  while (true) {
    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { # 预读下一个Token
    case COMMA:
      break;
    default:
      jj_la1[182] = jj_gen;
      break label_21;
    }
    jj_consume_token(COMMA);
    KeyValueOption(list);
  }
  jj_consume_token(RPAREN);
      {if (true) return new SqlNodeList(list, s.end(this));}
  throw new Error("Missing return statement in function");
}

方法说明:

  • jj_consume_token:真读Token,从Token流读取并移除该Token
  • jj_ntk:预读Token,进行回溯匹配

语法正则映射关系:

  • <token值> : Token匹配读取,对应 jj_consume_token(token值);
  • | :对应 if 或者 switch的判断条件,或判断
  • (...)* :对应while循环语句,支持0次或多次匹配,直到满足break标识;
  • (...)+ :对应while循环语句,支持1次或多次匹配,直到满足break标识;
  • (...) :对应处理逻辑,1次匹配,支持final字段的初始赋值;如果没有指定<token值>,则默认匹配所有TOKEN;如果多个 | (或判断)没有匹配,switchdefault 抛出异常;
  • (...)?:对应判断操作匹配0-1次,如果多个 | (或判断)没有匹配,switch default 不抛出异常;
  • [...] :对应判断匹配0-1次,与(...)?类似

抽象语法树

在Calcite中,基于SqlNode表示AST抽象语法树,一个SqlNode可对应语法树中的一个节点,即对应SQL语句中的一个元素。SqlNode是一个抽象类,拥有许多子类,每个子类代表SQL语法中一类元素,主要包括:

  1. SqlCall:代表SQL运算符(operator)调用,有很多关系运算相关的扩展子类,如 SqlJoin、SqlFilter;也可以用于描述语法结构,如 SELECT(SqlSelect)、INSERT(SqlInsert)
  2. SqlIdentifier:代表 SQL标识符,例如表名、列名等
  3. SqlLiteral:代表 SQL字面量,例如字符串、数字、日期等
  4. SqlDataTypeSpec:代表数据类型规范,描述数据类型的各种属性,包括基本类型、精度、字符集等

在Calcite中,SqlOperator代表SQL语句中的运算符,可通过SqlCall调用执行,其子类包括:数学运算符、比较运算符、逻辑运算符、自定义SQL函数(SqlFunction)

如图所示:一条SQL语句基于SqlParser解析后,转换为SqlNode语法树结构

总结

语法解析是SQL处理的前提和基础,目前由于不同的计算引擎SQL方言不同,因此SQL解析处理模式也大相径庭。从整体上看,SQL解析将SQL转为AST抽象语法树,该语法树是朴素的,无元数据绑定的,也无法直接进行查询优化。但基于语法树遍历,也可以挖掘丰富的SQL执行信息,如目标库表、数据血缘、防御SQL注入攻击、热度分析等。除此之外,基于语法树也可以进行SQL改写处理,识别特定节点并变更后,再将语法树转为改写后的SQL执行。

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
分布式 | DBLE 之 SQL 解析
今天我们主要来谈谈 SQL 解析,SQL 的全称为 Structured Query Language,即结构化查询语言,既然定义为语言,那其实它和任何其他语言都是平等的。所以对 SQL 的解析完全等同于对任何一门语言的解析,对编程语言的解析这就涉及到编译原理相关知识了。
爱可生开源社区
2020/05/06
5190
javacc功能一览
1.编译原理中常见的解析器LL和LR的对比;2.javacc的特征;3.如何在java ide中进行javacc的开发;4.通过演示一个javacc计算器的例子让你对javacc有更多了解(只是一个简单地演示,不涉及过多的语法说明)。
山行AI
2020/11/10
2K0
javacc功能一览
Hive源码系列(六)编译模块之词法、语法解析 (上)
词法、语法解析模块会先介绍一下antlr环境(上)。然后举实际案例说明怎么使用antlr工具、利用antlr生成的Lexer、Parser、TreeParser代码,获取asttree。这些都是hive获取asttree的过程,理解了这些,再理解hive的asttree就很容易了(中)。 最后 详细介绍hive词法、语法解析的源码 以及hive AstTree的使用 (下)
数据仓库践行者
2020/04/18
1.2K0
Calcite系列(五):执行流程-概览
SQL执行流程有一套通用的步骤,尽管具体的实现可能会因数据库系统的不同而有所差异,但流程相对固定。以下是通用的SQL处理流程:
Yiwenwu
2024/04/18
4870
如何实现一个SQL解析器
随着技术的不断的发展,在大数据领域出现了越来越多的技术框架。而为了降低大数据的学习成本和难度,越来越多的大数据技术和应用开始支持SQL进行数据查询。SQL作为一个学习成本很低的语言,支持SQL进行数据查询可以降低用户使用大数据的门槛,让更多的用户能够使用大数据。
2020labs小助手
2022/10/24
2.6K0
统一元数据:数据血缘
数据血缘(Data Lineage):是数据治理中元数据管理领域下的一个子范畴,是数据的溯源过程,获得数据产生链路,发现数据的关联关系,目的是解决"数据的哲学三问":我是谁,我从哪里来,我到哪里去。
Yiwenwu
2024/05/10
2.9K1
统一元数据:数据血缘
Apache Calcite 功能简析及在 Flink 的应用
• Apache Calcite 是一个动态数据的管理框架,可以用来构建数据库系统的语法解析模块
KyleMeow
2018/09/02
7.9K0
Apache Calcite 功能简析及在 Flink 的应用
看这篇就够了丨基于Calcite框架的SQL语法扩展探索
Calcite 在大数据系统中有着广泛的运用,比如 Apache Flink, Apache Drill 等都大量使用了 Calcite,理解 Calcite 的原理可以说已经成为理解大数据系统中 SQL 访问层实现原理的必备条件之一。
袋鼠云数栈
2023/01/12
4.6K0
TiDB SQL Parser 的实现
其中,SQL Parser的功能是把SQL语句按照SQL语法规则进行解析,将文本转换成抽象语法树(AST),这部分功能需要些背景知识才能比较容易理解,我尝试做下相关知识的介绍,希望能对读懂这部分代码有点帮助。
mazhen
2023/11/24
6270
TiDB SQL Parser 的实现
flink sql 知其所以然(六)| flink sql 约会 calcite(看这篇就够了)
全网第一个 flink sql 实战,本文主要介绍 flink sql 与 calcite 之间的关系。flink sql 的解析主要依赖 calcite。
公众号:大数据羊说
2022/04/04
2.4K0
flink sql 知其所以然(六)| flink sql 约会 calcite(看这篇就够了)
编译原理初学者入门指南
作者:pixelcao,腾讯 IEG 后台开发工程师 一、引子 最近的工作需要用表达式做一些参数的配置,然后发现大脑一片空白,在 Google 里试了几个关键词(起初搜了下“符号引擎”,发现根本不是我想要的)之后,明白过来自己应该是需要补一些编译原理的知识了。在掉了两晚上头发之后,决定整理一下自己的知识网络。 要解析的表达式大概长这个样子: avg(teams[*].players.attributes[skill])*rules[latency].maxLatency 正则表达式是个办法,但不是最优
腾讯技术工程官方号
2021/01/21
2.5K0
Antlr4实战:统一SQL路由多引擎
ANTLR是一款功能强大的语法分析器生成器,可用来读取、处理、执行和转换结构化文本或二进制文件。它被广泛应用于学术界和工业界构建各种语言、工具和框架。Antlr在Hadoop整个生态系统应用较为广泛,如Hive 词法文件是Antlr3写的;Presto词法文件也Antlr4实现的;SparkSQL词法文件是用Presto的词法文件改写的;还有HBase的访问客户端Phoenix也用Antlr工具进行SQL解析的等等。
用户7600169
2022/04/25
10.1K1
Antlr4实战:统一SQL路由多引擎
【Flink】第二十八篇:Flink SQL 与 Apache Calcite
【Flink】第四篇:【迷思】对update语义拆解D-、I+后造成update原子性丢失
章鱼carl
2022/03/31
2.4K0
【Flink】第二十八篇:Flink SQL 与 Apache Calcite
用 Antlr 重构脚本解释器
在上一个版本实现的脚本解释器 GScript 中实现了基本的四则运算以及 AST 的生成。
crossoverJie
2022/10/27
7950
用 Antlr 重构脚本解释器
基于Calcite自定义SQL解析器
这本应该是《我也能写数据库》系列文章中的一篇,但是最近一直在反思这个系列标题是不是有点不亲民,所以,暂时放弃这个系列标题了。
麒思妙想
2020/07/10
3.4K0
85.精读《手写 SQL 编译器 - 智能提示》
词法、语法、语义分析概念都属于编译原理的前端领域,而这次的目的是做 具备完善语法提示的 SQL 编辑器,只需用到编译原理的前端部分。
黄子毅
2022/03/14
4K0
85.精读《手写 SQL 编译器 - 智能提示》
编译入门 - 从零实现中文计算器
“如果你不知道编译器咋工作的你就不知道电脑是咋工作的。” -- STEVE YEGGE
羽月
2022/10/08
7880
编译入门 - 从零实现中文计算器
Calcite - 看懂 Parser.jj 中的 SqlSelect
javacc 会根据 parser.jj 中定义的相互穿插的 Token、Java 代码来自动生成 org.apache.calcite.sql.parser.impl.SqlParserImpl 的代码。本文期望以一个简单的 Select 语句为例来说清楚 Sql 语句、Sql 语法定义、SqlParser 之间的关系。
codingforfun
2021/05/17
2.2K0
Calcite - 看懂 Parser.jj 中的 SqlSelect
使用Calcite做Sql语法解析
Flink SQL中使用Calcite作为sql语法解析、校验、优化工具,本篇是实操篇,介绍一下calcite做sql语法解析使用方式。
Flink实战剖析
2022/04/18
3.2K0
打破国外垄断,开发中国人自己的编程语言(1):编写解析表达式的计算器
本文是《打破国外垄断,开发中国人自己的编程语言》系列文章的第1篇。本系列文章的主要目的是教大家学会如何从零开始设计一种编程语言(marvel语言),并使用marvel语言开发一些真实的项目,如移动App、Web应用等。marvel语言可以通过下面3种方式运行:
蒙娜丽宁
2020/07/30
2.4K1
打破国外垄断,开发中国人自己的编程语言(1):编写解析表达式的计算器
相关推荐
分布式 | DBLE 之 SQL 解析
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文