Implemented UNION and OFFSET

This commit is contained in:
Pedro 2014-11-13 01:27:47 +01:00
parent f2a9f5b3a8
commit dfbc50ed27
13 changed files with 167 additions and 77 deletions

View File

@ -10,8 +10,9 @@ make grammar_test -C src/
echo "\n\n" echo "\n\n"
./bin/analysis "SELECT t1.a AS id, t1.b, t2.c FROM \"tbl\" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5" # ./bin/analysis "SELECT t1.a AS id, t1.b, t2.c FROM \"tbl\" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5"
# ./bin/analysis "CREATE TABLE \"table\" FROM TBL FILE 'students.tbl'" # ./bin/analysis "CREATE TABLE \"table\" FROM TBL FILE 'students.tbl'"
./bin/analysis "SELECT * FROM t1 UNION (SELECT abc AS t FROM t2 ORDER BY col3 LIMIT 10) ORDER BY col1;"
echo "\n\n" echo "\n\n"

View File

@ -19,7 +19,11 @@ typedef enum {
* @struct CreateStatement * @struct CreateStatement
*/ */
struct CreateStatement : Statement { struct CreateStatement : Statement {
CreateStatement() : Statement(kStmtCreate) {}; CreateStatement() :
Statement(kStmtCreate),
file_path(NULL),
table_name(NULL) {};
virtual ~CreateStatement(); // defined in destructors.cpp virtual ~CreateStatement(); // defined in destructors.cpp
CreateType create_type; CreateType create_type;

View File

@ -50,7 +50,13 @@ struct Expr {
Expr(ExprType type) : type(type), expr(NULL), expr2(NULL), name(NULL), table(NULL), alias(NULL) {}; Expr(ExprType type) :
type(type),
expr(NULL),
expr2(NULL),
name(NULL),
table(NULL),
alias(NULL) {};
// Interesting side-effect: // Interesting side-effect:
// Making the destructor virtual causes segmentation faults // Making the destructor virtual causes segmentation faults

View File

@ -19,7 +19,11 @@ typedef enum {
* @struct ImportStatement * @struct ImportStatement
*/ */
struct ImportStatement : Statement { struct ImportStatement : Statement {
ImportStatement() : Statement(kStmtImport) {}; ImportStatement() :
Statement(kStmtImport),
file_path(NULL),
table_name(NULL) {};
virtual ~ImportStatement(); // defined in destructors.cpp virtual ~ImportStatement(); // defined in destructors.cpp
ImportFileType file_type; ImportFileType file_type;

View File

@ -20,7 +20,10 @@ typedef enum {
} OrderType; } OrderType;
struct OrderDescription { struct OrderDescription {
OrderDescription(OrderType type, Expr* expr) : type(type), expr(expr) {} OrderDescription(OrderType type, Expr* expr) :
type(type),
expr(expr) {}
virtual ~OrderDescription(); // defined in destructors.cpp virtual ~OrderDescription(); // defined in destructors.cpp
OrderType type; OrderType type;
@ -34,7 +37,10 @@ struct OrderDescription {
const int64_t kNoLimit = -1; const int64_t kNoLimit = -1;
const int64_t kNoOffset = -1; const int64_t kNoOffset = -1;
struct LimitDescription { struct LimitDescription {
LimitDescription(int64_t limit, int64_t offset) : limit(limit), offset(offset) {} LimitDescription(int64_t limit, int64_t offset) :
limit(limit),
offset(offset) {}
int64_t limit; int64_t limit;
int64_t offset; int64_t offset;
}; };
@ -44,15 +50,24 @@ struct LimitDescription {
* Representation of a full select statement. * Representation of a full select statement.
*/ */
struct SelectStatement : Statement { struct SelectStatement : Statement {
SelectStatement() : Statement(kStmtSelect) {}; SelectStatement() :
Statement(kStmtSelect),
from_table(NULL),
select_list(NULL),
where_clause(NULL),
group_by(NULL),
order(NULL),
limit(NULL),
union_select(NULL) {};
virtual ~SelectStatement(); // defined in destructors.cpp virtual ~SelectStatement(); // defined in destructors.cpp
TableRef* from_table; TableRef* from_table;
List<Expr*>* select_list; List<Expr*>* select_list;
Expr* where_clause; Expr* where_clause;
List<Expr*>* group_by; List<Expr*>* group_by;
SelectStatement* union_select;
OrderDescription* order; OrderDescription* order;
LimitDescription* limit; LimitDescription* limit;
}; };

View File

@ -11,7 +11,7 @@ namespace hsql {
typedef enum { typedef enum {
kStmtError, kStmtError, // Unused
kStmtSelect, kStmtSelect,
kStmtImport, kStmtImport,
// Following types are planned but not supported yet // Following types are planned but not supported yet
@ -26,7 +26,9 @@ typedef enum {
struct Statement { struct Statement {
Statement(StatementType type) : type(type) {}; Statement(StatementType type) :
type(type) {};
virtual ~Statement(); // defined in destructors.cpp virtual ~Statement(); // defined in destructors.cpp
StatementType type; StatementType type;
@ -35,8 +37,16 @@ struct Statement {
class StatementList : public List<Statement*> { class StatementList : public List<Statement*> {
public: public:
StatementList() : List<Statement*>(), isValid(true) {}; StatementList() :
StatementList(Statement* stmt) : List<Statement*>(stmt), isValid(true) {}; List<Statement*>(),
isValid(true),
parser_msg(NULL) {};
StatementList(Statement* stmt) :
List<Statement*>(stmt),
isValid(true),
parser_msg(NULL) {};
virtual ~StatementList(); // defined in destructors.cpp virtual ~StatementList(); // defined in destructors.cpp
bool isValid; bool isValid;

View File

@ -29,7 +29,16 @@ typedef enum {
typedef struct TableRef TableRef; typedef struct TableRef TableRef;
struct TableRef { struct TableRef {
TableRef(TableRefType type) : type(type) {} TableRef(TableRefType type) :
type(type),
name(NULL),
alias(NULL),
select(NULL),
list(NULL),
left(NULL),
right(NULL),
join_condition(NULL) {}
virtual ~TableRef(); // defined in destructors.cpp virtual ~TableRef(); // defined in destructors.cpp
TableRefType type; TableRefType type;

View File

@ -70,7 +70,7 @@ void printExpression(Expr* expr, uint num_indent) {
default: fprintf(stderr, "Unrecognized expression type %d\n", expr->type); return; default: fprintf(stderr, "Unrecognized expression type %d\n", expr->type); return;
} }
if (expr->alias != NULL) { if (expr->alias != NULL) {
inprint("Alias", num_indent); inprint(expr->alias, num_indent+1); inprint("Alias", num_indent+1); inprint(expr->alias, num_indent+2);
} }
} }
@ -87,6 +87,12 @@ void printSelectStatementInfo(SelectStatement* stmt, uint num_indent) {
printExpression(stmt->where_clause, num_indent+2); printExpression(stmt->where_clause, num_indent+2);
} }
if (stmt->union_select != NULL) {
inprint("Union:", num_indent+1);
printSelectStatementInfo(stmt->union_select, num_indent+2);
}
if (stmt->order != NULL) { if (stmt->order != NULL) {
inprint("OrderBy:", num_indent+1); inprint("OrderBy:", num_indent+1);
printExpression(stmt->order->expr, num_indent+2); printExpression(stmt->order->expr, num_indent+2);

View File

@ -105,12 +105,12 @@ typedef void* yyscan_t;
%token <uval> NOTEQUALS LESSEQ GREATEREQ %token <uval> NOTEQUALS LESSEQ GREATEREQ
/* SQL Keywords */ /* SQL Keywords */
%token DISTINCT DATABASE NATURAL CONTROL BETWEEN SELECT %token DATABASE DISTINCT BETWEEN CONTROL NATURAL COLUMN
%token HAVING OFFSET CREATE IMPORT RENAME DELETE INSERT %token CREATE DELETE HAVING IMPORT INSERT ISNULL OFFSET
%token UPDATE UNLOAD COLUMN ISNULL WHERE GROUP ORDER LIMIT %token RENAME SELECT UNLOAD UPDATE ALTER CROSS GROUP INDEX
%token INNER OUTER RIGHT CROSS USING TABLE INDEX ALTER FROM %token INNER LIMIT ORDER OUTER RIGHT TABLE UNION USING WHERE
%token DESC JOIN LEFT FILE DROP LOAD INTO NULL LIKE TOP ASC %token DESC DROP FILE FROM INTO JOIN LEFT LIKE LOAD NULL ALL
%token CSV TBL NOT AND BY ON AS OR IN IS %token AND ASC CSV NOT TBL TOP AS BY IN IS ON OR
/********************************* /*********************************
@ -118,7 +118,7 @@ typedef void* yyscan_t;
*********************************/ *********************************/
%type <stmt_list> statement_list %type <stmt_list> statement_list
%type <statement> statement %type <statement> statement
%type <select_stmt> select_statement %type <select_stmt> select_statement select_ref select_with_paren select_no_paren select_clause
%type <import_stmt> import_statement %type <import_stmt> import_statement
%type <create_stmt> create_statement %type <create_stmt> create_statement
%type <sval> table_name opt_alias alias file_path %type <sval> table_name opt_alias alias file_path
@ -126,12 +126,12 @@ typedef void* yyscan_t;
%type <table> join_clause join_table %type <table> join_clause join_table
%type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr expr_alias %type <expr> expr scalar_expr unary_expr binary_expr function_expr star_expr expr_alias
%type <expr> column_name literal int_literal num_literal string_literal %type <expr> column_name literal int_literal num_literal string_literal
%type <expr> comp_expr where_clause join_condition %type <expr> comp_expr opt_where join_condition
%type <expr_list> expr_list group_clause select_list %type <expr_list> expr_list opt_group select_list
%type <table_list> table_ref_commalist %type <table_list> table_ref_commalist
%type <order> order_by_clause %type <order> opt_order
%type <limit> limit_clause %type <limit> opt_limit
%type <order_type> order_type %type <order_type> opt_order_type
%type <uval> import_file_type %type <uval> import_file_type
@ -226,18 +226,42 @@ create_statement:
******************************/ ******************************/
select_statement: select_statement:
SELECT select_list from_clause where_clause group_clause order_by_clause limit_clause select_with_paren
{ | select_no_paren
SelectStatement* s = new SelectStatement(); ;
s->select_list = $2;
s->from_table = $3; select_with_paren:
s->where_clause = $4; '(' select_no_paren ')' { $$ = $2; }
s->group_by = $5; | '(' select_with_paren ')' { $$ = $2; }
s->order = $6; ;
s->limit = $7;
$$ = s; select_no_paren:
select_clause opt_order opt_limit {
$$ = $1;
$$->order = $2;
$$->limit = $3;
}
| select_ref UNION select_ref opt_order opt_limit {
$$ = $1;
$$->union_select = $3;
$$->order = $4;
$$->limit = $5;
}
;
select_ref:
select_clause
| select_with_paren
;
select_clause:
SELECT select_list from_clause opt_where opt_group {
$$ = new SelectStatement();
$$->select_list = $2;
$$->from_table = $3;
$$->where_clause = $4;
$$->group_by = $5;
} }
| '(' select_statement ')' { $$ = $2; }
; ;
@ -251,31 +275,33 @@ from_clause:
; ;
where_clause: opt_where:
WHERE expr { $$ = $2; } WHERE expr { $$ = $2; }
| /* empty */ { $$ = NULL; } | /* empty */ { $$ = NULL; }
; ;
// TODO: having // TODO: having
group_clause: opt_group:
GROUP BY expr_list { $$ = $3; } GROUP BY expr_list { $$ = $3; }
| /* empty */ { $$ = NULL; } | /* empty */ { $$ = NULL; }
; ;
order_by_clause: opt_order:
ORDER BY expr order_type { $$ = new OrderDescription($4, $3); } ORDER BY expr opt_order_type { $$ = new OrderDescription($4, $3); }
| /* empty */ { $$ = NULL; } | /* empty */ { $$ = NULL; }
; ;
order_type: opt_order_type:
ASC { $$ = kOrderAsc; } ASC { $$ = kOrderAsc; }
| DESC { $$ = kOrderDesc; } | DESC { $$ = kOrderDesc; }
| /* empty */ { $$ = kOrderAsc; } | /* empty */ { $$ = kOrderAsc; }
; ;
limit_clause:
opt_limit:
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; } LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
| LIMIT int_literal OFFSET int_literal { $$ = new LimitDescription($2->ival, $4->ival); delete $2; delete $4; }
| /* empty */ { $$ = NULL; } | /* empty */ { $$ = NULL; }
; ;

View File

@ -56,57 +56,59 @@
[ \t\n]+ /* skip whitespace */; [ \t\n]+ /* skip whitespace */;
DISTINCT TOKEN(DISTINCT)
DATABASE TOKEN(DATABASE) DATABASE TOKEN(DATABASE)
NATURAL TOKEN(NATURAL) DISTINCT TOKEN(DISTINCT)
CONTROL TOKEN(CONTROL)
BETWEEN TOKEN(BETWEEN) BETWEEN TOKEN(BETWEEN)
SELECT TOKEN(SELECT) CONTROL TOKEN(CONTROL)
HAVING TOKEN(HAVING) NATURAL TOKEN(NATURAL)
OFFSET TOKEN(OFFSET)
CREATE TOKEN(CREATE)
IMPORT TOKEN(IMPORT)
RENAME TOKEN(RENAME)
DELETE TOKEN(DELETE)
INSERT TOKEN(INSERT)
UPDATE TOKEN(UPDATE)
UNLOAD TOKEN(UNLOAD)
COLUMN TOKEN(COLUMN) COLUMN TOKEN(COLUMN)
CREATE TOKEN(CREATE)
DELETE TOKEN(DELETE)
HAVING TOKEN(HAVING)
IMPORT TOKEN(IMPORT)
INSERT TOKEN(INSERT)
ISNULL TOKEN(ISNULL) ISNULL TOKEN(ISNULL)
WHERE TOKEN(WHERE) OFFSET TOKEN(OFFSET)
RENAME TOKEN(RENAME)
SELECT TOKEN(SELECT)
UNLOAD TOKEN(UNLOAD)
UPDATE TOKEN(UPDATE)
ALTER TOKEN(ALTER)
CROSS TOKEN(CROSS)
GROUP TOKEN(GROUP) GROUP TOKEN(GROUP)
ORDER TOKEN(ORDER) INDEX TOKEN(INDEX)
LIMIT TOKEN(LIMIT)
INNER TOKEN(INNER) INNER TOKEN(INNER)
LIMIT TOKEN(LIMIT)
ORDER TOKEN(ORDER)
OUTER TOKEN(OUTER) OUTER TOKEN(OUTER)
RIGHT TOKEN(RIGHT) RIGHT TOKEN(RIGHT)
CROSS TOKEN(CROSS)
USING TOKEN(USING)
TABLE TOKEN(TABLE) TABLE TOKEN(TABLE)
INDEX TOKEN(INDEX) UNION TOKEN(UNION)
ALTER TOKEN(ALTER) USING TOKEN(USING)
FROM TOKEN(FROM) WHERE TOKEN(WHERE)
DESC TOKEN(DESC) DESC TOKEN(DESC)
DROP TOKEN(DROP)
FILE TOKEN(FILE)
FROM TOKEN(FROM)
INTO TOKEN(INTO)
JOIN TOKEN(JOIN) JOIN TOKEN(JOIN)
LEFT TOKEN(LEFT) LEFT TOKEN(LEFT)
FILE TOKEN(FILE)
DROP TOKEN(DROP)
LOAD TOKEN(LOAD)
INTO TOKEN(INTO)
NULL TOKEN(NULL)
LIKE TOKEN(LIKE) LIKE TOKEN(LIKE)
TOP TOKEN(TOP) LOAD TOKEN(LOAD)
NULL TOKEN(NULL)
ALL TOKEN(ALL)
AND TOKEN(AND)
ASC TOKEN(ASC) ASC TOKEN(ASC)
CSV TOKEN(CSV) CSV TOKEN(CSV)
TBL TOKEN(TBL)
NOT TOKEN(NOT) NOT TOKEN(NOT)
AND TOKEN(AND) TBL TOKEN(TBL)
BY TOKEN(BY) TOP TOKEN(TOP)
ON TOKEN(ON)
AS TOKEN(AS) AS TOKEN(AS)
OR TOKEN(OR) BY TOKEN(BY)
IN TOKEN(IN) IN TOKEN(IN)
IS TOKEN(IS) IS TOKEN(IS)
ON TOKEN(ON)
OR TOKEN(OR)
"<>" TOKEN(NOTEQUALS) "<>" TOKEN(NOTEQUALS)

View File

@ -5,7 +5,8 @@ import math
with open("sql_keywords.txt", 'r') as fh: with open("sql_keywords.txt", 'r') as fh:
keywords = [line.strip() for line in fh.readlines() if not line.strip().startswith("//") and len(line.strip()) > 0] keywords = [line.strip() for line in fh.readlines() if not line.strip().startswith("//") and len(line.strip()) > 0]
keywords = sorted(keywords, key=lambda x: len(x), reverse=True) keywords = sorted(keywords) # Sort by name
keywords = sorted(keywords, key=lambda x: len(x), reverse=True) # Sort by length
################# #################
# Flex # Flex

View File

@ -14,6 +14,8 @@ DESC
LIMIT LIMIT
DISTINCT DISTINCT
OFFSET OFFSET
UNION
ALL
// Join clause // Join clause
JOIN JOIN

View File

@ -5,6 +5,10 @@ SELECT col1 AS myname, col2, 'test' FROM "table", foo AS t WHERE age > 12 AND zi
SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5 SELECT * from "table" JOIN table2 ON a = b WHERE (b OR NOT a) AND a = 12.5
(SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10); (SELECT a FROM foo WHERE a > 12 OR b > 3 AND c NOT LIKE 's%' LIMIT 10);
SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5 SELECT t1.a, t1.b, t2.c FROM "table" AS t1 JOIN (SELECT * FROM foo JOIN bar ON foo.id = bar.id) t2 ON t1.a = t2.b WHERE (t1.b OR NOT t1.a) AND t2.c = 12.5
SELECT * FROM "table" LIMIT 10 OFFSET 10;
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY col1;
SELECT * FROM t1 UNION (SELECT * FROM t2) ORDER BY col1;
SELECT * FROM t1 UNION (SELECT * FROM t2 UNION SELECT * FROM t3) ORDER BY col1;
# CREATE statement # CREATE statement
CREATE TABLE "table" FROM TBL FILE 'students.tbl' CREATE TABLE "table" FROM TBL FILE 'students.tbl'
# Multiple statements # Multiple statements