Implemented conversion from parse tree to SQL structure.

Added debug printing for SQL statements.
This commit is contained in:
2018-06-10 12:21:13 +01:00
parent 5f6f10fe2e
commit 9af2f7bb45
8 changed files with 352 additions and 25 deletions

View File

@@ -10,8 +10,8 @@ Statement = SelectStmt | InsertStmt | UpdateStmt | DeleteStmt | CreateStmt | Dro
SelectStmt = 'Select', FieldList, 'From', Identifier, ['Where', ComparisonGroup] ;
InsertStmt = 'Insert Into', Identifier, 'Set', AssignmentList ;
UpdateStmt = 'Update', Identifier, 'Set', AssignmentList, 'Where', AssignmentList ;
DeleteStmt = 'Delete From', Identifier, 'Where', AssignmentList ;
UpdateStmt = 'Update', Identifier, 'Set', AssignmentList, 'Where', ComparisonGroup ;
DeleteStmt = 'Delete From', Identifier, 'Where', ComparisonGroup ;
CreateStmt = 'Create Table', Identifier, '(', ColumnSpecList, ')' ;
DropStmt = 'Drop Table', Identifier ;

154
src/SQL.c
View File

@@ -3,10 +3,13 @@
//
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "SQL.h"
Value *new_value() {
Value *value = malloc(sizeof(Value));
value->type = VALUE_NONE;
value->number = 0;
value->string = NULL;
return value;
@@ -177,7 +180,7 @@ SelectStmt *new_select_stmt() {
void free_select_stmt(SelectStmt *stmt) {
if (stmt->where != NULL) {
free_assignment_list(stmt->where);
free_comparison_group(stmt->where);
}
if (stmt->tableName != NULL) {
free(stmt->tableName);
@@ -218,7 +221,7 @@ void free_update_stmt(UpdateStmt *stmt) {
free(stmt->tableName);
}
if (stmt->where != NULL) {
free_assignment_list(stmt->where);
free_comparison_group(stmt->where);
}
if (stmt->values != NULL) {
free_assignment_list(stmt->values);
@@ -237,7 +240,7 @@ void free_delete_stmt(DeleteStmt *stmt) {
free(stmt->tableName);
}
if (stmt->where != NULL) {
free_assignment_list(stmt->where);
free_comparison_group(stmt->where);
}
free(stmt);
}
@@ -272,10 +275,10 @@ void free_drop_stmt(DropStmt *stmt) {
free(stmt);
}
Statement *new_statement() {
Statement *new_statement(StatementType type, void *statement) {
Statement *stmt = malloc(sizeof(Statement));
stmt->type = STMT_NONE;
stmt->stmt = NULL;
stmt->type = type;
stmt->stmt = statement;
return stmt;
}
@@ -330,4 +333,143 @@ void append_statement_list(StatementList *list, Statement *statement) {
list->length++;
list->statements = realloc(list->statements, sizeof(Statement *) * list->length);
list->statements[list->length - 1] = statement;
}
void print_statement_list(StatementList *list) {
for (size_t i = 0; i < list->length; i++) {
Statement *stmt = list->statements[i];
switch (stmt->type) {
case STMT_SELECT: {
SelectStmt *select = stmt->stmt;
printf("SELECT ");
print_field_list(select->fields);
printf(" FROM %s", select->tableName);
if (select->where->length > 0) {
printf(" WHERE ");
print_comparison_group(select->where);
}
}
break;
case STMT_INSERT: {
InsertStmt *insert = stmt->stmt;
printf("INSERT INTO %s SET ", insert->tableName);
print_assignment_list(insert->values);
}
break;
case STMT_UPDATE: {
UpdateStmt *update = stmt->stmt;
printf("UPDATE %s SET ", update->tableName);
print_assignment_list(update->values);
if (update->where->length > 0) {
printf(" WHERE ");
print_comparison_group(update->where);
}
}
break;
case STMT_DELETE: {
DeleteStmt *delete = stmt->stmt;
printf("DELETE FROM %s", delete->tableName);
if (delete->where->length > 0) {
printf(" ");
print_comparison_group(delete->where);
}
}
break;
case STMT_CREATE: {
CreateStmt *create = stmt->stmt;
printf("CREATE TABLE %s (", create->tableName);
print_column_spec_list(create->columns);
printf(")");
}
break;
case STMT_DROP: {
DropStmt *drop = stmt->stmt;
printf("DELETE TABLE %s", drop->tableName);
}
break;
default:
break;
}
printf(";\n");
}
}
void print_field_list(FieldList *list) {
for (size_t i = 0; i < list->length; i++) {
printf("%s%s", list->fields[i], i + 1 < list->length ? ", " : "");
}
}
void print_assignment_list(AssignmentList *list) {
for (size_t i = 0; i < list->length; i++) {
Assignment *assignment = list->assignments[i];
printf("%s=", assignment->identifier);
print_value(assignment->value);
if (i + 1 < list->length) {
printf(", ");
}
}
}
void print_comparison_group(ComparisonGroup *group) {
for (size_t i = 0; i < group->length; i++) {
Comparison *comparison = group->comparisons[i];
printf("%s=", comparison->identifier);
print_value(comparison->value);
if (i + 1 < group->length) {
printf(" AND ");
}
}
}
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(%d)", spec->identifier, spec->size);
} else if (spec->type == COLTYPE_INT) {
printf("%s INTEGER", spec->identifier);
}
if (spec->option == COLOPT_INDEX) {
printf(" INDEX");
}
if (i + 1 < list->length) {
printf(", ");
}
}
}
void print_value(Value *value) {
if (value->type == VALUE_STRING) {
printf("'");
size_t len = strlen(value->string);
for (size_t i = 0; i < len; i++) {
char next = value->string[i];
switch (next) {
case '\'':
printf("\\'");
break;
case '\n':
printf("\\n");
break;
case '\r':
printf("\\r");
break;
case '\t':
printf("\\t");
break;
case '\\':
printf("\\\\");
break;
default:
printf("%c", next);
break;
}
}
printf("'");
} else if (value->type == VALUE_NUMBER) {
printf("%lld", value->number);
}
}

View File

@@ -8,11 +8,19 @@
#include <stddef.h>
#include <inttypes.h>
union Value_t {
char *string;
uint64_t number;
enum ValueType_t {
VALUE_NONE,
VALUE_STRING,
VALUE_NUMBER
};
typedef union Value_t Value;
typedef enum ValueType_t ValueType;
struct Value_t {
ValueType type;
char *string;
int64_t number;
};
typedef struct Value_t Value;
Value *new_value();
@@ -33,6 +41,7 @@ struct Comparison_t {
typedef struct Comparison_t Comparison;
Comparison *new_comparison();
void free_comparison(Comparison *comparison);
struct ComparisonGroup_t {
@@ -42,7 +51,9 @@ struct ComparisonGroup_t {
typedef struct ComparisonGroup_t ComparisonGroup;
ComparisonGroup *new_comparision_group();
void free_comparison_group(ComparisonGroup* group);
void free_comparison_group(ComparisonGroup *group);
void append_comparison_group(ComparisonGroup *group, Comparison *comparison);
struct Assignment_t {
@@ -119,7 +130,7 @@ void append_column_spec_list(ColumnSpecList *list, ColumnSpec *spec);
struct SelectStmt_t {
FieldList *fields;
char *tableName;
AssignmentList *where;
ComparisonGroup *where;
};
typedef struct SelectStmt_t SelectStmt;
@@ -140,7 +151,7 @@ void free_insert_stmt(InsertStmt *stmt);
struct UpdateStmt_t {
char *tableName;
AssignmentList *values;
AssignmentList *where;
ComparisonGroup *where;
};
typedef struct UpdateStmt_t UpdateStmt;
@@ -150,7 +161,7 @@ void free_update_stmt(UpdateStmt *stmt);
struct DeleteStmt_t {
char *tableName;
AssignmentList *where;
ComparisonGroup *where;
};
typedef struct DeleteStmt_t DeleteStmt;
@@ -194,7 +205,7 @@ struct Statement_t {
};
typedef struct Statement_t Statement;
Statement *new_statement();
Statement *new_statement(StatementType type, void *statement);
void free_statement(Statement *stmt);
@@ -210,4 +221,16 @@ void free_statement_list(StatementList *list);
void append_statement_list(StatementList *list, Statement *statement);
void print_statement_list(StatementList *list);
void print_field_list(FieldList *list);
void print_assignment_list(AssignmentList *list);
void print_comparison_group(ComparisonGroup *group);
void print_column_spec_list(ColumnSpecList *list);
void print_value(Value *value);
#endif //SDB_SQL_H

View File

@@ -36,6 +36,11 @@ void parse_input(char *input) {
if (node != NULL) {
printf("%s\n", input);
parser_print_node_tree(node, 0);
StatementList* list = parser_node_convert(node);
print_statement_list(list);
free_statement_list(list);
free_parser_node(node);
}

View File

@@ -76,6 +76,149 @@ void free_parser(Parser *parser) {
free(parser);
}
StatementList *parser_node_convert(ParserNode *node) {
if (node->type != NODE_STATEMENT_LIST) {
return NULL;
}
StatementList *list = new_statement_list();
size_t i, k;
for (i = 0; i < node->childrenLength; i++) {
ParserNode *child = node->children[i];
switch (child->type) {
case NODE_SELECT_STMT: {
SelectStmt *select = new_select_stmt();
append_statement_list(list, new_statement(STMT_SELECT, select));
select->fields = new_field_list();
select->tableName = strdup(child->children[1]->token->valueStr);
for (k = 0; k < child->children[0]->childrenLength; k++) {
ParserNode *fieldNode = child->children[0]->children[k];
append_field_list(select->fields, strdup(fieldNode->token->valueStr));
}
if (child->childrenLength == 3) {
select->where = parser_node_convert_comparison_group(child->children[2]);
} else {
select->where = new_comparision_group();
}
}
break;
case NODE_INSERT_STMT: {
InsertStmt *insert = new_insert_stmt();
append_statement_list(list, new_statement(STMT_INSERT, insert));
insert->tableName = strdup(child->children[0]->token->valueStr);
insert->values = parser_node_convert_assignment_list(child->children[1]);
}
break;
case NODE_UPDATE_STMT: {
UpdateStmt *update = new_update_stmt();
append_statement_list(list, new_statement(STMT_UPDATE, update));
update->tableName = strdup(child->children[0]->token->valueStr);
update->values = parser_node_convert_assignment_list(child->children[1]);
if (child->childrenLength == 3) {
update->where = parser_node_convert_comparison_group(child->children[2]);
} else {
update->where = new_comparision_group();
}
}
break;
case NODE_DELETE_STMT: {
DeleteStmt *delete = new_delete_stmt();
append_statement_list(list, new_statement(STMT_DELETE, delete));
delete->tableName = strdup(child->children[0]->token->valueStr);
if (child->childrenLength == 2) {
delete->where = parser_node_convert_comparison_group(child->children[1]);
} else {
delete->where = new_comparision_group();
}
}
break;
case NODE_CREATE_STMT: {
CreateStmt *create = new_create_stmt();
append_statement_list(list, new_statement(STMT_CREATE, create));
create->tableName = strdup(child->children[0]->token->valueStr);
create->columns = parser_node_convert_column_spec_list(child->children[1]);
}
break;
case NODE_DROP_STMT: {
DropStmt *drop= new_drop_stmt();
append_statement_list(list, new_statement(STMT_DROP, drop));
drop->tableName = (child->children[0]->token->valueStr);
}
break;
default:
break;
}
}
return list;
}
ColumnSpecList *parser_node_convert_column_spec_list(ParserNode *node) {
ColumnSpecList *list = new_column_spec_list();
for (size_t i = 0; i < node->childrenLength; i++) {
ParserNode* specNode = node->children[i];
ColumnSpec *spec = new_column_spec();
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;
spec->size = (size_t)colTypeNode->children[0]->token->valueInt;
} else if (colTypeNode->token->type == T_KW_INT) {
spec->type = COLTYPE_INT;
}
if (specNode->childrenLength == 2) {
if (specNode->children[1]->token->type == T_KW_INDEX) {
spec->option = COLOPT_INDEX;
}
}
}
return list;
}
ComparisonGroup *parser_node_convert_comparison_group(ParserNode *node) {
ComparisonGroup *group = new_comparision_group();
for (size_t i = 0; i < node->childrenLength; i++) {
ParserNode *compNode = node->children[i];
Comparison *comp = new_comparison();
append_comparison_group(group, comp);
comp->identifier = strdup(compNode->children[0]->token->valueStr);
if (compNode->children[1]->token->type == T_COMP_EQ) {
comp->comp = COMP_EQ;
} else if (compNode->children[1]->token->type == T_COMP_NEQ) {
comp->comp = COMP_NEQ;
}
comp->value = parser_node_convert_value(compNode->children[2]);
}
return group;
}
AssignmentList *parser_node_convert_assignment_list(ParserNode *node) {
AssignmentList *list = new_assignment_list();
for (size_t i = 0; i < node->childrenLength; i++) {
ParserNode *assignmentNode = node->children[i];
Assignment *assignment = new_assignment();
append_assignment_list(list, assignment);
assignment->identifier = strdup(assignmentNode->token->valueStr);
assignment->value = parser_node_convert_value(assignmentNode->children[0]);
}
return list;
}
Value *parser_node_convert_value(ParserNode *node) {
Value *value = new_value();
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;
}
return value;
}
#define NEXT_TOKEN() {\
token = scanner_next_token(scanner, token);\
}
@@ -286,9 +429,9 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) {
ASCEND_NODE();
} else if (token->type == T_KW_WHERE) {
node->phase++;
ParserNode *assignments = new_parser_node(NODE_ASSIGNMENT_LIST, NULL);
append_parser_node(node, assignments);
node = assignments;
ParserNode *comparisons = new_parser_node(NODE_COMPARISON_GROUP, NULL);
append_parser_node(node, comparisons);
node = comparisons;
}
}
break;
@@ -407,6 +550,10 @@ ParserNode *parser_parse(Parser *parser, Scanner *scanner) {
parser_set_error(parser, "Expected number", token);
break;
}
if (token->valueInt < 1) {
parser_set_error(parser, "Expected positive number", token);
break;
}
append_parser_node(columnType, new_parser_node(NODE_COLUMN_TYPE_SPECIFIER, token));
token = NULL;
EXPECT(T_PAREN_CLOSE);

View File

@@ -55,7 +55,7 @@ enum ParserNodeType_t {
typedef enum ParserNodeType_t ParserNodeType;
#undef X
char* parser_node_type_to_str(ParserNodeType nodeType);
char *parser_node_type_to_str(ParserNodeType nodeType);
struct ParserNode_t {
struct ParserNode_t *parent;
@@ -73,6 +73,16 @@ void free_parser_node(ParserNode *node);
void append_parser_node(ParserNode *node, ParserNode *child);
StatementList *parser_node_convert(ParserNode *node);
ColumnSpecList *parser_node_convert_column_spec_list(ParserNode *node);
ComparisonGroup *parser_node_convert_comparison_group(ParserNode *node);
AssignmentList *parser_node_convert_assignment_list(ParserNode *node);
Value *parser_node_convert_value(ParserNode *node);
struct Parser_t {
ParseStatus status;
char *errMsg;

View File

@@ -203,11 +203,11 @@ ScannerToken *scanner_next_token(Scanner *scanner, ScannerToken *token) {
}
//Numbers
if (isdigit(scanner_peek_char(scanner))) {
if (isdigit(scanner_peek_char(scanner)) || scanner_peek_char(scanner) == '-') {
char intInput[32] = {0};
size_t intIndex = 0;
while (scanner_peek_char(scanner) != 0
&& isdigit(scanner_peek_char(scanner))
&& (isdigit(scanner_peek_char(scanner)) || scanner_peek_char(scanner) == '-')
&& intIndex + 1 < 32) {
intInput[intIndex++] = scanner_next_char(scanner);
}
@@ -219,7 +219,7 @@ ScannerToken *scanner_next_token(Scanner *scanner, ScannerToken *token) {
}
token->type = T_NUMBER;
//convert number
token->valueInt = (uint64_t) strtol(intInput, NULL, 10);
token->valueInt = (int64_t) strtol(intInput, NULL, 10);
return token;
}

View File

@@ -48,7 +48,7 @@ char* scanner_token_type_to_str(ScannerTokenType tokenType);
struct ScannerToken_t {
ScannerTokenType type;
char *valueStr;
uint64_t valueInt;
int64_t valueInt;
size_t lineNo;
size_t linePos;
};