闲来无事,写个数据库吧(2)

项目地址  How Does a Database Work? | Let’s Build a Simple Database

我们要写个sqlite,须知sqlite的“前端”是一个SQL编译器,它解析字符串并输出称为字节码的内部表示形式。

经历了前端后,在传输到虚拟机并到后端。

这样将分成两个步骤有几个优点:

  • 降低每个部分的复杂性(例如,虚拟机不担心语法错误)
  • 允许编译一次常见查询并缓存字节码以提高性能。

我们已经有了第一节课的空框架了,接下来我们要完成识别insert、select的功能

首先,我们要怎么判断输入的是不是合法命令?

合法命令有两种,一种是sql命令,另一种是元命令(比如.exit)。我们判断两种命令的依据是输入的第一个字符是否为'.'。

我们现在要加两个关键字select 和insert。在这里,我们先假设输入select就能输出所有内容,而insert后面得再输入数据(先不管它是什么)。所以这里我们用strcmp函数及strncmp函数判断输入。判断以后生成对应状态,然后再根据状态输出”insert“、”select“。

这里给大家一点点思考的时间,如果是你,你会怎么设计?


我们定义Statement表示状态,StatementType表示状态类型

typedef enum { STATEMENT_INSERT, STATEMENT_SELECT } StatementType;

typedef struct {
  StatementType type;
} Statement;

我们用MetaCommandResult判断是否为元命令,用PrepareResult判断是否为sql命令

typedef enum {
  META_COMMAND_SUCCESS,
  META_COMMAND_UNRECOGNIZED_COMMAND
} MetaCommandResult;

typedef enum { PREPARE_SUCCESS, PREPARE_UNRECOGNIZED_STATEMENT } PrepareResult;

之前的判断.exit太占main函数了,我们将其变成函数调用

MetaCommandResult do_meta_command(InputBuffer* input_buffer) {
  if (strcmp(input_buffer->buffer, ".exit") == 0) {
    exit(EXIT_SUCCESS);
  } else {
    return META_COMMAND_UNRECOGNIZED_COMMAND;
  }
}

预处理select、insert函数识别

PrepareResult prepare_statement(InputBuffer* input_buffer,
                                Statement* statement) {
  if (strncmp(input_buffer->buffer, "insert", 6) == 0) {
    statement->type = STATEMENT_INSERT;
    return PREPARE_SUCCESS;
  }
  if (strcmp(input_buffer->buffer, "select") == 0) {
    statement->type = STATEMENT_SELECT;
    return PREPARE_SUCCESS;
  }

  return PREPARE_UNRECOGNIZED_STATEMENT;
}

最后用switch把状态输出

void execute_statement(Statement* statement) {
  switch (statement->type) {
    case (STATEMENT_INSERT):
      printf("This is where we would do an insert.\n");
      break;
    case (STATEMENT_SELECT):
      printf("This is where we would do a select.\n");
      break;
  }
}

main函数改改,先判断命令类型,再判断预处理类型,如果正确最后再执行命令。

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");

最后代码长这样

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum {
  META_COMMAND_SUCCESS,
  META_COMMAND_UNRECOGNIZED_COMMAND
} MetaCommandResult;

typedef enum { 
 PREPARE_SUCCESS,
 PREPARE_UNRECOGNIZED_STATEMENT
} PrepareResult;

typedef enum { 
STATEMENT_INSERT, 
STATEMENT_SELECT
} StatementType;

typedef struct {
  StatementType type;
} Statement;

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;
}

PrepareResult prepare_statement(InputBuffer* input_buffer,
                                Statement* statement) {
  if (strncmp(input_buffer->buffer, "insert", 6) == 0) {
    statement->type = STATEMENT_INSERT;
    return PREPARE_SUCCESS;
  }
  if (strcmp(input_buffer->buffer, "select") == 0) {
    statement->type = STATEMENT_SELECT;
    return PREPARE_SUCCESS;
  }

  return PREPARE_UNRECOGNIZED_STATEMENT;
}

void execute_statement(Statement* statement) {
  switch (statement->type) {
    case (STATEMENT_INSERT):
      printf("This is where we would do an insert.\n");
      break;
    case (STATEMENT_SELECT):
      printf("This is where we would do a select.\n");
      break;
  }
}

void print_prompt() { printf("sqlite>"); }

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);
}

MetaCommandResult do_meta_command(InputBuffer* input_buffer) {
  if (strcmp(input_buffer->buffer, ".exit") == 0) {
    exit(EXIT_SUCCESS);
  } else {
    return META_COMMAND_UNRECOGNIZED_COMMAND;
  }
}

int main(int argc, char* argv[]) {
  InputBuffer* input_buffer = new_input_buffer();
  while (true) {
    print_prompt();
    read_input(input_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");
    
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
社区闲置共享系统需要设计一个数据库来保存用户信息、商品信息、订单信息等数据。以下是一个简单的数据库设计方案: 1. 用户表(User):保存用户信息,包括用户ID、用户名、密码、邮箱、电话等。 | 字段名称 | 数据类型 | 描述 | | -------- | -------- | ---- | | user_id | int | 用户ID,主键 | | username | varchar | 用户名 | | password | varchar | 密码 | | email | varchar | 邮箱 | | phone | varchar | 电话 | 2. 商品表(Product):保存商品信息,包括商品ID、商品名称、商品描述、价格、发布者ID等。 | 字段名称 | 数据类型 | 描述 | | ----------- | -------- | ---- | | product_id | int | 商品ID,主键 | | product_name| varchar | 商品名称 | | description | varchar | 商品描述 | | price | float | 商品价格 | | user_id | int | 发布者ID,外键,关联用户表的user_id字段 | 3. 订单表(Order):保存订单信息,包括订单ID、商品ID、买家ID、卖家ID、订单状态等。 | 字段名称 | 数据类型 | 描述 | | --------- | -------- | ---- | | order_id | int | 订单ID,主键 | | product_id| int | 商品ID,外键,关联商品表的product_id字段 | | buyer_id | int | 买家ID,外键,关联用户表的user_id字段 | | seller_id | int | 卖家ID,外键,关联用户表的user_id字段 | | status | int | 订单状态,0表示待支付,1表示已支付,2表示已完成 | 以上是一个简单的数据库设计方案,实际上还需要根据具体需求进行调整和完善。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_51275728

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值