├── README.md ├── Makefile ├── consts.h ├── input.h ├── pager.h ├── input.c ├── prepare.h ├── LICENSE ├── prepare.c ├── pager.c ├── tree.h └── db.c /README.md: -------------------------------------------------------------------------------- 1 | # simple-db-in-c 2 | build a simple database in C, just like SQLite 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | db: 2 | gcc *.c -o simple-db 3 | 4 | run: 5 | ./simple-db 6 | 7 | clean: 8 | rm -rf simple-db test.db 9 | 10 | format: *.c 11 | clang-format -style=Google -i *.c *.h 12 | -------------------------------------------------------------------------------- /consts.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_DB_C_CONSTS_H 2 | #define SIMPLE_DB_C_CONSTS_H 3 | 4 | #include "stdlib.h" 5 | 6 | #define TABLE_MAX_PAGES 100 7 | #define COLUMN_USERNAME_SIZE 32 8 | #define COLUMN_EMAIL_SIZE 255 9 | 10 | #define PAGE_SIZE 4096 11 | 12 | #endif // SIMPLE_DB_C_CONSTS_H 13 | -------------------------------------------------------------------------------- /input.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by roseduan on 2022/6/13. 3 | // 4 | 5 | #ifndef SIMPLE_DB_C_INPUT_H 6 | #define SIMPLE_DB_C_INPUT_H 7 | 8 | #include "stdio.h" 9 | #include "stdlib.h" 10 | 11 | typedef struct { 12 | char* buffer; 13 | size_t buffer_length; 14 | size_t input_length; 15 | } InputBuffer; 16 | 17 | InputBuffer* new_input_buffer(); 18 | void read_input(InputBuffer* input_buffer); 19 | void close_input_buffer(InputBuffer* input_buffer); 20 | 21 | #endif // SIMPLE_DB_C_INPUT_H 22 | -------------------------------------------------------------------------------- /pager.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_DB_C_PAGER_H 2 | #define SIMPLE_DB_C_PAGER_H 3 | 4 | #include "consts.h" 5 | #include "stdio.h" 6 | #include "stdlib.h" 7 | 8 | typedef struct { 9 | int file_descriptor; 10 | uint32_t file_length; 11 | uint32_t num_pages; 12 | void* pages[TABLE_MAX_PAGES]; 13 | } Pager; 14 | 15 | Pager* pager_open(const char* filename); 16 | void* get_page(Pager* pager, uint32_t page_num); 17 | void pager_flush(Pager* pager, uint32_t page_num); 18 | 19 | #endif // SIMPLE_DB_C_PAGER_H 20 | -------------------------------------------------------------------------------- /input.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by roseduan on 2022/6/13. 3 | // 4 | 5 | #include "input.h" 6 | 7 | #include "stdio.h" 8 | #include "stdlib.h" 9 | 10 | InputBuffer* new_input_buffer() { 11 | InputBuffer* input_buffer = malloc(sizeof(InputBuffer)); 12 | input_buffer->buffer = NULL; 13 | input_buffer->buffer_length = 0; 14 | input_buffer->input_length = 0; 15 | 16 | return input_buffer; 17 | } 18 | 19 | void read_input(InputBuffer* input_buffer) { 20 | ssize_t bytes_read = 21 | getline(&(input_buffer->buffer), &(input_buffer->buffer_length), stdin); 22 | if (bytes_read <= 0) { 23 | printf("Error readning input\n"); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | input_buffer->input_length = bytes_read - 1; 28 | input_buffer->buffer[bytes_read - 1] = 0; 29 | } 30 | 31 | void close_input_buffer(InputBuffer* input_buffer) { 32 | free(input_buffer->buffer); 33 | free(input_buffer); 34 | } 35 | -------------------------------------------------------------------------------- /prepare.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_DB_C_PREPARE_H 2 | #define SIMPLE_DB_C_PREPARE_H 3 | 4 | #include "consts.h" 5 | #include "input.h" 6 | #include "stdio.h" 7 | 8 | typedef enum { 9 | PREPARE_SUCCESS, 10 | PREPARE_SYNTAX_ERROR, 11 | PREPARE_NEGATIVE_ID, 12 | PREPARE_STRING_TOO_LONG, 13 | PREAPRE_UNRECOGNIZED_STATEMENT, 14 | } PrepareResult; 15 | 16 | typedef enum { 17 | STATEMENT_INSERT, 18 | STATEMENT_SELECT, 19 | } StatementType; 20 | 21 | typedef struct { 22 | uint32_t id; 23 | char username[COLUMN_USERNAME_SIZE + 1]; 24 | char email[COLUMN_EMAIL_SIZE + 1]; 25 | } Row; 26 | 27 | typedef struct { 28 | StatementType type; 29 | Row row_to_insert; 30 | } Statement; 31 | 32 | PrepareResult prepare_statement(InputBuffer* input_buffer, 33 | Statement* statement); 34 | PrepareResult prepare_insert(InputBuffer* input_buffer, Statement* statement); 35 | 36 | #endif // SIMPLE_DB_C_PREPARE_H 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 FlowerCorp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /prepare.c: -------------------------------------------------------------------------------- 1 | #include "prepare.h" 2 | 3 | #include "string.h" 4 | 5 | PrepareResult prepare_statement(InputBuffer* input_buffer, 6 | Statement* statement) { 7 | if (strncmp(input_buffer->buffer, "insert", 6) == 0) { 8 | statement->type = STATEMENT_INSERT; 9 | return prepare_insert(input_buffer, statement); 10 | } 11 | 12 | if (strncmp(input_buffer->buffer, "select", 6) == 0) { 13 | statement->type = STATEMENT_SELECT; 14 | return PREPARE_SUCCESS; 15 | } 16 | 17 | return PREAPRE_UNRECOGNIZED_STATEMENT; 18 | } 19 | 20 | PrepareResult prepare_insert(InputBuffer* input_buffer, Statement* statement) { 21 | char* keyword = strtok(input_buffer->buffer, " "); 22 | char* id_string = strtok(NULL, " "); 23 | char* username = strtok(NULL, " "); 24 | char* email = strtok(NULL, " "); 25 | 26 | if (id_string == NULL || username == NULL || email == NULL) { 27 | return PREPARE_SYNTAX_ERROR; 28 | } 29 | 30 | int id = atoi(id_string); 31 | if (id < 0) { 32 | return PREPARE_NEGATIVE_ID; 33 | } 34 | if (strlen(username) > COLUMN_USERNAME_SIZE) { 35 | return PREPARE_STRING_TOO_LONG; 36 | } 37 | if (strlen(email) > COLUMN_EMAIL_SIZE) { 38 | return PREPARE_STRING_TOO_LONG; 39 | } 40 | 41 | statement->row_to_insert.id = id; 42 | strcpy(statement->row_to_insert.username, username); 43 | strcpy(statement->row_to_insert.email, email); 44 | 45 | return PREPARE_SUCCESS; 46 | } 47 | -------------------------------------------------------------------------------- /pager.c: -------------------------------------------------------------------------------- 1 | #include "pager.h" 2 | 3 | #include "errno.h" 4 | #include "fcntl.h" 5 | #include "unistd.h" 6 | 7 | Pager* pager_open(const char* filename) { 8 | int fd = open(filename, O_RDWR | O_CREAT, 0644); 9 | if (fd == -1) { 10 | fprintf(stderr, "Unable to open file %s\n", filename); 11 | exit(EXIT_FAILURE); 12 | } 13 | 14 | off_t file_length = lseek(fd, 0, SEEK_END); 15 | 16 | Pager* pager = malloc(sizeof(Pager)); 17 | pager->file_descriptor = fd; 18 | pager->file_length = file_length; 19 | pager->num_pages = (file_length / PAGE_SIZE); 20 | if (file_length % PAGE_SIZE != 0) { 21 | printf("DB file is not a whole number of pages. Corrupt file.\n"); 22 | exit(EXIT_FAILURE); 23 | } 24 | 25 | for (uint32_t i = 0; i < TABLE_MAX_PAGES; i++) { 26 | pager->pages[i] = NULL; 27 | } 28 | 29 | return pager; 30 | } 31 | 32 | void* get_page(Pager* pager, uint32_t page_num) { 33 | if (page_num > TABLE_MAX_PAGES) { 34 | printf("Tried to fetch page number out of bounds.\n"); 35 | exit(EXIT_FAILURE); 36 | } 37 | 38 | if (pager->pages[page_num] == NULL) { 39 | void* page = malloc(PAGE_SIZE); 40 | 41 | uint32_t num_pages = pager->file_length / PAGE_SIZE; 42 | if (pager->file_length % PAGE_SIZE) { 43 | num_pages += 1; 44 | } 45 | 46 | if (page_num <= num_pages) { 47 | lseek(pager->file_descriptor, page_num * PAGE_SIZE, SEEK_SET); 48 | // check whether file have enough space 49 | ssize_t bytes_read = read(pager->file_descriptor, page, PAGE_SIZE); 50 | if (bytes_read == -1) { 51 | printf("Error reading file.\n"); 52 | exit(EXIT_FAILURE); 53 | } 54 | } 55 | 56 | pager->pages[page_num] = page; 57 | 58 | if (page_num >= pager->num_pages) { 59 | pager->num_pages = page_num + 1; 60 | } 61 | } 62 | 63 | return pager->pages[page_num]; 64 | } 65 | 66 | void pager_flush(Pager* pager, uint32_t page_num) { 67 | if (pager->pages[page_num] == NULL) { 68 | printf("Tried to flush null pages.\n"); 69 | exit(EXIT_FAILURE); 70 | } 71 | 72 | off_t offset = lseek(pager->file_descriptor, page_num * PAGE_SIZE, SEEK_SET); 73 | if (offset == -1) { 74 | printf("Error seeking: %d\n", errno); 75 | exit(EXIT_FAILURE); 76 | } 77 | 78 | ssize_t bytes_write = 79 | write(pager->file_descriptor, pager->pages[page_num], PAGE_SIZE); 80 | if (bytes_write == -1) { 81 | printf("Error writing: %d\n", errno); 82 | exit(EXIT_FAILURE); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tree.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLE_DB_C_TREE_H 2 | #define SIMPLE_DB_C_TREE_H 3 | 4 | #include "consts.h" 5 | #include "stdio.h" 6 | #include "stdlib.h" 7 | 8 | // same value with ROW_SIZE in db.c 9 | const uint32_t ROW_SIZ = 293; 10 | 11 | // Common Node Header Layout 12 | const uint32_t NODE_TYPE_SIZE = sizeof(uint8_t); 13 | const uint32_t NODE_TYPE_OFFSET = 0; 14 | const uint32_t IS_ROOT_SIZE = sizeof(uint8_t); 15 | const uint32_t IS_ROOT_OFFSET = NODE_TYPE_SIZE; 16 | const uint32_t PARENT_POINTER_SIZE = sizeof(uint32_t); 17 | const uint32_t PARENT_POINTER_OFFSET = IS_ROOT_OFFSET + IS_ROOT_SIZE; 18 | const uint8_t COMMON_NODE_HEADER_SIZE = 19 | NODE_TYPE_SIZE + IS_ROOT_SIZE + PARENT_POINTER_SIZE; 20 | 21 | // Leaf Node Header Layout 22 | const uint32_t LEAF_NODE_NUM_CELLS_SIZE = sizeof(uint32_t); 23 | const uint32_t LEAF_NODE_NUM_CELLS_OFFSET = COMMON_NODE_HEADER_SIZE; 24 | const uint32_t LEAF_NODE_HEADER_SIZE = 25 | COMMON_NODE_HEADER_SIZE + LEAF_NODE_NUM_CELLS_SIZE; 26 | 27 | // Leaf Node Body Layout 28 | const uint32_t LEAF_NODE_KEY_SIZE = sizeof(uint32_t); 29 | const uint32_t LEAF_NODE_KEY_OFFSET = 0; 30 | const uint32_t LEAF_NODE_VALUE_SIZE = ROW_SIZ; 31 | const uint32_t LEAF_NODE_VALUE_OFFSET = 32 | LEAF_NODE_KEY_OFFSET + LEAF_NODE_KEY_OFFSET; 33 | const uint32_t LEAF_NODE_CELL_SIZE = LEAF_NODE_KEY_SIZE + LEAF_NODE_VALUE_SIZE; 34 | const uint32_t LEAF_NODE_SPACE_FOR_CELLS = PAGE_SIZE - LEAF_NODE_HEADER_SIZE; 35 | const uint32_t LEAF_NODE_MAX_CELLS = 36 | LEAF_NODE_SPACE_FOR_CELLS / LEAF_NODE_CELL_SIZE; 37 | 38 | typedef enum { 39 | NODE_INTERNAL, 40 | NODE_LEAF, 41 | } NodeType; 42 | 43 | uint32_t* leaf_node_num_cells(void* node) { 44 | return node + LEAF_NODE_NUM_CELLS_OFFSET; 45 | } 46 | 47 | void* leaf_node_cell(void* node, uint32_t cell_num) { 48 | return node + LEAF_NODE_HEADER_SIZE + cell_num * LEAF_NODE_CELL_SIZE; 49 | } 50 | 51 | uint32_t* leaf_node_key(void* node, uint32_t cell_num) { 52 | return leaf_node_cell(node, cell_num); 53 | } 54 | 55 | void* leaf_node_value(void* node, uint32_t cell_num) { 56 | return leaf_node_cell(node, cell_num) + LEAF_NODE_KEY_SIZE; 57 | } 58 | 59 | void initialize_leaaf_node(void* node) { *leaf_node_num_cells(node) = 0; } 60 | 61 | void print_constants() { 62 | printf("ROW_SIZE: %d\n", ROW_SIZ); 63 | printf("COMMON_NODE_HEADER_SIZE: %d\n", COMMON_NODE_HEADER_SIZE); 64 | printf("LEAF_NODE_HEADER_SIZE: %d\n", LEAF_NODE_HEADER_SIZE); 65 | printf("LEAF_NODE_CELL_SIZE: %d\n", LEAF_NODE_CELL_SIZE); 66 | printf("LEAF_NODE_SPACE_FOR_CELLS: %d\n", LEAF_NODE_SPACE_FOR_CELLS); 67 | printf("LEAF_NODE_MAX_CELLS: %d\n", LEAF_NODE_MAX_CELLS); 68 | } 69 | 70 | void print_leaf_node(void* node) { 71 | uint32_t num_cells = *leaf_node_num_cells(node); 72 | printf("leaf (size %d)\n", num_cells); 73 | for (uint32_t i = 0; i < num_cells; i++) { 74 | uint32_t key = *leaf_node_key(node, i); 75 | printf(" - %d : %d\n", i, key); 76 | } 77 | } 78 | 79 | #endif // SIMPLE_DB_C_TREE_H 80 | -------------------------------------------------------------------------------- /db.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by roseduan on 2022/6/13. 3 | // 4 | 5 | #include "input.h" 6 | #include "pager.h" 7 | #include "prepare.h" 8 | #include "stdbool.h" 9 | #include "stdio.h" 10 | #include "stdlib.h" 11 | #include "string.h" 12 | #include "tree.h" 13 | #include "unistd.h" 14 | 15 | #define size_of_attribute(Struct, Attribute) sizeof(((Struct*)0)->Attribute) 16 | 17 | typedef enum { 18 | META_COMMAND_SUCCESS, 19 | META_COMMAND_UNRECOGNIZED_COMMAND, 20 | } MetaCommandResult; 21 | 22 | typedef enum { 23 | EXECUTE_SUCCESS, 24 | EXECUTE_TABLE_FULL, 25 | } ExecuteResult; 26 | 27 | const uint32_t ID_SIZE = size_of_attribute(Row, id); 28 | const uint32_t USERNAME_SIZE = size_of_attribute(Row, username); 29 | const uint32_t EMAIL_SIZE = size_of_attribute(Row, email); 30 | const uint32_t ID_OFFSET = 0; 31 | const uint32_t USERNAME_OFFSET = ID_OFFSET + ID_SIZE; 32 | const uint32_t EMAIL_OFFSET = USERNAME_OFFSET + USERNAME_SIZE; 33 | const uint32_t ROW_SIZE = ID_SIZE + USERNAME_SIZE + EMAIL_SIZE; 34 | 35 | typedef struct { 36 | Pager* pager; 37 | uint32_t root_page_num; 38 | } Table; 39 | 40 | typedef struct { 41 | Table* table; 42 | uint32_t page_num; 43 | uint32_t cell_num; 44 | bool end_of_table; 45 | } Cursor; 46 | 47 | MetaCommandResult do_meta_command(InputBuffer* input_buffer, Table* table); 48 | ExecuteResult execute_statement(Statement* statement, Table* table); 49 | 50 | void serialize_row(Row* source, void* destination); 51 | void deserialize_row(void* source, Row* destination); 52 | 53 | Table* db_open(const char* filename); 54 | void db_close(Table* table); 55 | 56 | Cursor* table_start(Table* table); 57 | Cursor* table_end(Table* table); 58 | 59 | void cursor_advance(Cursor* cursor); 60 | void* cursor_value(Cursor* cursor); 61 | 62 | void leaf_node_insert(Cursor* cursor, uint32_t key, Row* value); 63 | 64 | MetaCommandResult do_meta_command(InputBuffer* input_buffer, Table* table) { 65 | if (strcmp(input_buffer->buffer, ".exit") == 0) { 66 | close_input_buffer(input_buffer); 67 | db_close(table); 68 | exit(EXIT_SUCCESS); 69 | } else if (strcmp(input_buffer->buffer, ".btree") == 0) { 70 | printf("Tree : \n"); 71 | print_leaf_node(get_page(table->pager, 0)); 72 | return META_COMMAND_SUCCESS; 73 | } else if (strcmp(input_buffer->buffer, ".constants") == 0) { 74 | printf("Constants : \n"); 75 | print_constants(); 76 | return META_COMMAND_SUCCESS; 77 | } else { 78 | return META_COMMAND_UNRECOGNIZED_COMMAND; 79 | } 80 | } 81 | 82 | void print_row(Row* row) { 83 | printf("(%d %s %s)\n", row->id, row->username, row->email); 84 | } 85 | 86 | ExecuteResult execute_insert(Statement* statement, Table* table) { 87 | void* node = get_page(table->pager, table->root_page_num); 88 | if ((*leaf_node_num_cells(node) >= LEAF_NODE_MAX_CELLS)) { 89 | return EXECUTE_TABLE_FULL; 90 | } 91 | 92 | Row* row_to_insert = &(statement->row_to_insert); 93 | Cursor* cursor = table_end(table); 94 | 95 | leaf_node_insert(cursor, row_to_insert->id, row_to_insert); 96 | return EXECUTE_SUCCESS; 97 | } 98 | 99 | ExecuteResult execute_select(Statement* statement, Table* table) { 100 | if (table->root_page_num <= 101 | 0) { // todo: confirm whether it is the same as original code. 102 | return EXECUTE_SUCCESS; 103 | } 104 | 105 | Cursor* cursor = table_start(table); 106 | Row row; 107 | while (!cursor->end_of_table) { 108 | deserialize_row(cursor_value(cursor), &row); 109 | print_row(&row); 110 | cursor_advance(cursor); 111 | } 112 | return EXECUTE_SUCCESS; 113 | } 114 | 115 | ExecuteResult execute_statement(Statement* statement, Table* table) { 116 | switch (statement->type) { 117 | case (STATEMENT_INSERT): 118 | return execute_insert(statement, table); 119 | case (STATEMENT_SELECT): 120 | return execute_select(statement, table); 121 | } 122 | } 123 | 124 | void serialize_row(Row* source, void* destination) { 125 | memcpy(destination + ID_OFFSET, &(source->id), ID_SIZE); 126 | memcpy(destination + USERNAME_OFFSET, &(source->username), USERNAME_SIZE); 127 | memcpy(destination + EMAIL_OFFSET, &(source->email), EMAIL_SIZE); 128 | } 129 | 130 | void deserialize_row(void* source, Row* destination) { 131 | memcpy(&(destination->id), source + ID_OFFSET, ID_SIZE); 132 | memcpy(&(destination->username), source + USERNAME_OFFSET, USERNAME_SIZE); 133 | memcpy(&(destination->email), source + EMAIL_OFFSET, EMAIL_SIZE); 134 | } 135 | 136 | Table* db_open(const char* filename) { 137 | Pager* pager = pager_open(filename); 138 | 139 | Table* table = (Table*)malloc(sizeof(Table)); 140 | table->pager = pager; 141 | table->root_page_num = 0; 142 | 143 | if (pager->num_pages == 0) { 144 | void* root_node = get_page(pager, 0); 145 | initialize_leaaf_node(root_node); 146 | } 147 | return table; 148 | } 149 | 150 | void db_close(Table* table) { 151 | Pager* pager = table->pager; 152 | 153 | for (uint32_t i = 0; i < pager->num_pages; i++) { 154 | if (pager->pages[i] == NULL) { 155 | continue; 156 | } 157 | 158 | pager_flush(pager, i); 159 | free(pager->pages[i]); 160 | pager->pages[i] = NULL; 161 | } 162 | 163 | int close_res = close(pager->file_descriptor); 164 | if (close_res == -1) { 165 | printf("Error closing db file.\n"); 166 | exit(EXIT_FAILURE); 167 | } 168 | 169 | for (uint32_t i = 0; i < TABLE_MAX_PAGES; i++) { 170 | void* page = pager->pages[i]; 171 | if (page != NULL) { 172 | free(page); 173 | pager->pages[i] = NULL; 174 | } 175 | } 176 | 177 | free(pager); 178 | free(table); 179 | } 180 | 181 | Cursor* table_start(Table* table) { 182 | Cursor* cursor = malloc(sizeof(Cursor)); 183 | cursor->table = table; 184 | cursor->page_num = table->root_page_num; 185 | cursor->cell_num = 0; 186 | 187 | void* root_node = get_page(table->pager, table->root_page_num); 188 | uint32_t num_cells = *leaf_node_num_cells(root_node); 189 | cursor->end_of_table = (num_cells == 0); 190 | 191 | return cursor; 192 | } 193 | 194 | Cursor* table_end(Table* table) { 195 | Cursor* cursor = malloc(sizeof(Cursor)); 196 | cursor->table = table; 197 | cursor->page_num = table->root_page_num; 198 | 199 | void* root_node = get_page(table->pager, table->root_page_num); 200 | uint32_t num_cells = *leaf_node_num_cells(root_node); 201 | cursor->cell_num = num_cells; 202 | cursor->end_of_table = true; 203 | 204 | return cursor; 205 | } 206 | 207 | void cursor_advance(Cursor* cursor) { 208 | uint32_t page_num = cursor->page_num; 209 | void* node = get_page(cursor->table->pager, page_num); 210 | 211 | cursor->cell_num += 1; 212 | if (cursor->cell_num >= (*leaf_node_num_cells(node))) { 213 | cursor->end_of_table = true; 214 | } 215 | } 216 | 217 | void* cursor_value(Cursor* cursor) { 218 | uint32_t page_num = cursor->page_num; 219 | void* page = get_page(cursor->table->pager, page_num); 220 | return leaf_node_value(page, cursor->cell_num); 221 | } 222 | 223 | void leaf_node_insert(Cursor* cursor, uint32_t key, Row* value) { 224 | void* node = get_page(cursor->table->pager, cursor->page_num); 225 | uint32_t num_cells = *leaf_node_num_cells(node); 226 | 227 | if (num_cells > LEAF_NODE_MAX_CELLS) { 228 | printf("Need to implement splitting a leaf node.\n"); 229 | exit(EXIT_FAILURE); 230 | } 231 | 232 | if (cursor->cell_num < num_cells) { 233 | for (uint32_t i = num_cells; i > cursor->cell_num; i--) { 234 | memcpy(leaf_node_cell(node, i), leaf_node_cell(node, i - 1), 235 | LEAF_NODE_CELL_SIZE); 236 | } 237 | } 238 | 239 | *(leaf_node_num_cells(node)) += 1; 240 | *(leaf_node_key(node, cursor->cell_num)) = key; 241 | serialize_row(value, leaf_node_value(node, cursor->cell_num)); 242 | } 243 | 244 | void print_prompt() { printf("simple-db> "); } 245 | 246 | int main(int argc, char* argv[]) { 247 | if (argc < 2) { 248 | printf("Sorry, you must supply a database filename :)\n"); 249 | exit(EXIT_FAILURE); 250 | } 251 | 252 | char* filename = argv[1]; 253 | Table* table = db_open(filename); 254 | 255 | InputBuffer* input_buffer = new_input_buffer(); 256 | while (true) { 257 | print_prompt(); 258 | read_input(input_buffer); 259 | 260 | if (input_buffer->buffer[0] == '\0') { 261 | continue; 262 | } 263 | 264 | if (input_buffer->buffer[0] == '.') { 265 | switch (do_meta_command(input_buffer, table)) { 266 | case (META_COMMAND_SUCCESS): 267 | continue; 268 | case (META_COMMAND_UNRECOGNIZED_COMMAND): 269 | printf("Unrecognized command '%s'.\n", input_buffer->buffer); 270 | continue; 271 | } 272 | } 273 | 274 | Statement statement; 275 | switch (prepare_statement(input_buffer, &statement)) { 276 | case (PREPARE_SUCCESS): 277 | break; 278 | case (PREPARE_NEGATIVE_ID): 279 | printf("ID field must be positive.\n"); 280 | continue; 281 | case (PREPARE_STRING_TOO_LONG): 282 | printf("String field is too long.\n"); 283 | continue; 284 | case (PREPARE_SYNTAX_ERROR): 285 | printf("Syntax error. Cannot parse statement.\n"); 286 | continue; 287 | case (PREAPRE_UNRECOGNIZED_STATEMENT): 288 | printf("Unrecognized keyword at start of '%s'.\n", 289 | input_buffer->buffer); 290 | continue; 291 | } 292 | 293 | ExecuteResult exe_result = execute_statement(&statement, table); 294 | switch (exe_result) { 295 | case (EXECUTE_SUCCESS): 296 | printf("Executed\n"); 297 | break; 298 | case (EXECUTE_TABLE_FULL): 299 | printf("Error: Table full.\n"); 300 | break; 301 | } 302 | } 303 | } 304 | --------------------------------------------------------------------------------