文章同步更新于 Notion

写在前面

Shell

  • 程序运行之后,参数由 Shell 接受,并给其他组件下发任务,其中更新语句由下述函数处理

    int dongmendb_shell_handle_update_data(dongmendb_shell_handle_sql_t *ctx, const char *sqlupdate);
  • 函数首先调用 Tokenizer 与 Parser 模块,对输入的SQL语句进行分析与处理,以便转换成后台能理解的指令

Tokenizer

  • Tokenizer 的类型值在 Token 头文件种进行定义,制定了 Token 的合法元组,头文件同时定义了 Token 类,包含一个字符串 text 与一个元组值 TokenType
  • Tokenizer 类创建了一个 SQL 指令副本,记为 inputStream,同时创建了一个 buffer 字符串用以逐步分析
  • Tokenizer 用于将输入的字符串分割为标记(Token),进而将标记进行分类(TokenType)的过程。生成的标记随后便被用来进行解析(Paser)

Paser

  • 在得到了 Tokenizer 分析之后,就到了包装调用 Tokenizer 数据的 Paser 模块

  • Paser 包括几个关键:一个 Tokenizer 数据,还有下述几个迭代 Token 的函数

    Token *parseNextToken(); // 返回最近的非 NULL 的 Token,若 当前Token 为 NULL,返回下一个,否则返回当前 Token
    Token *parseEatToken(); // 强行赋值当前 Token 为 NULL,并且返回 NULL
    Token *parseEatAndNextToken(); // 返回下一个非 NULL 的 Token
    int matchToken( TokenType type, char *text); // 用以比较当前 Token 与 一个字符串是否是欲匹配的类型,其中类型必须在 TokenType 元组中,TOKEN_RESERVED_WORD 为关键字,在 Tokenizer 的 isReservedWord 方法中进行甄别

SRA

  • SRA_t 是一种关系表达式数据结构,这个东东貌似是生成一个简要的任务信息,程序会根据该参数提供的类型进行不同的扫描类型,Update 要使用到的便是 ExecutionPlan 提供的 generateScan 创建一个虚拟(alias)的执行子表

执行流程

数据库SQL语句的执行流程大概如下面这个流程图所示

nUA0bt.png

Update 分词解析

  • 首先我们要让程序理解 SQL 的执行要求,所以有几个数据必须要得到
    • 数据表:tableName
    • set 的键域:fields
    • set 的值域:fieldsExpr
    • 作用域: where(SRA类型)
  • 下一步肯定是要匹配关键字 update,这里使用的就是 matchToken方法,接下来就是匹配表名了,匹配成功就调用 new_id_name 分配空间并复制
  • 在匹配 set 关键字的时候应该注意的是要吃掉当前的字符并且下移一位,不然当前 Token 还会是表名从而一直都匹配失败
  • 接下来进行的就是读取键值对了,由于键值对有不确定个,所以使用 vector 进行数据管理,其中键就是字符串集和,但是值的存储要使用 Expression * 类型,用以兼容支持替换的值是表达式的情况
  • 循环匹配的时候,只对合法字符解析,其中 TOKEN_COMMA 匹配分隔符,值 的解析交由 parseExpressionRD 进行
  • 最后是寻找作用域,先创建一个子表,便于后面表扫描。由于作用域的表示也可以是一个表达式,所以也是一个 Expression 进行表达,将解析后的结果包装成一个关系表达式(SRA_t),便于后续的Select

Update 物理执行

  • 首先,要对解析的结果进行拆包,得到数据表名、修改的键值对、关系数据表达式
  • 通过 ExecutionPlan 的 generateScan 模块根据类型不同创建扫描计划
  • 遍历扫描数据表进行修改数据

解析执行流程

nUuMWV.png

标签: 数据库

添加新评论