major improvements to expr-structure
This commit is contained in:
parent
67d2ad9336
commit
e24a2ae88d
|
@ -12,7 +12,6 @@
|
||||||
*********************************/
|
*********************************/
|
||||||
|
|
||||||
#include "Statement.h"
|
#include "Statement.h"
|
||||||
#include "List.h"
|
|
||||||
#include "bison_parser.h"
|
#include "bison_parser.h"
|
||||||
#include "flex_lexer.h"
|
#include "flex_lexer.h"
|
||||||
|
|
||||||
|
@ -82,7 +81,7 @@ typedef void* yyscan_t;
|
||||||
%token SELECT FROM WHERE GROUP BY HAVING
|
%token SELECT FROM WHERE GROUP BY HAVING
|
||||||
%token JOIN ON INNER OUTER LEFT RIGHT CROSS USING NATURAL
|
%token JOIN ON INNER OUTER LEFT RIGHT CROSS USING NATURAL
|
||||||
%token CREATE TABLE DATABASE INDEX
|
%token CREATE TABLE DATABASE INDEX
|
||||||
%token AS NOT AND OR NULL
|
%token AS NOT AND OR NULL LIKE
|
||||||
%token <sval> NAME STRING COMPARISON
|
%token <sval> NAME STRING COMPARISON
|
||||||
%token <number> FLOAT
|
%token <number> FLOAT
|
||||||
%token <uintnum> EQUALS NOTEQUALS LESS GREATER LESSEQ GREATEREQ
|
%token <uintnum> EQUALS NOTEQUALS LESS GREATER LESSEQ GREATEREQ
|
||||||
|
@ -94,12 +93,34 @@ typedef void* yyscan_t;
|
||||||
%type <select_statement> select_statement
|
%type <select_statement> select_statement
|
||||||
%type <sval> table_name
|
%type <sval> table_name
|
||||||
%type <table> from_clause table_ref table_ref_atomic
|
%type <table> from_clause table_ref table_ref_atomic
|
||||||
%type <expr> expr column_name scalar_exp literal
|
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr
|
||||||
%type <expr> comparison_predicate predicate search_condition where_clause
|
%type <expr> column_name literal
|
||||||
|
%type <expr> comp_expr where_clause
|
||||||
%type <explist> expr_list group_clause select_list
|
%type <explist> expr_list group_clause select_list
|
||||||
%type <tbllist> table_ref_commalist
|
%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:
|
select_list:
|
||||||
'*' { $$ = new List<Expr*>(new Expr(eExprStar)); }
|
expr_list
|
||||||
| expr_list;
|
;
|
||||||
|
|
||||||
|
|
||||||
from_clause:
|
from_clause:
|
||||||
|
@ -152,7 +173,7 @@ from_clause:
|
||||||
|
|
||||||
|
|
||||||
where_clause:
|
where_clause:
|
||||||
WHERE search_condition { $$ = $2; }
|
WHERE expr { $$ = $2; }
|
||||||
| /* empty */ { $$ = NULL; }
|
| /* empty */ { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -163,59 +184,70 @@ group_clause:
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
// TODO: multiple predicates
|
/******************************
|
||||||
search_condition:
|
** Expressions
|
||||||
predicate
|
******************************/
|
||||||
|
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:
|
||||||
|
'(' expr ')' { $$ = $2; }
|
||||||
|
| scalar_expr
|
||||||
|
| unary_expr
|
||||||
|
| binary_expr
|
||||||
|
| function_expr
|
||||||
|
;
|
||||||
|
|
||||||
|
scalar_expr:
|
||||||
column_name
|
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
|
comp_expr:
|
||||||
scalar_exp:
|
expr EQUALS expr { $$ = Expr::makeOpBinary($1, '=', $3); }
|
||||||
column_name
|
| expr NOTEQUALS expr { $$ = Expr::makeOpBinary($1, NOT_EQUALS, $3); }
|
||||||
| literal
|
| 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:
|
column_name:
|
||||||
NAME { $$ = makeColumnRef($1); }
|
NAME { $$ = makeColumnRef($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
literal:
|
literal:
|
||||||
STRING { $$ = makeStringLiteral($1); }
|
STRING { $$ = makeStringLiteral($1); }
|
||||||
| FLOAT { $$ = makeFloatLiteral($1); }
|
| FLOAT { $$ = makeFloatLiteral($1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
star_expr:
|
||||||
opt_semicolon:
|
'*' { $$ = new Expr(eExprStar); }
|
||||||
';'
|
|
||||||
| /* empty */
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
expr_list:
|
|
||||||
expr { $$ = new List<Expr*>($1); }
|
|
||||||
| expr_list ',' expr { $1->push_back($3); $$ = $1; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -256,6 +288,13 @@ table_name:
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
opt_semicolon:
|
||||||
|
';'
|
||||||
|
| /* empty */
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
/*********************************
|
/*********************************
|
||||||
** Section 4: Additional C code
|
** Section 4: Additional C code
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
%{
|
%{
|
||||||
|
|
||||||
#include "Statement.h"
|
#include "Statement.h"
|
||||||
#include "List.h"
|
|
||||||
#include "bison_parser.h"
|
#include "bison_parser.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
make clean
|
make clean
|
||||||
|
|
||||||
make tests
|
# make tests
|
||||||
./bin/tests
|
# ./bin/tests
|
||||||
|
|
||||||
make execution
|
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;"
|
|
@ -1,6 +1,15 @@
|
||||||
|
|
||||||
#include "Expr.h"
|
#include "Expr.h"
|
||||||
#include <stdio.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) {
|
Expr* makeColumnRef(char* name) {
|
||||||
ALLOC_EXPR(e, eExprColumnRef);
|
ALLOC_EXPR(e, eExprColumnRef);
|
||||||
|
@ -15,15 +24,6 @@ Expr* makeFunctionRef(char* func_name, Expr* expr) {
|
||||||
return e;
|
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) {
|
Expr* makeFloatLiteral(float value) {
|
||||||
ALLOC_EXPR(e, eExprLiteralFloat);
|
ALLOC_EXPR(e, eExprLiteralFloat);
|
||||||
e->float_literal = value;
|
e->float_literal = value;
|
||||||
|
@ -32,6 +32,33 @@ Expr* makeFloatLiteral(float value) {
|
||||||
|
|
||||||
Expr* makeStringLiteral(char* string) {
|
Expr* makeStringLiteral(char* string) {
|
||||||
ALLOC_EXPR(e, eExprLiteralString);
|
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;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,27 +4,54 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
eExprLiteralFloat,
|
eExprLiteralFloat,
|
||||||
eExprLiteralString,
|
eExprLiteralString,
|
||||||
eExprStar,
|
eExprStar,
|
||||||
eExprColumnRef,
|
eExprColumnRef,
|
||||||
eExprFunctionRef,
|
eExprFunctionRef,
|
||||||
eExprPredicate
|
eExprOperator
|
||||||
} EExprType;
|
} 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;
|
typedef struct Expr Expr;
|
||||||
|
|
||||||
struct Expr {
|
struct Expr {
|
||||||
Expr(EExprType type) : type(type) {};
|
Expr(ExprType type) : type(type) {};
|
||||||
|
|
||||||
EExprType type;
|
ExprType type;
|
||||||
|
|
||||||
Expr* expr;
|
Expr* expr;
|
||||||
Expr* expr2;
|
Expr* expr2;
|
||||||
char* name;
|
char* name;
|
||||||
uint pred_type;
|
|
||||||
float float_literal;
|
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
|
// 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* makeColumnRef(char* name);
|
||||||
Expr* makeFunctionRef(char* func_name, Expr* expr);
|
Expr* makeFunctionRef(char* func_name, Expr* expr);
|
||||||
Expr* makePredicate(Expr* expr1, uint op, Expr* expr2);
|
|
||||||
Expr* makeFloatLiteral(float value);
|
Expr* makeFloatLiteral(float value);
|
||||||
Expr* makeStringLiteral(char* string);
|
Expr* makeStringLiteral(char* string);
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,14 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#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(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(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(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) {
|
void printTableRefInfo(TableRef* table, uint num_indent) {
|
||||||
switch (table->type) {
|
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) {
|
void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
|
||||||
inprint("SelectStatement", num_indent);
|
inprint("SelectStatement", num_indent);
|
||||||
inprint("Fields:", num_indent+1);
|
inprint("Fields:", num_indent+1);
|
||||||
for (Expr* expr : stmt->select_list->_vector) {
|
for (Expr* expr : stmt->select_list->_vector) printExpression(expr, num_indent+2);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inprint("Sources:", num_indent+1);
|
inprint("Sources:", num_indent+1);
|
||||||
printTableRefInfo(stmt->from_table, num_indent+2);
|
printTableRefInfo(stmt->from_table, num_indent+2);
|
||||||
|
|
||||||
|
inprint("Search Conditions:", num_indent+1);
|
||||||
|
printExpression(stmt->where_clause, num_indent+2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
void SelectTest1() {
|
void SelectTest1() {
|
||||||
printf("Test: SelectTest1... "); fflush(stdout);
|
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);
|
Statement* sqlStatement = SQLParser::parseSQLString(sql);
|
||||||
ASSERT(sqlStatement != NULL);
|
ASSERT(sqlStatement != NULL);
|
||||||
ASSERT(sqlStatement->type == eSelect);
|
ASSERT(sqlStatement->type == eSelect);
|
||||||
|
@ -48,7 +48,7 @@ void SelectTest1() {
|
||||||
void SelectTest2() {
|
void SelectTest2() {
|
||||||
printf("Test: SelectTest2... "); fflush(stdout);
|
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);
|
Statement* stmt = SQLParser::parseSQLString(sql);
|
||||||
ASSERT(stmt != NULL);
|
ASSERT(stmt != NULL);
|
||||||
ASSERT(stmt->type == eSelect);
|
ASSERT(stmt->type == eSelect);
|
||||||
|
|
Loading…
Reference in New Issue