Adding tables
This commit is contained in:
@@ -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 ;
|
||||
Value = "'", string, "'" | '"', string, '"' | integer ;
|
||||
@@ -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)
|
||||
30
src/SQL.c
30
src/SQL.c
@@ -5,12 +5,15 @@
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
10
src/SQL.h
10
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;
|
||||
|
||||
173
src/Table.c
Normal file
173
src/Table.c
Normal file
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// Created by sam on 07/12/2019.
|
||||
//
|
||||
|
||||
#include <malloc.h>
|
||||
#include <assert.h>
|
||||
#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;
|
||||
}
|
||||
74
src/Table.h
Normal file
74
src/Table.h
Normal file
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
26
src/parser.c
26
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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user