因为实习工作原因,需要学习SQLite的 源码。那我就寻思,干嘛不直接写一个呢,于是找了一个 资源,准备从无到有来过一下SQLite的框架。于是在这里做一个记录。
简介
SQLite,是一款轻型的数据库,是遵守ACID的关系数据库管理系统,SQLite是D.RichardHipp用C语言编写的开源嵌入式数据库引擎。它是完全独立的,不具有外部依赖性。它是作PHPV4.3中的一个选项引入的,构建在PHPV5中。SQLite支持多数SQL92标准,可以在所有主要的操作系统上运行,并且支持大多数计算机语言。
SQLite 对 SQL92 标准的支持包括索引、限制、触发和查看。SQLite 不支持外键限制,但支持原子的、一致的、独立的和持久的 (ACID) 事务。
区别于其他数据库引擎,SQLite引擎不是一个独立的进程,而是根据应用程序要求进行动态或静态连接到程序中成为它的一个主要部分。SQLite直接访问其存储文件。整个数据库(定义、表、索引和数据本身)都在宿主主机上存储在一个单一的文件中。
它包含在一个简介的C库中。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix 等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,与Mysql、PostgreSQL这两款开源的世界著名数据库管理系统相比,它的处理速度更快。SQLite第一个Alpha版本诞生于2000年5月。 至今已经有14个年头,SQLite也迎来了一个版本 SQLite 3已经发布。
查询经过一连串的组件才能检索或修改数据。所述前端包括的:
- 标记器(tokenizer)
- 解析器(parser)
- 代码生成器(code generator)
前端的输入是一个SQL查询。输出是sqlite虚拟机字节码(本质上是可以在数据库上运行的已编译程序)。
在后端组成的:
- 虚拟机(virtual machine)
- B树(B-tree)
- 分页组件(pager)
- 操作系统接口(os interface)
该虚拟机采用由前端的指令生成的字节代码。然后,它可以对一个或多个表或索引执行操作,每个表或索引都存储在称为B树的数据结构中。VM本质上是关于字节码指令类型的大开关语句。
每个B树由许多节点组成。每个节点的长度为一页。B树可以通过向分页组件发出命令来从磁盘检索页面或将其保存回磁盘。
该分页组件接收命令来读取或数据写入页。它负责以适当的偏移量在数据库文件中进行读取/写入。它还将最近访问的页面保留在内存中,并确定何时需要将这些页面写回到磁盘。
OS接口是根据操作系统源码编译为不同的层。
制作简单的REPL(read-execute-print loop)
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* buffer;
size_t buffer_length;
ssize_t input_length;
} InputBuffer;
InputBuffer* new_input_buffer() {
InputBuffer* input_buffer = malloc(sizeof(InputBuffer));
input_buffer->buffer = NULL;
input_buffer->buffer_length = 0;
input_buffer->input_length = 0;
return input_buffer;
}
void print_prompt() { printf("db > "); }
void read_input(InputBuffer* input_buffer) {
ssize_t bytes_read =
getline(&(input_buffer->buffer), &(input_buffer->buffer_length), stdin);
if (bytes_read <= 0) {
printf("Error reading input\n");
exit(EXIT_FAILURE);
}
// Ignore trailing newline
input_buffer->input_length = bytes_read - 1;
input_buffer->buffer[bytes_read - 1] = 0;
}
void close_input_buffer(InputBuffer* input_buffer) {
free(input_buffer->buffer);
free(input_buffer);
}
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) {
close_input_buffer(input_buffer);
exit(EXIT_SUCCESS);
} else {
printf("Unrecognized command '%s'.\n", input_buffer->buffer);
}
}
}