实现一个简单的Database2(译文)


前文回顾:实现一个简单的Database1(译文)

译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运行的。本文是第二篇,主要是实现数据库的前端组件,编译器与虚拟机部分功能

Part 2 世界上最简单的SQL编译器与虚拟机

我们正在实现一个sqlite的克隆版本。sqlite的前端是SQL编译器,编译器用来解析字符串并输出一个内部的表示,叫做字节码。

这些字节码被传到虚拟机(virtual machine),在虚拟机中,字节码将被执行。

SQLite Architecture (https://www.sqlite.org/arch.html)

像这样把事情分成两个步骤(SQL编译和虚拟机)有以下两个优点:

  • 减少各个部分的复杂性(例如:虚拟机不用关心输入语句语法错误)
  • 允许只编译通用查询一次,然后对生成的字节码进行缓存,以此来提升性能

有了这些想法,让我们来重构主函数,在程序中支持了两个新的关键字:

译注:下面代码中行开头加减号是相对与第一部分(part 1)的实现,增加或者删除的代码。代码对main()重构以适合识别新关键字,在第一部分中,main()函数只能识别“.exit”关键字,也就是程序退出命令。

int main(int argc, char* argv[]) { InputBuffer* input_buffer = new_input_buffer(); while (true) { print_prompt(); read_input(input_buffer); - if (strcmp(input_buffer->buffer, ".exit") == 0) { - exit(EXIT_SUCCESS); - } else { - printf("Unrecognized command '%s'.n", input_buffer->buffer); + if (input_buffer->buffer[0] == '.') { + switch (do_meta_command(input_buffer)) { + case (META_COMMAND_SUCCESS): + continue; + case (META_COMMAND_UNRECOGNIZED_COMMAND): + printf("Unrecognized command '%s'n", input_buffer->buffer); + continue; + } } + + Statement statement; + switch (prepare_statement(input_buffer, &statement)) { + case (PREPARE_SUCCESS): + break; + case (PREPARE_UNRECOGNIZED_STATEMENT): + printf("Unrecognized keyword at start of '%s'.n", + input_buffer->buffer); + continue; + } + + execute_statement(&statement); + printf("Executed.n"); } }