乐趣区

关于数据库:一文走进-SQL-编译语义解析

一、概述 SQL

引擎次要由三大部分形成:解析器、优化器和执行器。解析器的次要作用是将客户端传来的命令解析编译成数据库能辨认运行的命令,其次要由词法解析、语法解析和语义解析三局部形成,如下图所示。

本文将重点介绍 KaiwuDB 语义解析局部,其输出为 AST 语法树,输入为可供优化器应用的 Expr 表达式。KaiwuDB 中的语义解析次要包含:

  • 查看数据库或表是否存在
  • 查看语句所需的特定权限
  • 对语句中的表达式进行语义解析
  • 查看 DDL 语句所申请的 schema change 的有效性

二、语义解析

KaiwuDB 中的语义解析次要包含以下流程:

  • 查看查问是否为 SQL 语言中的无效语句
  • 解析名称,例如表名或变量名的值
  • 打消不必要的两头计算,例如用 1.0 替换 0.6 + 0.4,这也被称为常数折叠
  • 确定用于两头后果的数据类型

其代码流程介于 parser 和 memo 构建之间,将 parser 输入的 AST 中的对象进行语义解析,语义解析的输入作为 memo 构建的输出。

接下来,将重点介绍查问语句的语义解析流程:

  • Source and target analysis(指标解析)
  • Permission check(权限校验)
  • Semantic decomposition & validation(表达式拆分及其语义解析)
  1. 指标解析及权限校验
    1)接口门路:buildStmt() -> buildSelectStmtWithoutParent() ->  buildSelectClause() -> builtFrom() -> buildDataSource()
    2)外围接口为:

    ResolveDataSource 通过 object name 解析出对象描述符(元数据),Privilege check 应用 current username 来校验以后用户对该对象是否有相应权限。
    在实现指标解析和权限校验后,会为 select stmt 中的 from clause 构建 memo 表达式。这个行为看似不是语义解析应该做的,呈现在这里的起因是 KaiwuDB 的语义解析和局部逻辑打算优化是互相交融的。

  2. 表达式拆分及其语义解析
    1)接口门路:buildStmt() -> buildSelectStmtWithoutParent() -> buildSelectClause()KaiwuDB 将 select stmt 中的各个局部拆分为表达式,并对其进行标量表达式的语义解析,从而实现 scalarExpr 的构建。例如:

    2)标量表达式语义解析:
    ROLE:查看表达式是否非法,为其做一些初步的优化,为其赋予类型。INTERFACE:
           in : Expr
           out : TypedExpr
           本质上是查看并赋予类型 + 简化表达式
           AnalyzeExpr()
    HOW:
           i. Name Resolution
           ii. TypeCheck
           iii. Normalize Expr
    这些子工作实现简直是纯正的函数,惟一的缺点是,TypeCheck 将 SQL 占位符($1、$2 等)的类型以一种对程序敏感的形式,输入到通过递归传递的语义环境对象上。
    留神:能够应用 EXPLAIN(EXPRS, TYPES) 来查看表达式,而不进行解构和简化。
    i. Name Resolution

    参数 sources 和 IndexedVars,如果都不是 nil,则示意 resolveNames 应该被执行。IndexedVars map 将被填充并且作为后果返回。
    · 用 parser.IndexedVar 实例替换列名
    · 用 parser.FuncDef 援用替换函数名

    ii. TypeCheck
    parser.TypeCheck() / parser.TypeCheckAndRequire():
    · 常数折叠
    · 类型推断
    · 类型查看
    · 在 ComparisonExpr 节点上记忆比拟器函数
    · 用其类型来正文表达式和占位符
    实现 Expr 接口的表达式有很多:AndExpr, OrExpr, CastExpr, CaseExpr 等。每个表达式都实现了 TypeCheck 接口,在被调用时返回后果表达式的类型,包含 bool, string, int 等。
    iii. Normalize
    parser.NormalizeExpr():
    留神:此处的 normalize 有点不太精确,因为他并没有进行规范的 normalize,这里只是将除变量名以外的货色都放到比拟符号的右侧,从而达到简化的目标。
    Normalize Example:
    · (a+1) < 3 is transformed to a < 2
    · -(a – b) is transformed to (b – a)
    · a between c and d is transformed to a >= c and a <= d

    Normalize 的实现次要依附 WalkExpr 函数。WalkExpr 会横穿 Expr,其通过传入对应的 visitor 来定义 WalkExpr 的具体行为,后面讲到的 name resolution 也是通过传入 name resolution visitor 实现的。上述就是 KaiwuDB 对于语义解析的介绍,欢送大家关注咱们的公众号,后续将陆续为大家介绍更多对于 SQL 编译的相干内容。

退出移动版