diff --git a/Language.txt b/Language.txt index 4f8204c..4ef7cf7 100644 --- a/Language.txt +++ b/Language.txt @@ -17,7 +17,7 @@ DropStmt = 'Drop Table', Identifier ; ColumnSpecList = ColumnSpec | ColumnSpecList, ',', ColumnSpec ; ColumnSpec = Identifier, ColumnType | Identifier, ColumnType, ColumnOption ; -ColumnType = 'String', '(', number, ')' | 'Int' | 'Integer' ; +ColumnType = 'String', '(', integer, ')' | 'Int' | 'Integer' ; ColumnOption = 'Index' ; FieldList = Identifier | FieldList, ',', Identifier ; @@ -29,4 +29,4 @@ Comparison = Identifier, Comparator, Value; Comparator = '=' | '<>'; Identifier = { letter, '_' } , { letter | digit | '_' } ; -Value = "'", string, "'" | '"', string, '"' | number ; \ No newline at end of file +Value = "'", string, "'" | '"', string, '"' | integer ; \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8a14030..5956a61 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,7 @@ add_library(SDBLib STATIC scanner.c scanner.h parser.c parser.h bplus_tree.c bplus_tree.h - ../lib/MurmurHash3.c ../lib/MurmurHash3.h random.c random.h) + ../lib/MurmurHash3.c ../lib/MurmurHash3.h random.c random.h Table.c Table.h) add_executable(SDB main.c) target_link_libraries(SDB SDBLib) \ No newline at end of file diff --git a/src/SQL.c b/src/SQL.c index 2d00412..84ddfa3 100644 --- a/src/SQL.c +++ b/src/SQL.c @@ -5,12 +5,15 @@ #include #include #include +#include #include "SQL.h" +#include "MurmurHash3.h" +#include "random.h" Value *new_value() { Value *value = malloc(sizeof(Value)); value->type = VALUE_NONE; - value->number = 0; + value->integer = 0; value->string = NULL; return value; } @@ -32,7 +35,7 @@ Comparison *new_comparison() { void free_comparison(Comparison *comparison) { if (comparison->value != NULL) { - free(comparison->value); + free_value(comparison->value); } if (comparison->identifier != NULL) { free(comparison->identifier); @@ -50,7 +53,7 @@ ComparisonGroup *new_comparision_group() { void free_comparison_group(ComparisonGroup *group) { if (group->length > 0) { for (size_t i = 0; i < group->length; i++) { - free(group->comparisons[i]); + free_comparison(group->comparisons[i]); } free(group->comparisons); group->length = 0; @@ -131,6 +134,8 @@ void append_field_list(FieldList *list, char *field) { ColumnSpec *new_column_spec() { ColumnSpec *spec = malloc(sizeof(ColumnSpec)); + spec->id = 0; + spec->rowOffset = 0; spec->identifier = NULL; spec->option = COLOPT_NONE; spec->size = 0; @@ -145,6 +150,17 @@ void free_column_spec(ColumnSpec *spec) { free(spec); } +size_t column_spec_data_size(ColumnSpec *spec) { + switch (spec->type) { + case COLTYPE_CHAR: + return (sizeof(char) * spec->size) + 1; + case COLTYPE_INT: + return sizeof(uint64_t); + default: + return 0; + } +} + ColumnSpecList *new_column_spec_list() { ColumnSpecList *list = malloc(sizeof(ColumnSpecList)); list->length = 0; @@ -427,8 +443,8 @@ void print_comparison_group(ComparisonGroup *group) { void print_column_spec_list(ColumnSpecList *list) { for (size_t i = 0; i < list->length; i++) { ColumnSpec *spec = list->columns[i]; - if (spec->type == COLTYPE_STRING) { - printf("%s STRING(%ld)", spec->identifier, spec->size); + if (spec->type == COLTYPE_CHAR) { + printf("%s CHAR(%ld)", spec->identifier, spec->size); } else if (spec->type == COLTYPE_INT) { printf("%s INTEGER", spec->identifier); } @@ -469,7 +485,7 @@ void print_value(Value *value) { } } printf("'"); - } else if (value->type == VALUE_NUMBER) { - printf("%ld", value->number); + } else if (value->type == VALUE_INTEGER) { + printf("%ld", value->integer); } } \ No newline at end of file diff --git a/src/SQL.h b/src/SQL.h index 1b1ee85..231af0f 100644 --- a/src/SQL.h +++ b/src/SQL.h @@ -11,14 +11,14 @@ enum ValueType_t { VALUE_NONE, VALUE_STRING, - VALUE_NUMBER + VALUE_INTEGER }; typedef enum ValueType_t ValueType; struct Value_t { ValueType type; char *string; - int64_t number; + int64_t integer; }; typedef struct Value_t Value; @@ -98,12 +98,14 @@ typedef enum ColumnOption_t ColumnOption; enum ColumnType_t { COLTYPE_NONE, - COLTYPE_STRING, + COLTYPE_CHAR, COLTYPE_INT }; typedef enum ColumnType_t ColumnType; struct ColumnSpec_t { + uint16_t id; + size_t rowOffset; char *identifier; ColumnType type; size_t size; @@ -115,6 +117,8 @@ ColumnSpec *new_column_spec(); void free_column_spec(ColumnSpec *spec); +size_t column_spec_data_size(ColumnSpec *spec); + struct ColumnSpecList_t { ColumnSpec **columns; size_t length; diff --git a/src/Table.c b/src/Table.c new file mode 100644 index 0000000..0070331 --- /dev/null +++ b/src/Table.c @@ -0,0 +1,173 @@ +// +// Created by sam on 07/12/2019. +// + +#include +#include +#include "Table.h" + +TableIndex *new_table_index() { + TableIndex *index = malloc(sizeof(TableIndex)); + index->name = NULL; + index->columnId = 0; + index->tree = NULL; + return index; +} + +void free_table_index(TableIndex *index) { + if (index->name != NULL) { + free(index->name); + } + if (index->tree != NULL) { + free_bplus_tree(index->tree); + } + free(index); +} + +TableIndexList *new_table_index_list() { + TableIndexList *list = malloc(sizeof(TableIndexList)); + list->indexes = NULL; + list->length = 0; + return list; +} + +void free_table_index_list(TableIndexList *list) { + if (list->length > 0) { + for (size_t i = 0; i < list->length; i++) { + free_table_index(list->indexes[i]); + } + free(list->indexes); + } + free(list); +} + +void append_table_index_list(TableIndexList *list, TableIndex *index) { + list->length++; + list->indexes = realloc(list->indexes, sizeof(TableIndex *) * list->length); + list->indexes[list->length - 1] = index; +} + +void table_index_list_remove(TableIndexList *list, TableIndex *index) { + if (list->length == 0) { + return; + } + for (size_t i = 0; i < list->length; i++) { + if (list->indexes[i] == index) { + while (i + 1 < list->length) { + list->indexes[i] = list->indexes[i + 1]; + i++; + } + list->length--; + list->indexes = realloc(list->indexes, sizeof(TableIndex *) * list->length); + return; + } + } +} + +TableIndex *table_index_list_get(TableIndexList *list, uint16_t columnId) { + if (list->length == 0) { + return NULL; + } + for (size_t i = 0; i < list->length; i++) { + if (list->indexes[i]->columnId == columnId) { + return list->indexes[i]; + } + } +} + +TableRow *new_table_row() { + TableRow *row = malloc(sizeof(TableRow)); + row->rowId = 0; + row->data = NULL; + row->next = NULL; + return row; +} + +void free_table_row(TableRow *row) { + if (row->data != NULL) { + free(row->data); + } + free(row); +} + +Table *new_table() { + Table *table = malloc(sizeof(Table)); + table->name = NULL; + table->columns = NULL; + table->columnLength = 0; + table->indexes = new_table_index_list(); + table->rowCount = 0; + table->rowSize = 0; + table->rowFirst = NULL; + return table; +} + +void free_table(Table *table) { + if (table->name != NULL) { + free(table->name); + } + if (table->columns != NULL) { + for (size_t i = 0; i < table->columnLength; i++) { + free_column_spec(table->columns[i]); + } + free(table->columns); + table->columnLength = 0; + } + if (table->indexes != NULL) { + free_table_index_list(table->indexes); + } + if (table->rowFirst != NULL) { + TableRow *row = table->rowFirst; + do { + TableRow *temp = row; + row = row->next; + free_table_row(temp); + } while (row == NULL); + } + free(table); +} + +size_t table_determine_row_size(Table *table) { + size_t minSize = 0; + for (size_t i = 0; i < table->columnLength; i++) { + minSize += column_spec_data_size(table->columns[i]); + } + size_t rowSize = 0; + while (minSize > rowSize) rowSize += TABLE_PAGE_SIZE; + return rowSize; +} + +TableRow *table_new_row(Table *table) { + TableRow *row = new_table_row(); + row->data = calloc(1, table->rowSize); + if (table->rowFirst == NULL) { + table->rowFirst = row; + return row; + } + TableRow *lastRow = table->rowFirst; + while (lastRow->next != NULL) { + lastRow = lastRow->next; + } + lastRow->next = row; + return row; +} + +void table_add_column(Table *table, ColumnSpec *spec) { + table->columnLength++; + table->columns = realloc(table->columns, sizeof(ColumnSpec) * table->columnLength); + table->columns[table->columnLength - 1] = spec; + table->rowSize = table_determine_row_size(table); + spec->id = table->columnLength - 1; + if (spec->id > 0) { + ColumnSpec *previousColumn = table->columns[spec->id - 1]; + spec->rowOffset = previousColumn->rowOffset + column_spec_data_size(previousColumn); + } else { + spec->rowOffset = 0; + } +} + +void* table_row_column_data(Table *table, TableRow *row, uint16_t columnId) { + assert(columnId < table->columnLength); + ColumnSpec *columnSpec = table->columns[columnId]; + return row->data + columnSpec->rowOffset; +} diff --git a/src/Table.h b/src/Table.h new file mode 100644 index 0000000..5238537 --- /dev/null +++ b/src/Table.h @@ -0,0 +1,74 @@ +// +// Created by sam on 07/12/2019. +// + +#ifndef SDB_TABLE_H +#define SDB_TABLE_H + +#include "SQL.h" +#include "bplus_tree.h" + +#define TABLE_PAGE_SIZE 4096 + +struct TableIndex_t { + char *name; + uint16_t columnId; + BPlusTree *tree; +}; +typedef struct TableIndex_t TableIndex; + +TableIndex *new_table_index(); + +void free_table_index(TableIndex *index); + +struct TableIndexList_t { + TableIndex **indexes; + size_t length; +}; +typedef struct TableIndexList_t TableIndexList; + +TableIndexList *new_table_index_list(); + +void free_table_index_list(TableIndexList *list); + +void append_table_index_list(TableIndexList *list, TableIndex *index); + +void table_index_list_remove(TableIndexList *list, TableIndex *index); + +TableIndex *table_index_list_get(TableIndexList *list, uint16_t columnId); + +struct TableRow_t { + uint64_t rowId; + struct TableRow_t *next; + void *data; +}; +typedef struct TableRow_t TableRow; + +TableRow *new_table_row(); + +void free_table_row(TableRow *row); + +struct Table_t { + char *name; + ColumnSpec **columns; + size_t columnLength; + TableIndexList *indexes; + size_t rowSize; + size_t rowCount; + TableRow *rowFirst; +}; +typedef struct Table_t Table; + +Table *new_table(); + +void free_table(Table *table); + +void table_add_column(Table *table, ColumnSpec *spec); + +size_t table_determine_row_size(Table *table); + +TableRow *table_new_row(Table *table); + +void* table_row_column_data(Table *table, TableRow *row, uint16_t columnId); + +#endif //SDB_TABLE_H diff --git a/src/bplus_tree.c b/src/bplus_tree.c index 9a9b93f..d58ca4d 100644 --- a/src/bplus_tree.c +++ b/src/bplus_tree.c @@ -77,7 +77,7 @@ bool bplus_node_insert_kv(BPlusNode *node, BPlusKV *kv) { return true; } - //Find an index where we should insert + //Find an tree where we should insert size_t i; for (i = 0; i < node->keyCount; i++) { if (kv->key < node->keys[i]->key) { diff --git a/src/parser.c b/src/parser.c index 94d1626..8947435 100644 --- a/src/parser.c +++ b/src/parser.c @@ -163,8 +163,8 @@ ColumnSpecList *parser_node_convert_column_spec_list(ParserNode *node) { append_column_spec_list(list, spec); spec->identifier = strdup(specNode->token->valueStr); ParserNode *colTypeNode = specNode->children[0]; - if (colTypeNode->token->type == T_KW_STRING) { - spec->type = COLTYPE_STRING; + if (colTypeNode->token->type == T_KW_CHAR) { + spec->type = COLTYPE_CHAR; spec->size = (size_t)colTypeNode->children[0]->token->valueInt; } else if (colTypeNode->token->type == T_KW_INT) { spec->type = COLTYPE_INT; @@ -212,9 +212,9 @@ Value *parser_node_convert_value(ParserNode *node) { if (node->token->type == T_STRING) { value->type = VALUE_STRING; value->string = strdup(node->token->valueStr); - } else if (node->token->type == T_NUMBER) { - value->type = VALUE_NUMBER; - value->number = node->token->valueInt; + } else if (node->token->type == T_INTEGER) { + value->type = VALUE_INTEGER; + value->integer = node->token->valueInt; } return value; } @@ -536,22 +536,22 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) { token = NULL; append_parser_node(node, columnSpec); NEXT_TOKEN(); - if (token == NULL || (token->type != T_KW_STRING && token->type != T_KW_INT)) { + if (token == NULL || (token->type != T_KW_CHAR && token->type != T_KW_INT)) { parser_set_error(parser, "Expected one of STRING, INT, INTEGER", token); break; } - if (token->type == T_KW_STRING) { + if (token->type == T_KW_CHAR) { ParserNode *columnType = new_parser_node(NODE_COLUMN_TYPE, token); token = NULL; append_parser_node(columnSpec, columnType); EXPECT(T_PAREN_OPEN); NEXT_TOKEN(); - if (token == NULL || token->type != T_NUMBER) { - parser_set_error(parser, "Expected number", token); + if (token == NULL || token->type != T_INTEGER) { + parser_set_error(parser, "Expected integer", token); break; } if (token->valueInt < 1) { - parser_set_error(parser, "Expected positive number", token); + parser_set_error(parser, "Expected positive integer", token); break; } append_parser_node(columnType, new_parser_node(NODE_COLUMN_TYPE_SPECIFIER, token)); @@ -599,7 +599,7 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) { append_parser_node(node, assignment); EXPECT(T_COMP_EQ); NEXT_TOKEN(); - if (token == NULL || (token->type != T_STRING && token->type != T_NUMBER)) { + if (token == NULL || (token->type != T_STRING && token->type != T_INTEGER)) { parser_set_error(parser, "Expected value", token); break; } @@ -669,7 +669,7 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) { } break; case 2: - if (token->type == T_STRING || token->type == T_NUMBER) { + if (token->type == T_STRING || token->type == T_INTEGER) { append_parser_node(node, new_parser_node(NODE_VALUE, token)); token = NULL; node->phase = -1; @@ -742,7 +742,7 @@ void parser_print_node_tree(ParserNode *node, size_t indent) { case T_STRING: printf("<%s>", node->token->valueStr); break; - case T_NUMBER: + case T_INTEGER: printf("<%ld>", node->token->valueInt); break; default: diff --git a/src/scanner.c b/src/scanner.c index d2e9911..58b2e74 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -168,10 +168,10 @@ ScannerToken *scanner_next_token(Scanner *scanner, ScannerToken *token) { else if (scanner_match(scanner, "create", true)) token->type = T_KW_CREATE; else if (scanner_match(scanner, "table", true)) token->type = T_KW_TABLE; else if (scanner_match(scanner, "drop", true)) token->type = T_KW_DROP; - else if (scanner_match(scanner, "string", true)) token->type = T_KW_STRING; + else if (scanner_match(scanner, "char", true)) token->type = T_KW_CHAR; else if (scanner_match(scanner, "int", true)) token->type = T_KW_INT; else if (scanner_match(scanner, "integer", true)) token->type = T_KW_INT; - else if (scanner_match(scanner, "index", true)) token->type = T_KW_INDEX; + else if (scanner_match(scanner, "tree", true)) token->type = T_KW_INDEX; if (token->type != T_NONE) { return token; } @@ -222,7 +222,7 @@ ScannerToken *scanner_next_token(Scanner *scanner, ScannerToken *token) { free_scanner_token(token); return NULL; } - token->type = T_NUMBER; + token->type = T_INTEGER; //convert number token->valueInt = (int64_t) strtol(intInput, NULL, 10); return token; diff --git a/src/scanner.h b/src/scanner.h index 5cc64a0..4d2438c 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -12,7 +12,7 @@ #define SCANNER_TOKEN_TYPE_LIST \ X(T_NONE) \ X(T_STRING) \ - X(T_NUMBER) \ + X(T_INTEGER) \ X(T_IDENTIFIER) \ X(T_COMMA) \ X(T_SEMICOLON) \ @@ -32,7 +32,7 @@ X(T_KW_CREATE) \ X(T_KW_TABLE) \ X(T_KW_DROP) \ - X(T_KW_STRING) \ + X(T_KW_CHAR) \ X(T_KW_INT) \ X(T_KW_INDEX)