🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文 || 一分钟看完我的上千篇博客
🔥温馨提示:划到文末发现专栏彩蛋 点击这里直接传送
🔥本篇概览:数据库的前世今生 || 详细解了手写sqlite数据库Part 1——介绍sqlite与REPL。🌈⭕🔥
【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】
🌈序言
数据库乃我长久之志也,此关必过。今日既得之方向,应按此路学之习之,而长久不可懈怠。
前一系列文章详细讲解了XX,建议先将这部分知识掌握之后再来学习本篇内容,点击查看。
🔥 手写底层系列
1.夺命7连问:
数据以什么格式存储?存在哪里?
数据什么时候从内存存到磁盘?
为什么每一个表只能有一个主键?
事务回滚机制是怎样工作的?
索引是是怎么组织的?
全表扫描什么时候发生?怎样扫描的?
我们的sql查询语句是怎样保存与工作的?
总而言之?数据库系统是怎么工作的?
以上现在不会没关系,会在终章给出详尽的解答!
2.sqlite架构

下面逐步解释之:
(1)前端架构:
标记器(Tokenizer):
解析器(Parser):
代码生成器(Code Generator):
前端的输入是一个 SQL 查询。输出是 SQLite 虚拟机字节码(本质上是一个可以在数据库上运行的编译程序)。
(2)后端架构:
虚拟机(virtual machine):
虚拟机将前段生成的字节码作为指令,他够操作组织在B树上的一个或多个表或者索引。虚拟机本质上是一个关于字节码指令类型的大型 switch 语句。
B树(B-tree):
每一颗B树包含许多节点,每个节点的长度为一页。通过向页面管理器发送命令,B树能从磁盘上检索页面或者将页面存入磁盘。
页面管理器(pager):
页面管理器接受命令来读或写页面上的数据,他负责在数据库文件中的适当偏移处进行读取或写入,并且会在内存中保存最近使用的页面的缓存。他决定了这些页面什么时候需要被写回磁盘。
操作系统接口(os interface):
os接口是更具编译sqlite的操作系统而有所不同的层,会调用操作系统接口,完成操作硬件的功能。
3.REPL:读取执行打印循环
实现过程:
主体是一个mian无限循环,一直会读取用户输入的文本,这里输入是使用的自定义的getline()完成的,该函数返回输入的字符长度。参数为一个专门保存命令的结构体,输入的文本就保存在结构体的char*里面。后续对这里面的char* 进行解析就好了。
本节仅仅实现了判断退出(.exit)与空输入的情况。
(1)主体函数:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<stdbool.h>
#include <errno.h>
#include <stdint.h>
//#include "getline.h"
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
/*
* the data structure is for input token
*/
typedef struct {
char *buffer;
size_t buffer_length;//size_t equals to unsigned long long int
ssize_t input_length;//ssize_t equals to long long int
} InputBuffer;
/*
* just initialised a new buffer
* return the structure of buffer for containing the next input token
*/
InputBuffer *new_input_buffer() {//
InputBuffer *input_buffer = malloc(sizeof(InputBuffer));//dynamic memory in the heap
input_buffer->buffer = NULL;//the token chars haven't pointed to anything
input_buffer->buffer_length = 0;
input_buffer->input_length = 0;
return input_buffer;
}
void print_prompt() {
printf("EYKDB > ");//can be custom
}
/*
* input the token now!
* used the getline function
* two details:
* 1.replace the enter char with '\0' at the end
* 2.the real length must minus 1
*/
void read_input(InputBuffer *inputBuffer) {
ssize_t byte_read = getline(&(inputBuffer->buffer), &(inputBuffer->buffer_length), stdin);
if (byte_read <= 0) {
printf("Error reading input\n");
exit(EXIT_FAILURE);
}
inputBuffer->input_length = byte_read - 1;
inputBuffer->buffer[byte_read - 1] = 0;
}
/*
* free the dynamic memory allocated in the input_buffer(all the point's data should be free)
*/
void close_input_buffer(InputBuffer *input_buffer) {
free(input_buffer->buffer);
free(input_buffer);
}
/*
* main function: just a infinite loop
*/
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);
}
}
}
(2)getline函数:
/*
* the getline function
* lineptr :
* a pointer to the variable we use to point to the buffer containing the read line.
* If it set to NULL it is mallocatted by getline and should thus be freed by the user, even if the command fails.
*
* n :
* a pointer to the variable we use to save the size of allocated buffer.
*
* stream :
* the input stream to read from. We’ll be reading from standard input.
*
* return value :
* the number of bytes read, which may be less than the size of the buffer.
*/
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
size_t pos;
int c;
if (lineptr == NULL || stream == NULL || n == NULL) {
errno = EINVAL;
return -1;
}
c = getc(stream);
if (c == EOF) {
return -1;
}
if (*lineptr == NULL) {
*lineptr = malloc(128);
if (*lineptr == NULL) {
return -1;
}
*n = 128;
}
pos = 0;
while (c != EOF) {
if (pos + 1 >= *n) {
size_t new_size = *n + (*n >> 2);
if (new_size < 128) {
new_size = 128;
}
char *new_ptr = realloc(*lineptr, new_size);
if (new_ptr == NULL) {
return -1;
}
*n = new_size;
*lineptr = new_ptr;
}
((unsigned char *) (*lineptr))[pos++] = c;
if (c == '\n') {
break;
}
c = getc(stream);
}
(*lineptr)[pos] = '\0';
return pos;
}
4.运行结果:

📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!
👇下面是专栏彩蛋系列,你会喜欢的!👇
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖


被折叠的 条评论
为什么被折叠?



