major improvements to expr-structure

This commit is contained in:
Pedro 2014-10-24 16:10:38 +02:00
parent 67d2ad9336
commit e24a2ae88d
7 changed files with 191 additions and 75 deletions

View File

@ -12,7 +12,6 @@
*********************************/
#include "Statement.h"
#include "List.h"
#include "bison_parser.h"
#include "flex_lexer.h"
@ -82,7 +81,7 @@ typedef void* yyscan_t;
%token SELECT FROM WHERE GROUP BY HAVING
%token JOIN ON INNER OUTER LEFT RIGHT CROSS USING NATURAL
%token CREATE TABLE DATABASE INDEX
%token AS NOT AND OR NULL
%token AS NOT AND OR NULL LIKE
%token <sval> NAME STRING COMPARISON
%token <number> FLOAT
%token <uintnum> EQUALS NOTEQUALS LESS GREATER LESSEQ GREATEREQ
@ -94,12 +93,34 @@ typedef void* yyscan_t;
%type <select_statement> select_statement
%type <sval> table_name
%type <table> from_clause table_ref table_ref_atomic
%type <expr> expr column_name scalar_exp literal
%type <expr> comparison_predicate predicate search_condition where_clause
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr
%type <expr> column_name literal
%type <expr> comp_expr where_clause
%type <explist> expr_list group_clause select_list
%type <tbllist> table_ref_commalist
/******************************
** Token Precedence and Associativity
** Precedence: lowest to highest
******************************/
%left OR
%left AND
%right NOT
%right '=' EQUALS NOTEQUALS
%nonassoc '<' '>' LESS GREATER LESSEQ GREATEREQ
%nonassoc NOTNULL
%nonassoc ISNULL
%nonassoc IS /* sets precedence for IS NULL, etc */
%left '+' '-'
%left '*' '/' '%'
%left '^'
/* Unary Operators */
%left '[' ']'
%left '(' ')'
%left '.'
%%
/*********************************
@ -142,8 +163,8 @@ select_statement:
select_list:
'*' { $$ = new List<Expr*>(new Expr(eExprStar)); }
| expr_list;
expr_list
;
from_clause:
@ -152,7 +173,7 @@ from_clause:
where_clause:
WHERE search_condition { $$ = $2; }
WHERE expr { $$ = $2; }
| /* empty */ { $$ = NULL; }
;
@ -163,59 +184,70 @@ group_clause:
;
// TODO: multiple predicates
search_condition:
predicate
/******************************
** Expressions
******************************/
expr_list:
expr { $$ = new List<Expr*>($1); }
| expr_list ',' expr { $1->push_back($3); $$ = $1; }
;
predicate:
comparison_predicate
;
comparison_predicate:
scalar_exp EQUALS scalar_exp { $$ = makePredicate($1, SQL_EQUALS, $3); }
| scalar_exp NOTEQUALS scalar_exp { $$ = makePredicate($1, SQL_NOTEQUALS, $3); }
| scalar_exp LESS scalar_exp { $$ = makePredicate($1, SQL_LESS, $3); }
| scalar_exp GREATER scalar_exp { $$ = makePredicate($1, SQL_GREATER, $3); }
| scalar_exp LESSEQ scalar_exp { $$ = makePredicate($1, SQL_LESSEQ, $3); }
| scalar_exp GREATEREQ scalar_exp { $$ = makePredicate($1, SQL_GREATEREQ, $3); }
;
// TODO: Expression can also be scalar_exp
expr:
'(' expr ')' { $$ = $2; }
| scalar_expr
| unary_expr
| binary_expr
| function_expr
;
scalar_expr:
column_name
| NAME '(' expr ')' { $$ = makeFunctionRef($1, $3); }
| star_expr
| literal
;
unary_expr:
'-' expr { $$ = NULL; } // TODO
| '+' expr { $$ = NULL; }
| NOT expr { $$ = NULL; }
;
binary_expr:
comp_expr
| expr '-' expr { $$ = Expr::makeOpBinary($1, '-', $3); }
| expr '+' expr { $$ = Expr::makeOpBinary($1, '+', $3); }
| expr '/' expr { $$ = Expr::makeOpBinary($1, '/', $3); }
| expr '*' expr { $$ = Expr::makeOpBinary($1, '*', $3); }
| expr AND expr { $$ = Expr::makeOpBinary($1, AND, $3); }
| expr OR expr { $$ = Expr::makeOpBinary($1, OR, $3); }
;
// TODO: Scalar expressions can also be arithmetic
scalar_exp:
column_name
| literal
comp_expr:
expr EQUALS expr { $$ = Expr::makeOpBinary($1, '=', $3); }
| expr NOTEQUALS expr { $$ = Expr::makeOpBinary($1, NOT_EQUALS, $3); }
| expr LESS expr { $$ = Expr::makeOpBinary($1, '<', $3); }
| expr GREATER expr { $$ = Expr::makeOpBinary($1, '>', $3); }
| expr LESSEQ expr { $$ = Expr::makeOpBinary($1, LESS_EQ, $3); }
| expr GREATEREQ expr { $$ = Expr::makeOpBinary($1, GREATER_EQ, $3); }
;
function_expr:
NAME '(' expr ')' { $$ = makeFunctionRef($1, $3); }
;
column_name:
NAME { $$ = makeColumnRef($1); }
;
literal:
STRING { $$ = makeStringLiteral($1); }
| FLOAT { $$ = makeFloatLiteral($1); }
;
opt_semicolon:
';'
| /* empty */
;
expr_list:
expr { $$ = new List<Expr*>($1); }
| expr_list ',' expr { $1->push_back($3); $$ = $1; }
star_expr:
'*' { $$ = new Expr(eExprStar); }
;
@ -256,6 +288,13 @@ table_name:
;
opt_semicolon:
';'
| /* empty */
;
%%
/*********************************
** Section 4: Additional C code

View File

@ -11,7 +11,6 @@
%{
#include "Statement.h"
#include "List.h"
#include "bison_parser.h"
#include <stdio.h>

View File

@ -1,8 +1,9 @@
make clean
make tests
./bin/tests
# make tests
# ./bin/tests
make execution
./bin/sql_execution "SELECT col1, col2 FROM table, (SELECT * FROM a, table, (SELECT * FROM (SELECT * FROM foo))) GROUP BY col1;"
./bin/sql_execution "SELECT a FROM foo WHERE a > 12 OR b > 3 AND c = 3"
./bin/sql_execution "SELECT col1, col2, 'test' FROM table, foo WHERE age > 12 AND zipcode = 12345 GROUP BY col1;"

View File

@ -1,6 +1,15 @@
#include "Expr.h"
#include <stdio.h>
#include <string.h>
char* substr(const char* source, int from, int to) {
int len = to-from;
char* copy = new char[len+1];
strncpy(copy, source+from, len);
copy[len] = '\0';
return copy;
}
Expr* makeColumnRef(char* name) {
ALLOC_EXPR(e, eExprColumnRef);
@ -15,15 +24,6 @@ Expr* makeFunctionRef(char* func_name, Expr* expr) {
return e;
}
Expr* makePredicate(Expr* expr1, uint op, Expr* expr2) {
ALLOC_EXPR(e, eExprPredicate);
// printf("Pred: %u\n", op);
e->pred_type = op;
e->expr = expr1;
e->expr2 = expr2;
return e;
}
Expr* makeFloatLiteral(float value) {
ALLOC_EXPR(e, eExprLiteralFloat);
e->float_literal = value;
@ -32,6 +32,33 @@ Expr* makeFloatLiteral(float value) {
Expr* makeStringLiteral(char* string) {
ALLOC_EXPR(e, eExprLiteralString);
e->name = string;
e->name = substr(string, 1, strlen(string)-1);
delete string;
return e;
}
Expr* Expr::makeOpUnary(OperatorType op, Expr* expr) {
ALLOC_EXPR(e, eExprOperator);
e->op_type = op;
e->expr = expr;
return e;
}
Expr* Expr::makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2) {
ALLOC_EXPR(e, eExprOperator);
e->op_type = op;
e->op_char = 0;
e->expr = expr1;
e->expr2 = expr2;
return e;
}
Expr* Expr::makeOpBinary(Expr* expr1, char op, Expr* expr2) {
ALLOC_EXPR(e, eExprOperator);
e->op_type = TRIVIAL_OP;
e->op_char = op;
e->expr = expr1;
e->expr2 = expr2;
return e;
}

View File

@ -4,27 +4,54 @@
#include <stdlib.h>
typedef enum {
eExprLiteralFloat,
eExprLiteralString,
eExprStar,
eExprColumnRef,
eExprFunctionRef,
eExprPredicate
} EExprType;
eExprOperator
} ExprType;
/**
* Trivial types are those that can be descriped by a sigle character e.g:
* + - * / < > = %
* Non-trivial are:
* <> <= >= LIKE ISNULL NOT
*/
typedef enum {
TRIVIAL_OP,
NOT_EQUALS,
LESS_EQ,
GREATER_EQ,
LIKE,
ISNULL,
NOT,
AND,
OR
} OperatorType;
typedef struct Expr Expr;
struct Expr {
Expr(EExprType type) : type(type) {};
Expr(ExprType type) : type(type) {};
EExprType type;
ExprType type;
Expr* expr;
Expr* expr2;
char* name;
uint pred_type;
float float_literal;
OperatorType op_type;
char op_char;
static Expr* makeOpUnary(OperatorType op, Expr* expr);
static Expr* makeOpBinary(Expr* expr1, char op, Expr* expr2);
static Expr* makeOpBinary(Expr* expr1, OperatorType op, Expr* expr2);
};
// Zero initializes an Expr object and assigns it to a space in the heap
@ -40,7 +67,6 @@ struct Expr {
Expr* makeColumnRef(char* name);
Expr* makeFunctionRef(char* func_name, Expr* expr);
Expr* makePredicate(Expr* expr1, uint op, Expr* expr2);
Expr* makeFloatLiteral(float value);
Expr* makeStringLiteral(char* string);

View File

@ -3,10 +3,14 @@
#include <stdio.h>
#include <string>
const char* indent(uint num_indent) { return std::string(num_indent, ' ').c_str(); }
void printExpression(Expr* expr, uint num_indent);
void printOperatorExpression(Expr* expr, uint num_indent);
const char* indent(uint num_indent) { return std::string(num_indent, '\t').c_str(); }
void inprint(int val, uint num_indent) { printf("%s%d\n", indent(num_indent), val); }
void inprint(float val, uint num_indent) { printf("%s%f\n", indent(num_indent), val); }
void inprint(const char* val, uint num_indent) { printf("%s%s\n", indent(num_indent), val); }
void inprint(char val, uint num_indent) { printf("%s%c\n", indent(num_indent), val); }
void printTableRefInfo(TableRef* table, uint num_indent) {
switch (table->type) {
@ -22,19 +26,39 @@ void printTableRefInfo(TableRef* table, uint num_indent) {
}
}
void printOperatorExpression(Expr* expr, uint num_indent) {
switch (expr->op_type) {
case TRIVIAL_OP: inprint(expr->op_char, num_indent); break;
case AND: inprint("AND", num_indent); break;
case OR: inprint("OR", num_indent); break;
default: inprint(expr->op_type, num_indent); break;
}
printExpression(expr->expr, num_indent+1);
if (expr->expr2 != NULL) printExpression(expr->expr2, num_indent+1);
}
void printExpression(Expr* expr, uint num_indent) {
switch (expr->type) {
case eExprStar: inprint("*", num_indent); break;
case eExprColumnRef: inprint(expr->name, num_indent); break;
case eExprLiteralFloat: inprint(expr->float_literal, num_indent); break;
case eExprLiteralString: inprint(expr->name, num_indent); break;
case eExprFunctionRef: /* todo */ break;
case eExprOperator: printOperatorExpression(expr, num_indent); break;
default:
fprintf(stderr, "Unrecognized expression type %d\n", expr->type);
break;
}
}
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
inprint("SelectStatement", num_indent);
inprint("Fields:", num_indent+1);
for (Expr* expr : stmt->select_list->_vector) {
switch (expr->type) {
case eExprStar: inprint("*", num_indent+2); break;
case eExprColumnRef: inprint(expr->name, num_indent+2); break;
case eExprLiteralFloat: inprint(expr->float_literal, num_indent+2); break;
case eExprLiteralString: inprint(expr->name, num_indent+2); break;
case eExprFunctionRef: /* todo */ break;
case eExprPredicate: /* todo */ break;
}
}
for (Expr* expr : stmt->select_list->_vector) printExpression(expr, num_indent+2);
inprint("Sources:", num_indent+1);
printTableRefInfo(stmt->from_table, num_indent+2);
inprint("Search Conditions:", num_indent+1);
printExpression(stmt->where_clause, num_indent+2);
}

View File

@ -18,7 +18,7 @@
void SelectTest1() {
printf("Test: SelectTest1... "); fflush(stdout);
const char* sql = "SELECT age, name, address from table WHERE age < 12.5;";
const char* sql = "SELECT age, (name), address from table WHERE age < 12.5;";
Statement* sqlStatement = SQLParser::parseSQLString(sql);
ASSERT(sqlStatement != NULL);
ASSERT(sqlStatement->type == eSelect);
@ -48,7 +48,7 @@ void SelectTest1() {
void SelectTest2() {
printf("Test: SelectTest2... "); fflush(stdout);
const char* sql = "SELECT * FROM (SELECT age FROM table, table2);";
const char* sql = "SELECT * FROM (SELECT age+zipcode FROM table, table2);";
Statement* stmt = SQLParser::parseSQLString(sql);
ASSERT(stmt != NULL);
ASSERT(stmt->type == eSelect);