Skip to content

Commit

Permalink
feat: create a new REPL program for tinydb based on sql-parser
Browse files Browse the repository at this point in the history
Here is some TODOs.
  - sql-parser: support insert, update, delete, commit, rollback keywords.
  - db-kernel: support select-where, update-where, create-table.
  • Loading branch information
sinkinben committed Feb 1, 2022
1 parent 01e62c4 commit eb27ec4
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 61 deletions.
21 changes: 2 additions & 19 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <stdbool.h>
#include "table.h"
#include "types.h"
#include "statement.h"
#include "sql-vm/vm.h"
#include "debug.h"
#ifndef COMMON_H
#define COMMON_H
Expand Down Expand Up @@ -96,24 +96,7 @@ meta_command_result_t do_meta_command(buffer_t *input, table_t *table)
// 真正调用底层 API 执行 SQL, 相当于 sqlite 的 Core
execute_result_t execute_statement(statement_t *statement, table_t *table)
{
switch (statement->type)
{
case STATEMENT_INSERT:
return execute_insert(statement, table);
case STATEMENT_SELECT:
return execute_select(statement, table);
case STATEMENT_UPDATE:
return execute_update(statement, table);
case STATEMENT_DELETE:
return execute_delete(statement, table);
case STATEMENT_COMMIT:
return execute_commit(statement, table);
case STATEMENT_ROLLBACK:
return execute_rollback(statement, table);
default:
break;
}
return EXECUTE_UNKNOWN_STATEMENT;
return execute_vm(statement, table);
}

#endif
45 changes: 45 additions & 0 deletions main2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @brief This is the REPL program of tinydb, which is based on a sql parser.
*/
#include "sql-parser/sqlparser.h"
#include "common.h"
int main(int argc, char *argv[])
{
buffer_t *input = new_buffer_input();

if (argc < 2)
{
printf("Must supply a database filename.\n");
exit(EXIT_FAILURE);
}
char *filename = argv[1];
table_t *table = db_open(filename);
statement_t *stm = (statement_t *)malloc(sizeof(statement_t));

while (1)
{
print_prompt();
read_input(input);

/* If `input` is a meta command, then it will start with '.' */
if (input->buffer[0] == '.')
{
switch (do_meta_command(input, table))
{
case META_COMMAND_SUCCESS:
continue;
case META_COMMAND_UNRECOGNIZED_COMMAND:
printf("Unrecognized meta command '%s'\n", input->buffer);
continue;
}
}

/* Parse the SQL, and put the result in statement_t `stm` */
statement_init(stm);
sql_parser(input->buffer, stm);
execute_vm(stm, table);

// printf("stm->type = %d \n", stm->type);
// printf("row = (%u, %s, %s) \n", stm->row_value.id, stm->row_value.username, stm->row_value.email);
}
}
22 changes: 18 additions & 4 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
CC=clang -Wall -Wno-pointer-to-int-cast
build:
$(CC) main.c -o tinydb
CC=clang -Wall -Wno-pointer-to-int-cast -Wno-unused-function

PROJECT=$(shell pwd)
SQLPARSER=$(PROJECT)/sql-parser
SQLVM=$(PROJECT)/sql-v,

INCLUDE=-I$(PROJECT) -I$(SQLPARSER) -I$(SQLVM)

build: sqlparser
$(CC) $(INCLUDE) sqlparser.tab.c lex.yy.c main.c -o tinydb

clean:
rm *.db
rm *.db tinydb lex.yy.c *.tab.c *.tab.h

run:
make build
./tinydb mydb.db

sqlparser:
flex $(SQLPARSER)/sqlex.l
bison -d $(SQLPARSER)/sqlparser.y

test:
$(CC) test.c -o a.out
./a.out
6 changes: 3 additions & 3 deletions sql-parser/condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct condition_t
};
typedef struct condition_t condition_t;

static condition_t *alloc_condition(uint64_t lchild, operator_t op, uint64_t rchild, bool is_leaf)
static inline condition_t *alloc_condition(uint64_t lchild, operator_t op, uint64_t rchild, bool is_leaf)
{
condition_t *cond = (condition_t *)malloc(sizeof(condition_t));
cond->op = op;
Expand All @@ -52,7 +52,7 @@ static condition_t *alloc_condition(uint64_t lchild, operator_t op, uint64_t rch
return cond;
}

static void print_tree(condition_t *node, int depth)
static inline void print_tree(condition_t *node, int depth)
{
if (node == NULL)
return;
Expand All @@ -70,7 +70,7 @@ static void print_tree(condition_t *node, int depth)
}
}

static void destroy_tree(condition_t *node)
static inline void destroy_tree(condition_t *node)
{
printf("TODO: PLEASE implement me. \n");
assert(0);
Expand Down
7 changes: 4 additions & 3 deletions sql-parser/schema.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "../list.h"
#include "list.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifndef __SCHEMA_H__
#define __SCHEMA_H__

const uint32_t TBALE_COLUMN_NAME_MAX_LENGTH = 32;
static const uint32_t TBALE_COLUMN_NAME_MAX_LENGTH = 32;
typedef enum
{
DUMMY = -1,
Expand Down Expand Up @@ -32,7 +33,7 @@ struct schema_node_t
typedef struct schema_node_t schema_node_t;


schema_node_t *alloc_schema_node(const char *filedname, uint32_t width, column_type_t column_type)
static inline schema_node_t *alloc_schema_node(const char *filedname, uint32_t width, column_type_t column_type)
{
schema_node_t *node = (schema_node_t *)malloc(sizeof(schema_node_t));
strcpy(node->schema.fieldname, filedname);
Expand Down
7 changes: 4 additions & 3 deletions sql-parser/sqlparser.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#include "sql-statement/statement.h"
#ifndef __SQL_PARSER_H__
#define __SQL_PARSER_H__

typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern YY_BUFFER_STATE yy_scan_string(const char *);
extern void yy_delete_buffer(YY_BUFFER_STATE);
extern int yyparse();
extern int yyparse(void *);

static int sql_parser(const char *sql)
static int sql_parser(const char *sql, statement_t *stm)
{
YY_BUFFER_STATE buffer = yy_scan_string(sql);
int ret = yyparse(); /* 0 - Success, 1 - Fail */
int ret = yyparse((void *)(stm)); /* 0 - Success, 1 - Fail */
yy_delete_buffer(buffer);
return ret;
}
Expand Down
11 changes: 10 additions & 1 deletion sql-parser/sqlparser.y
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <assert.h>
#include "schema.h"
#include "condition.h"
#include "sql-statement/statement.h"

extern int yyparse();
extern int yylex();
Expand All @@ -16,8 +17,14 @@ condition_t *condition_tree; // select `select_list` from tbl where `condition_

int yywrap() { return 1; }

void yyerror(const char *msg) { fprintf(stderr, "error: %s\n", msg); }
void yyerror(const char *msg) { fprintf(stderr, "[tinydb] SQL Parser: %s\n", msg); }

#define YYPARSE_PARAM parm

/* `stm_ptr` is a pointer, that points to a statement_t struct,
* see `sql_parser()` in sqlparser.h
*/
#define stm_ptr ((statement_t *)(parm))

%}

Expand Down Expand Up @@ -72,6 +79,8 @@ selectsql:
{
printf("TODO: please select * from [%s] \n", $4);
printf("IDNAME = %p\n", $4);
stm_ptr->table_name = $4;
stm_ptr->type = STATEMENT_SELECT;
}
| SELECT selectitemlist FROM IDNAME ';'
{
Expand Down
41 changes: 41 additions & 0 deletions sql-statement/statement.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "sql-parser/condition.h"
#include "types.h"
#ifndef STATEMENT_H
#define STATEMENT_H

typedef enum
{
STATEMENT_INSERT,
STATEMENT_SELECT,
STATEMENT_UPDATE,
STATEMENT_DELETE,
STATEMENT_COMMIT,
STATEMENT_ROLLBACK
} statement_type_t;


typedef struct
{
statement_type_t type; /* SELECT, UPDATE, DELETE, etc. */
row_t row_value; /* The row value of INSERT SQL */
const char *table_name; /* table name */
schema_node_t *schemas; /* SELECT column items list */
condition_t *conditions; /* WHERE conditions */
} statement_t;

static inline void statement_init(statement_t *stm)
{
stm->type = -1;
stm->table_name = NULL;
stm->schemas = NULL;
stm->conditions = NULL;
memset(&(stm->row_value), 0, sizeof(row_t));
}

static inline void statement_free(statement_t *stm)
{
// TODO
assert(0);
}

#endif
28 changes: 26 additions & 2 deletions statement.h → sql-vm/vm.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include "types.h"
#include "cursor.h"
#include "transaction.h"
#ifndef STATEMENT_H
#define STATEMENT_H
#include "sql-statement/statement.h"
#ifndef TINYDB_VM_H
#define TINYDB_VM_H

/**
* The parsing result of a SQL statement sentence is stored in statement_t.
Expand Down Expand Up @@ -118,4 +119,27 @@ execute_result_t execute_rollback(statement_t *statement, table_t *table)
#endif
return EXECUTE_SUCCESS;
}

execute_result_t execute_vm(statement_t *statement, table_t *table)
{
switch (statement->type)
{
case STATEMENT_INSERT:
return execute_insert(statement, table);
case STATEMENT_SELECT:
return execute_select(statement, table);
case STATEMENT_UPDATE:
return execute_update(statement, table);
case STATEMENT_DELETE:
return execute_delete(statement, table);
case STATEMENT_COMMIT:
return execute_commit(statement, table);
case STATEMENT_ROLLBACK:
return execute_rollback(statement, table);
default:
break;
}
return EXECUTE_UNKNOWN_STATEMENT;
}

#endif
2 changes: 1 addition & 1 deletion sqlparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "types.h"
#ifndef SQL_PARSER_H
#define SQL_PARSER_H
/**
/** A Dummy SQL Parser By Hand
* This is equal to `SQL Compiler` module in sqlite.
* Here, we just compiler(parse) the sql by hands :-D .
* Parse the sql statements, and put the result in statement_t
Expand Down
1 change: 1 addition & 0 deletions transaction.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifdef OPEN_TRANSACTION
#include "list.h"
#include "types.h"
#include "sql-statement/statement.h"
#ifndef TRANSACTION_H
#define TRANSACTION_H
typedef struct
Expand Down
34 changes: 9 additions & 25 deletions types.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,6 @@ typedef enum
PARSE_UNRECOGNIZED_STATEMENT
} parse_result_t;

typedef enum
{
STATEMENT_INSERT,
STATEMENT_SELECT,
STATEMENT_UPDATE,
STATEMENT_DELETE,
STATEMENT_COMMIT,
STATEMENT_ROLLBACK
} statement_type_t;

// table 的一行
#define COLUMN_USERNAME_SIZE 32
Expand All @@ -46,23 +37,16 @@ typedef struct
} row_t;

#define size_of_attribute(Struct, Attribute) sizeof(((Struct *)0)->Attribute)
const uint32_t ID_SIZE = size_of_attribute(row_t, id);
const uint32_t USERNAME_SIZE = size_of_attribute(row_t, username);
const uint32_t EMAIL_SIZE = size_of_attribute(row_t, email);
const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;
static const uint32_t ID_SIZE = size_of_attribute(row_t, id);
static const uint32_t USERNAME_SIZE = size_of_attribute(row_t, username);
static const uint32_t EMAIL_SIZE = size_of_attribute(row_t, email);
static const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE;

#define offset_of_attribute(Struct, Attribute) ((uint32_t)(&((Struct *)0)->Attribute))
const uint32_t ID_OFFSET = offset_of_attribute(row_t, id);
const uint32_t USERNAME_OFFSET = offset_of_attribute(row_t, username);
const uint32_t EMAIL_OFFSET = offset_of_attribute(row_t, email);
static const uint32_t ID_OFFSET = offset_of_attribute(row_t, id);
static const uint32_t USERNAME_OFFSET = offset_of_attribute(row_t, username);
static const uint32_t EMAIL_OFFSET = offset_of_attribute(row_t, email);

// insert, select 等命令的解析结果
// 相当于一个简易的 sql-parser
typedef struct
{
statement_type_t type;
row_t row_value;
} statement_t;

typedef enum
{
Expand All @@ -73,9 +57,9 @@ typedef enum
EXECUTE_TABLE_FULL
} execute_result_t;

const uint32_t TABLE_MAX_PAGES = 1 << 20;
static const uint32_t TABLE_MAX_PAGES = 1 << 20;

const uint32_t PAGE_SIZE = 4096; // 4KB
static const uint32_t PAGE_SIZE = 4096; // 4KB
// const uint32_t ROWS_PER_PAGE = PAGE_SIZE / ROW_SIZE;
// const uint32_t TABLE_MAX_ROWS = TABLE_MAX_PAGES * ROWS_PER_PAGE;

Expand Down

0 comments on commit eb27ec4

Please sign in to comment.