Add support to identify different set operators & allow chain of multiple set operators ()

This commit is contained in:
Tobias Nack 2020-02-18 14:26:10 +01:00 committed by GitHub
parent 4b617bca96
commit e8ce1c4caf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 2018 additions and 1613 deletions

File diff suppressed because it is too large Load Diff

@ -1,4 +1,4 @@
/* A Bison parser, made by GNU Bison 3.4.1. */ /* A Bison parser, made by GNU Bison 3.4.2. */
/* Bison interface for Yacc-like parsers in C /* Bison interface for Yacc-like parsers in C
@ -273,6 +273,7 @@ union HSQL_STYPE
hsql::GroupByDescription* group_t; hsql::GroupByDescription* group_t;
hsql::UpdateClause* update_t; hsql::UpdateClause* update_t;
hsql::Alias* alias_t; hsql::Alias* alias_t;
hsql::SetOperation* set_operator_t;
std::vector<hsql::SQLStatement*>* stmt_vec; std::vector<hsql::SQLStatement*>* stmt_vec;
@ -284,7 +285,7 @@ union HSQL_STYPE
std::vector<hsql::OrderDescription*>* order_vec; std::vector<hsql::OrderDescription*>* order_vec;
std::vector<hsql::WithDescription*>* with_description_vec; std::vector<hsql::WithDescription*>* with_description_vec;
#line 288 "bison_parser.h" #line 289 "bison_parser.h"
}; };
typedef union HSQL_STYPE HSQL_STYPE; typedef union HSQL_STYPE HSQL_STYPE;

@ -127,6 +127,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
hsql::GroupByDescription* group_t; hsql::GroupByDescription* group_t;
hsql::UpdateClause* update_t; hsql::UpdateClause* update_t;
hsql::Alias* alias_t; hsql::Alias* alias_t;
hsql::SetOperation* set_operator_t;
std::vector<hsql::SQLStatement*>* stmt_vec; std::vector<hsql::SQLStatement*>* stmt_vec;
@ -191,7 +192,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%type <exec_stmt> execute_statement %type <exec_stmt> execute_statement
%type <transaction_stmt> transaction_statement %type <transaction_stmt> transaction_statement
%type <prep_stmt> prepare_statement %type <prep_stmt> prepare_statement
%type <select_stmt> select_statement select_with_paren select_no_paren select_clause select_paren_or_clause %type <select_stmt> select_statement select_with_paren select_no_paren select_clause select_within_set_operation select_within_set_operation_no_parentheses
%type <import_stmt> import_statement %type <import_stmt> import_statement
%type <export_stmt> export_statement %type <export_stmt> export_statement
%type <create_stmt> create_statement %type <create_stmt> create_statement
@ -202,7 +203,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%type <show_stmt> show_statement %type <show_stmt> show_statement
%type <table_name> table_name %type <table_name> table_name
%type <sval> file_path prepare_target_query %type <sval> file_path prepare_target_query
%type <bval> opt_not_exists opt_exists opt_distinct opt_column_nullable %type <bval> opt_not_exists opt_exists opt_distinct opt_column_nullable opt_all
%type <uval> opt_join_type %type <uval> opt_join_type
%type <table> opt_from_clause from_clause table_ref table_ref_atomic table_ref_name nonjoin_table_ref_atomic %type <table> opt_from_clause from_clause table_ref table_ref_atomic table_ref_name nonjoin_table_ref_atomic
%type <table> join_clause table_ref_name_no_alias %type <table> join_clause table_ref_name_no_alias
@ -221,6 +222,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
%type <group_t> opt_group %type <group_t> opt_group
%type <alias_t> opt_table_alias table_alias opt_alias alias %type <alias_t> opt_table_alias table_alias opt_alias alias
%type <with_description_t> with_description %type <with_description_t> with_description
%type <set_operator_t> set_operator set_type
// ImportType is used for compatibility reasons // ImportType is used for compatibility reasons
%type <import_type_t> opt_file_type file_type %type <import_type_t> opt_file_type file_type
@ -689,20 +691,32 @@ select_statement:
$$ = $2; $$ = $2;
$$->withDescriptions = $1; $$->withDescriptions = $1;
} }
| opt_with_clause select_with_paren set_operator select_paren_or_clause opt_order opt_limit { | opt_with_clause select_with_paren set_operator select_within_set_operation opt_order opt_limit {
// TODO: allow multiple unions (through linked list)
// TODO: capture type of set_operator
// TODO: might overwrite order and limit of first select here
$$ = $2; $$ = $2;
$$->withDescriptions = $1; if ($$->setOperations == nullptr) {
$$->unionSelect = $4; $$->setOperations = new std::vector<SetOperation*>();
$$->order = $5;
// Limit could have been set by TOP.
if ($6 != nullptr) {
delete $$->limit;
$$->limit = $6;
} }
$$->setOperations->push_back($3);
$$->setOperations->back()->nestedSelectStatement = $4;
$$->setOperations->back()->resultOrder = $5;
$$->setOperations->back()->resultLimit = $6;
$$->withDescriptions = $1;
}
;
select_within_set_operation:
select_with_paren
| select_within_set_operation_no_parentheses;
select_within_set_operation_no_parentheses:
select_clause { $$ = $1; }
| select_clause set_operator select_within_set_operation {
$$ = $1;
if ($$->setOperations == nullptr) {
$$->setOperations = new std::vector<SetOperation*>();
}
$$->setOperations->push_back($2);
$$->setOperations->back()->nestedSelectStatement = $3;
} }
; ;
@ -711,11 +725,6 @@ select_with_paren:
| '(' select_with_paren ')' { $$ = $2; } | '(' select_with_paren ')' { $$ = $2; }
; ;
select_paren_or_clause:
select_with_paren
| select_clause
;
select_no_paren: select_no_paren:
select_clause opt_order opt_limit { select_clause opt_order opt_limit {
$$ = $1; $$ = $1;
@ -727,35 +736,47 @@ select_no_paren:
$$->limit = $3; $$->limit = $3;
} }
} }
| select_clause set_operator select_paren_or_clause opt_order opt_limit { | select_clause set_operator select_within_set_operation opt_order opt_limit {
// TODO: allow multiple unions (through linked list)
// TODO: capture type of set_operator
// TODO: might overwrite order and limit of first select here
$$ = $1; $$ = $1;
$$->unionSelect = $3; if ($$->setOperations == nullptr) {
$$->order = $4; $$->setOperations = new std::vector<SetOperation*>();
// Limit could have been set by TOP.
if ($5 != nullptr) {
delete $$->limit;
$$->limit = $5;
} }
$$->setOperations->push_back($2);
$$->setOperations->back()->nestedSelectStatement = $3;
$$->setOperations->back()->resultOrder = $4;
$$->setOperations->back()->resultLimit = $5;
} }
; ;
set_operator: set_operator:
set_type opt_all set_type opt_all {
$$ = $1;
$$->isAll = $2;
}
; ;
set_type: set_type:
UNION UNION {
| INTERSECT $$ = new SetOperation();
| EXCEPT $$->setType = SetType::kSetUnion;
}
| INTERSECT {
$$ = new SetOperation();
$$->setType = SetType::kSetIntersect;
}
| EXCEPT {
$$ = new SetOperation();
$$->setType = SetType::kSetExcept;
}
; ;
opt_all: opt_all:
ALL ALL {
| /* empty */ $$ = true;
}
| /* empty */ {
$$ = false;
}
; ;
select_clause: select_clause:

@ -1,6 +1,6 @@
#line 2 "flex_lexer.cpp" #line 1 "flex_lexer.cpp"
#line 4 "flex_lexer.cpp" #line 3 "flex_lexer.cpp"
#define YY_INT_ALIGNED short int #define YY_INT_ALIGNED short int
@ -573,8 +573,8 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
yyg->yy_hold_char = *yy_cp; \ yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \ *yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp; yyg->yy_c_buf_p = yy_cp;
#define YY_NUM_RULES 156 #define YY_NUM_RULES 158
#define YY_END_OF_BUFFER 157 #define YY_END_OF_BUFFER 159
/* This struct is not used in this scanner, /* This struct is not used in this scanner,
but its presence is necessary. */ but its presence is necessary. */
struct yy_trans_info struct yy_trans_info
@ -584,25 +584,25 @@ struct yy_trans_info
}; };
static const flex_int16_t yy_accept[1072] = static const flex_int16_t yy_accept[1072] =
{ 0, { 0,
0, 0, 153, 153, 2, 2, 157, 155, 4, 4, 0, 0, 155, 155, 2, 2, 159, 157, 4, 4,
155, 155, 145, 151, 145, 145, 148, 145, 145, 145, 157, 157, 147, 153, 147, 147, 150, 147, 147, 147,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 150, 150, 150, 145, 153, 154, 2, 2, 3, 152, 152, 152, 152, 147, 155, 156, 2, 2, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 4, 140, 0, 1, 148, 2, 2, 2, 2, 2, 4, 142, 0, 1, 150,
147, 146, 142, 141, 139, 143, 150, 150, 150, 150, 149, 148, 144, 143, 141, 145, 152, 152, 152, 152,
150, 150, 118, 150, 119, 150, 150, 150, 150, 150, 152, 152, 120, 152, 121, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 150, 150, 150, 150, 120, 152, 152, 152, 152, 152, 152, 152, 152, 152, 122,
150, 150, 121, 122, 150, 150, 150, 150, 150, 150, 152, 152, 123, 124, 152, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 150, 123, 124, 125, 150, 152, 152, 152, 152, 152, 152, 125, 126, 127, 152,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 126, 150, 150, 150, 150, 152, 152, 152, 152, 152, 128, 152, 152, 152, 152,
150, 150, 150, 150, 150, 144, 153, 152, 2, 2, 152, 152, 152, 152, 152, 146, 155, 154, 2, 2,
2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -613,19 +613,19 @@ static const flex_int16_t yy_accept[1072] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
149, 146, 106, 150, 107, 150, 150, 108, 150, 109, 151, 148, 108, 152, 109, 152, 152, 110, 152, 111,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 150, 150, 130, 150, 150, 150, 150, 150, 150, 152, 152, 152, 132, 152, 152, 152, 152, 152, 152,
150, 150, 150, 110, 150, 150, 150, 150, 150, 150, 152, 152, 152, 112, 152, 152, 152, 152, 152, 152,
150, 150, 150, 111, 150, 150, 150, 150, 150, 150, 152, 152, 152, 113, 152, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 150, 150, 112, 150, 150, 152, 152, 152, 152, 152, 152, 152, 114, 152, 152,
113, 150, 150, 150, 150, 150, 150, 150, 150, 150, 115, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 114, 150, 150, 115, 150, 150, 150, 150, 150, 152, 116, 152, 152, 117, 152, 152, 152, 152, 152,
150, 150, 150, 150, 150, 150, 150, 150, 116, 150, 152, 152, 152, 152, 152, 152, 152, 152, 118, 152,
150, 150, 150, 150, 150, 150, 150, 117, 150, 150, 152, 152, 152, 152, 152, 152, 152, 119, 152, 152,
150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152,
150, 2, 2, 2, 2, 2, 2, 2, 2, 2, 152, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -637,18 +637,18 @@ static const flex_int16_t yy_accept[1072] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 150, 150, 150, 150, 150, 150, 150, 77, 2, 2, 152, 152, 152, 152, 152, 152, 152, 79,
150, 78, 79, 150, 150, 150, 80, 150, 150, 81, 152, 80, 81, 152, 152, 152, 82, 152, 152, 83,
150, 150, 150, 150, 82, 150, 150, 150, 83, 84, 152, 152, 152, 152, 84, 152, 152, 152, 85, 86,
150, 150, 150, 150, 150, 150, 150, 85, 150, 150, 152, 152, 152, 152, 152, 152, 152, 87, 152, 152,
86, 87, 150, 150, 88, 150, 89, 129, 150, 150, 88, 89, 152, 152, 90, 152, 91, 131, 152, 152,
150, 150, 150, 150, 90, 150, 91, 92, 93, 150, 152, 152, 152, 152, 92, 152, 93, 94, 95, 152,
95, 150, 96, 150, 150, 150, 150, 97, 150, 150, 97, 152, 98, 152, 152, 152, 152, 99, 152, 152,
150, 150, 150, 98, 150, 150, 150, 150, 150, 150, 152, 152, 152, 100, 152, 152, 152, 152, 152, 152,
150, 150, 150, 99, 150, 150, 150, 150, 100, 101, 152, 152, 152, 101, 152, 152, 152, 152, 102, 103,
102, 150, 133, 150, 150, 150, 150, 150, 150, 150, 104, 152, 135, 152, 152, 152, 152, 152, 152, 152,
150, 103, 150, 104, 150, 105, 132, 2, 2, 2, 152, 105, 152, 106, 152, 107, 134, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -661,14 +661,14 @@ static const flex_int16_t yy_accept[1072] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 57, 58, 150, 59, 150, 136, 150, 150, 2, 2, 57, 58, 152, 59, 152, 138, 152, 152,
150, 150, 150, 150, 60, 150, 150, 150, 61, 150, 152, 152, 152, 152, 60, 152, 152, 152, 61, 152,
150, 150, 150, 150, 150, 150, 150, 150, 150, 134, 152, 152, 152, 152, 152, 152, 152, 152, 152, 136,
62, 150, 150, 63, 150, 94, 150, 64, 65, 150, 62, 152, 152, 63, 152, 96, 152, 64, 65, 152,
150, 150, 150, 66, 67, 68, 69, 150, 131, 150, 152, 152, 152, 66, 67, 68, 69, 152, 133, 152,
150, 150, 70, 71, 150, 150, 150, 150, 150, 72, 152, 152, 70, 71, 152, 152, 152, 152, 152, 72,
150, 150, 150, 150, 150, 150, 73, 150, 150, 150, 152, 152, 152, 152, 152, 152, 73, 152, 152, 152,
150, 74, 150, 150, 150, 75, 150, 150, 150, 76, 152, 74, 152, 152, 152, 77, 152, 152, 152, 78,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@ -677,30 +677,30 @@ static const flex_int16_t yy_accept[1072] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 150, 31, 2, 2, 2, 2, 2, 2, 2, 2, 152, 31,
150, 150, 32, 138, 150, 33, 150, 150, 34, 150, 152, 152, 32, 140, 152, 33, 152, 152, 34, 152,
35, 150, 36, 37, 38, 150, 39, 150, 150, 41, 35, 152, 36, 37, 38, 152, 39, 152, 152, 41,
42, 43, 44, 45, 150, 150, 46, 128, 150, 150, 42, 43, 44, 45, 152, 152, 46, 130, 152, 152,
47, 150, 150, 150, 48, 150, 150, 49, 127, 50, 47, 152, 152, 152, 48, 152, 152, 49, 129, 50,
51, 150, 52, 150, 150, 150, 150, 53, 54, 55, 51, 152, 52, 152, 152, 152, 152, 53, 54, 55,
56, 150, 150, 2, 2, 2, 2, 2, 2, 2, 56, 152, 152, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 15, 16, 2, 2, 2, 2, 2, 2, 2, 2, 15, 16,
17, 18, 19, 150, 20, 150, 150, 21, 22, 40, 17, 18, 19, 152, 20, 152, 152, 21, 22, 40,
23, 150, 24, 150, 150, 25, 26, 150, 150, 27, 23, 152, 24, 152, 152, 25, 26, 152, 152, 27,
28, 150, 150, 150, 150, 29, 30, 2, 2, 2, 28, 152, 152, 152, 152, 29, 30, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 150, 10, 11, 150, 2, 2, 2, 2, 2, 2, 152, 10, 11, 152,
12, 150, 13, 137, 150, 150, 150, 14, 2, 2, 12, 152, 13, 139, 152, 152, 152, 14, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
150, 7, 150, 8, 9, 150, 2, 2, 2, 2, 152, 7, 152, 8, 9, 152, 2, 2, 2, 2,
2, 2, 5, 6, 150, 2, 2, 2, 135, 2, 2, 2, 5, 6, 152, 2, 2, 2, 137, 2,
0 0
} ; } ;
@ -1982,7 +1982,7 @@ static const flex_int16_t yy_chk[4346] =
static thread_local std::stringstream strbuf; static thread_local std::stringstream strbuf;
#line 1986 "flex_lexer.cpp" #line 1985 "flex_lexer.cpp"
/*************************** /***************************
** Section 2: Rules ** Section 2: Rules
@ -1996,7 +1996,7 @@ static thread_local std::stringstream strbuf;
/*************************** /***************************
** Section 3: Rules ** Section 3: Rules
***************************/ ***************************/
#line 2000 "flex_lexer.cpp" #line 1999 "flex_lexer.cpp"
#define INITIAL 0 #define INITIAL 0
#define singlequotedstring 1 #define singlequotedstring 1
@ -2283,7 +2283,7 @@ YY_DECL
#line 56 "flex_lexer.l" #line 56 "flex_lexer.l"
#line 2287 "flex_lexer.cpp" #line 2286 "flex_lexer.cpp"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{ {
@ -2711,430 +2711,440 @@ TOKEN(UNION)
case 75: case 75:
YY_RULE_SETUP YY_RULE_SETUP
#line 134 "flex_lexer.l" #line 134 "flex_lexer.l"
TOKEN(USING) TOKEN(INTERSECT)
YY_BREAK YY_BREAK
case 76: case 76:
YY_RULE_SETUP YY_RULE_SETUP
#line 135 "flex_lexer.l" #line 135 "flex_lexer.l"
TOKEN(WHERE) TOKEN(EXCEPT)
YY_BREAK YY_BREAK
case 77: case 77:
YY_RULE_SETUP YY_RULE_SETUP
#line 136 "flex_lexer.l" #line 136 "flex_lexer.l"
TOKEN(CALL) TOKEN(USING)
YY_BREAK YY_BREAK
case 78: case 78:
YY_RULE_SETUP YY_RULE_SETUP
#line 137 "flex_lexer.l" #line 137 "flex_lexer.l"
TOKEN(CASE) TOKEN(WHERE)
YY_BREAK YY_BREAK
case 79: case 79:
YY_RULE_SETUP YY_RULE_SETUP
#line 138 "flex_lexer.l" #line 138 "flex_lexer.l"
TOKEN(CHAR) TOKEN(CALL)
YY_BREAK YY_BREAK
case 80: case 80:
YY_RULE_SETUP YY_RULE_SETUP
#line 139 "flex_lexer.l" #line 139 "flex_lexer.l"
TOKEN(COPY) TOKEN(CASE)
YY_BREAK YY_BREAK
case 81: case 81:
YY_RULE_SETUP YY_RULE_SETUP
#line 140 "flex_lexer.l" #line 140 "flex_lexer.l"
TOKEN(DATE) TOKEN(CHAR)
YY_BREAK YY_BREAK
case 82: case 82:
YY_RULE_SETUP YY_RULE_SETUP
#line 141 "flex_lexer.l" #line 141 "flex_lexer.l"
TOKEN(DESC) TOKEN(COPY)
YY_BREAK YY_BREAK
case 83: case 83:
YY_RULE_SETUP YY_RULE_SETUP
#line 142 "flex_lexer.l" #line 142 "flex_lexer.l"
TOKEN(DROP) TOKEN(DATE)
YY_BREAK YY_BREAK
case 84: case 84:
YY_RULE_SETUP YY_RULE_SETUP
#line 143 "flex_lexer.l" #line 143 "flex_lexer.l"
TOKEN(ELSE) TOKEN(DESC)
YY_BREAK YY_BREAK
case 85: case 85:
YY_RULE_SETUP YY_RULE_SETUP
#line 144 "flex_lexer.l" #line 144 "flex_lexer.l"
TOKEN(FILE) TOKEN(DROP)
YY_BREAK YY_BREAK
case 86: case 86:
YY_RULE_SETUP YY_RULE_SETUP
#line 145 "flex_lexer.l" #line 145 "flex_lexer.l"
TOKEN(FROM) TOKEN(ELSE)
YY_BREAK YY_BREAK
case 87: case 87:
YY_RULE_SETUP YY_RULE_SETUP
#line 146 "flex_lexer.l" #line 146 "flex_lexer.l"
TOKEN(FULL) TOKEN(FILE)
YY_BREAK YY_BREAK
case 88: case 88:
YY_RULE_SETUP YY_RULE_SETUP
#line 147 "flex_lexer.l" #line 147 "flex_lexer.l"
TOKEN(HASH) TOKEN(FROM)
YY_BREAK YY_BREAK
case 89: case 89:
YY_RULE_SETUP YY_RULE_SETUP
#line 148 "flex_lexer.l" #line 148 "flex_lexer.l"
TOKEN(HINT) TOKEN(FULL)
YY_BREAK YY_BREAK
case 90: case 90:
YY_RULE_SETUP YY_RULE_SETUP
#line 149 "flex_lexer.l" #line 149 "flex_lexer.l"
TOKEN(INTO) TOKEN(HASH)
YY_BREAK YY_BREAK
case 91: case 91:
YY_RULE_SETUP YY_RULE_SETUP
#line 150 "flex_lexer.l" #line 150 "flex_lexer.l"
TOKEN(JOIN) TOKEN(HINT)
YY_BREAK YY_BREAK
case 92: case 92:
YY_RULE_SETUP YY_RULE_SETUP
#line 151 "flex_lexer.l" #line 151 "flex_lexer.l"
TOKEN(LEFT) TOKEN(INTO)
YY_BREAK YY_BREAK
case 93: case 93:
YY_RULE_SETUP YY_RULE_SETUP
#line 152 "flex_lexer.l" #line 152 "flex_lexer.l"
TOKEN(LIKE) TOKEN(JOIN)
YY_BREAK YY_BREAK
case 94: case 94:
YY_RULE_SETUP YY_RULE_SETUP
#line 153 "flex_lexer.l" #line 153 "flex_lexer.l"
TOKEN(ILIKE) TOKEN(LEFT)
YY_BREAK YY_BREAK
case 95: case 95:
YY_RULE_SETUP YY_RULE_SETUP
#line 154 "flex_lexer.l" #line 154 "flex_lexer.l"
TOKEN(LOAD) TOKEN(LIKE)
YY_BREAK YY_BREAK
case 96: case 96:
YY_RULE_SETUP YY_RULE_SETUP
#line 155 "flex_lexer.l" #line 155 "flex_lexer.l"
TOKEN(LONG) TOKEN(ILIKE)
YY_BREAK YY_BREAK
case 97: case 97:
YY_RULE_SETUP YY_RULE_SETUP
#line 156 "flex_lexer.l" #line 156 "flex_lexer.l"
TOKEN(NULL) TOKEN(LOAD)
YY_BREAK YY_BREAK
case 98: case 98:
YY_RULE_SETUP YY_RULE_SETUP
#line 157 "flex_lexer.l" #line 157 "flex_lexer.l"
TOKEN(PLAN) TOKEN(LONG)
YY_BREAK YY_BREAK
case 99: case 99:
YY_RULE_SETUP YY_RULE_SETUP
#line 158 "flex_lexer.l" #line 158 "flex_lexer.l"
TOKEN(SHOW) TOKEN(NULL)
YY_BREAK YY_BREAK
case 100: case 100:
YY_RULE_SETUP YY_RULE_SETUP
#line 159 "flex_lexer.l" #line 159 "flex_lexer.l"
TOKEN(TEXT) TOKEN(PLAN)
YY_BREAK YY_BREAK
case 101: case 101:
YY_RULE_SETUP YY_RULE_SETUP
#line 160 "flex_lexer.l" #line 160 "flex_lexer.l"
TOKEN(THEN) TOKEN(SHOW)
YY_BREAK YY_BREAK
case 102: case 102:
YY_RULE_SETUP YY_RULE_SETUP
#line 161 "flex_lexer.l" #line 161 "flex_lexer.l"
TOKEN(TIME) TOKEN(TEXT)
YY_BREAK YY_BREAK
case 103: case 103:
YY_RULE_SETUP YY_RULE_SETUP
#line 162 "flex_lexer.l" #line 162 "flex_lexer.l"
TOKEN(VIEW) TOKEN(THEN)
YY_BREAK YY_BREAK
case 104: case 104:
YY_RULE_SETUP YY_RULE_SETUP
#line 163 "flex_lexer.l" #line 163 "flex_lexer.l"
TOKEN(WHEN) TOKEN(TIME)
YY_BREAK YY_BREAK
case 105: case 105:
YY_RULE_SETUP YY_RULE_SETUP
#line 164 "flex_lexer.l" #line 164 "flex_lexer.l"
TOKEN(WITH) TOKEN(VIEW)
YY_BREAK YY_BREAK
case 106: case 106:
YY_RULE_SETUP YY_RULE_SETUP
#line 165 "flex_lexer.l" #line 165 "flex_lexer.l"
TOKEN(ADD) TOKEN(WHEN)
YY_BREAK YY_BREAK
case 107: case 107:
YY_RULE_SETUP YY_RULE_SETUP
#line 166 "flex_lexer.l" #line 166 "flex_lexer.l"
TOKEN(ALL) TOKEN(WITH)
YY_BREAK YY_BREAK
case 108: case 108:
YY_RULE_SETUP YY_RULE_SETUP
#line 167 "flex_lexer.l" #line 167 "flex_lexer.l"
TOKEN(AND) TOKEN(ADD)
YY_BREAK YY_BREAK
case 109: case 109:
YY_RULE_SETUP YY_RULE_SETUP
#line 168 "flex_lexer.l" #line 168 "flex_lexer.l"
TOKEN(ASC) TOKEN(ALL)
YY_BREAK YY_BREAK
case 110: case 110:
YY_RULE_SETUP YY_RULE_SETUP
#line 169 "flex_lexer.l" #line 169 "flex_lexer.l"
TOKEN(END) TOKEN(AND)
YY_BREAK YY_BREAK
case 111: case 111:
YY_RULE_SETUP YY_RULE_SETUP
#line 170 "flex_lexer.l" #line 170 "flex_lexer.l"
TOKEN(FOR) TOKEN(ASC)
YY_BREAK YY_BREAK
case 112: case 112:
YY_RULE_SETUP YY_RULE_SETUP
#line 171 "flex_lexer.l" #line 171 "flex_lexer.l"
TOKEN(INT) TOKEN(END)
YY_BREAK YY_BREAK
case 113: case 113:
YY_RULE_SETUP YY_RULE_SETUP
#line 172 "flex_lexer.l" #line 172 "flex_lexer.l"
TOKEN(KEY) TOKEN(FOR)
YY_BREAK YY_BREAK
case 114: case 114:
YY_RULE_SETUP YY_RULE_SETUP
#line 173 "flex_lexer.l" #line 173 "flex_lexer.l"
TOKEN(NOT) TOKEN(INT)
YY_BREAK YY_BREAK
case 115: case 115:
YY_RULE_SETUP YY_RULE_SETUP
#line 174 "flex_lexer.l" #line 174 "flex_lexer.l"
TOKEN(OFF) TOKEN(KEY)
YY_BREAK YY_BREAK
case 116: case 116:
YY_RULE_SETUP YY_RULE_SETUP
#line 175 "flex_lexer.l" #line 175 "flex_lexer.l"
TOKEN(SET) TOKEN(NOT)
YY_BREAK YY_BREAK
case 117: case 117:
YY_RULE_SETUP YY_RULE_SETUP
#line 176 "flex_lexer.l" #line 176 "flex_lexer.l"
TOKEN(TOP) TOKEN(OFF)
YY_BREAK YY_BREAK
case 118: case 118:
YY_RULE_SETUP YY_RULE_SETUP
#line 177 "flex_lexer.l" #line 177 "flex_lexer.l"
TOKEN(AS) TOKEN(SET)
YY_BREAK YY_BREAK
case 119: case 119:
YY_RULE_SETUP YY_RULE_SETUP
#line 178 "flex_lexer.l" #line 178 "flex_lexer.l"
TOKEN(BY) TOKEN(TOP)
YY_BREAK YY_BREAK
case 120: case 120:
YY_RULE_SETUP YY_RULE_SETUP
#line 179 "flex_lexer.l" #line 179 "flex_lexer.l"
TOKEN(IF) TOKEN(AS)
YY_BREAK YY_BREAK
case 121: case 121:
YY_RULE_SETUP YY_RULE_SETUP
#line 180 "flex_lexer.l" #line 180 "flex_lexer.l"
TOKEN(IN) TOKEN(BY)
YY_BREAK YY_BREAK
case 122: case 122:
YY_RULE_SETUP YY_RULE_SETUP
#line 181 "flex_lexer.l" #line 181 "flex_lexer.l"
TOKEN(IS) TOKEN(IF)
YY_BREAK YY_BREAK
case 123: case 123:
YY_RULE_SETUP YY_RULE_SETUP
#line 182 "flex_lexer.l" #line 182 "flex_lexer.l"
TOKEN(OF) TOKEN(IN)
YY_BREAK YY_BREAK
case 124: case 124:
YY_RULE_SETUP YY_RULE_SETUP
#line 183 "flex_lexer.l" #line 183 "flex_lexer.l"
TOKEN(ON) TOKEN(IS)
YY_BREAK YY_BREAK
case 125: case 125:
YY_RULE_SETUP YY_RULE_SETUP
#line 184 "flex_lexer.l" #line 184 "flex_lexer.l"
TOKEN(OR) TOKEN(OF)
YY_BREAK YY_BREAK
case 126: case 126:
YY_RULE_SETUP YY_RULE_SETUP
#line 185 "flex_lexer.l" #line 185 "flex_lexer.l"
TOKEN(TO) TOKEN(ON)
YY_BREAK YY_BREAK
case 127: case 127:
YY_RULE_SETUP YY_RULE_SETUP
#line 186 "flex_lexer.l" #line 186 "flex_lexer.l"
TOKEN(SECOND) TOKEN(OR)
YY_BREAK YY_BREAK
case 128: case 128:
YY_RULE_SETUP YY_RULE_SETUP
#line 187 "flex_lexer.l" #line 187 "flex_lexer.l"
TOKEN(MINUTE) TOKEN(TO)
YY_BREAK YY_BREAK
case 129: case 129:
YY_RULE_SETUP YY_RULE_SETUP
#line 188 "flex_lexer.l" #line 188 "flex_lexer.l"
TOKEN(HOUR) TOKEN(SECOND)
YY_BREAK YY_BREAK
case 130: case 130:
YY_RULE_SETUP YY_RULE_SETUP
#line 189 "flex_lexer.l" #line 189 "flex_lexer.l"
TOKEN(DAY) TOKEN(MINUTE)
YY_BREAK YY_BREAK
case 131: case 131:
YY_RULE_SETUP YY_RULE_SETUP
#line 190 "flex_lexer.l" #line 190 "flex_lexer.l"
TOKEN(MONTH) TOKEN(HOUR)
YY_BREAK YY_BREAK
case 132: case 132:
YY_RULE_SETUP YY_RULE_SETUP
#line 191 "flex_lexer.l" #line 191 "flex_lexer.l"
TOKEN(YEAR) TOKEN(DAY)
YY_BREAK YY_BREAK
case 133: case 133:
YY_RULE_SETUP YY_RULE_SETUP
#line 192 "flex_lexer.l" #line 192 "flex_lexer.l"
TOKEN(TRUE) TOKEN(MONTH)
YY_BREAK YY_BREAK
case 134: case 134:
YY_RULE_SETUP YY_RULE_SETUP
#line 193 "flex_lexer.l" #line 193 "flex_lexer.l"
TOKEN(FALSE) TOKEN(YEAR)
YY_BREAK YY_BREAK
case 135: case 135:
YY_RULE_SETUP YY_RULE_SETUP
#line 194 "flex_lexer.l" #line 194 "flex_lexer.l"
TOKEN(TRANSACTION) TOKEN(TRUE)
YY_BREAK YY_BREAK
case 136: case 136:
YY_RULE_SETUP YY_RULE_SETUP
#line 195 "flex_lexer.l" #line 195 "flex_lexer.l"
TOKEN(BEGIN) TOKEN(FALSE)
YY_BREAK YY_BREAK
case 137: case 137:
YY_RULE_SETUP YY_RULE_SETUP
#line 196 "flex_lexer.l" #line 196 "flex_lexer.l"
TOKEN(ROLLBACK) TOKEN(TRANSACTION)
YY_BREAK YY_BREAK
case 138: case 138:
YY_RULE_SETUP YY_RULE_SETUP
#line 197 "flex_lexer.l" #line 197 "flex_lexer.l"
TOKEN(COMMIT) TOKEN(BEGIN)
YY_BREAK YY_BREAK
/* Allow =/== see https://sqlite.org/lang_expr.html#collateop */
case 139: case 139:
YY_RULE_SETUP YY_RULE_SETUP
#line 200 "flex_lexer.l" #line 198 "flex_lexer.l"
TOKEN(EQUALS) TOKEN(ROLLBACK)
YY_BREAK YY_BREAK
case 140: case 140:
YY_RULE_SETUP YY_RULE_SETUP
#line 201 "flex_lexer.l" #line 199 "flex_lexer.l"
TOKEN(NOTEQUALS) TOKEN(COMMIT)
YY_BREAK YY_BREAK
/* Allow =/== see https://sqlite.org/lang_expr.html#collateop */
case 141: case 141:
YY_RULE_SETUP YY_RULE_SETUP
#line 202 "flex_lexer.l" #line 202 "flex_lexer.l"
TOKEN(NOTEQUALS) TOKEN(EQUALS)
YY_BREAK YY_BREAK
case 142: case 142:
YY_RULE_SETUP YY_RULE_SETUP
#line 203 "flex_lexer.l" #line 203 "flex_lexer.l"
TOKEN(LESSEQ) TOKEN(NOTEQUALS)
YY_BREAK YY_BREAK
case 143: case 143:
YY_RULE_SETUP YY_RULE_SETUP
#line 204 "flex_lexer.l" #line 204 "flex_lexer.l"
TOKEN(GREATEREQ) TOKEN(NOTEQUALS)
YY_BREAK YY_BREAK
case 144: case 144:
YY_RULE_SETUP YY_RULE_SETUP
#line 205 "flex_lexer.l" #line 205 "flex_lexer.l"
TOKEN(CONCAT) TOKEN(LESSEQ)
YY_BREAK YY_BREAK
case 145: case 145:
YY_RULE_SETUP YY_RULE_SETUP
#line 207 "flex_lexer.l" #line 206 "flex_lexer.l"
{ return yytext[0]; } TOKEN(GREATEREQ)
YY_BREAK YY_BREAK
case 146: case 146:
#line 210 "flex_lexer.l" YY_RULE_SETUP
#line 207 "flex_lexer.l"
TOKEN(CONCAT)
YY_BREAK
case 147: case 147:
YY_RULE_SETUP YY_RULE_SETUP
#line 210 "flex_lexer.l" #line 209 "flex_lexer.l"
{ return yytext[0]; }
YY_BREAK
case 148:
#line 212 "flex_lexer.l"
case 149:
YY_RULE_SETUP
#line 212 "flex_lexer.l"
{ {
yylval->fval = atof(yytext); yylval->fval = atof(yytext);
return SQL_FLOATVAL; return SQL_FLOATVAL;
} }
YY_BREAK YY_BREAK
case 148: case 150:
YY_RULE_SETUP YY_RULE_SETUP
#line 215 "flex_lexer.l" #line 217 "flex_lexer.l"
{ {
yylval->ival = atol(yytext); yylval->ival = atol(yytext);
return SQL_INTVAL; return SQL_INTVAL;
} }
YY_BREAK YY_BREAK
case 149: case 151:
YY_RULE_SETUP YY_RULE_SETUP
#line 220 "flex_lexer.l" #line 222 "flex_lexer.l"
{ {
// Crop the leading and trailing quote char // Crop the leading and trailing quote char
yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1); yylval->sval = hsql::substr(yytext, 1, strlen(yytext)-1);
return SQL_IDENTIFIER; return SQL_IDENTIFIER;
} }
YY_BREAK YY_BREAK
case 150: case 152:
YY_RULE_SETUP YY_RULE_SETUP
#line 226 "flex_lexer.l" #line 228 "flex_lexer.l"
{ {
yylval->sval = strdup(yytext); yylval->sval = strdup(yytext);
return SQL_IDENTIFIER; return SQL_IDENTIFIER;
} }
YY_BREAK YY_BREAK
case 151:
YY_RULE_SETUP
#line 231 "flex_lexer.l"
{ BEGIN singlequotedstring; strbuf = std::stringstream{}; }
YY_BREAK
case 152:
YY_RULE_SETUP
#line 232 "flex_lexer.l"
{ strbuf << '\''; }
YY_BREAK
case 153: case 153:
/* rule 153 can match eol */
YY_RULE_SETUP YY_RULE_SETUP
#line 233 "flex_lexer.l" #line 233 "flex_lexer.l"
{ strbuf << yytext; } { BEGIN singlequotedstring; strbuf = std::stringstream{}; }
YY_BREAK YY_BREAK
case 154: case 154:
YY_RULE_SETUP YY_RULE_SETUP
#line 234 "flex_lexer.l" #line 234 "flex_lexer.l"
{ BEGIN 0; yylval->sval = strdup(strbuf.str().c_str()); return SQL_STRING; } { strbuf << '\''; }
YY_BREAK
case YY_STATE_EOF(singlequotedstring):
#line 235 "flex_lexer.l"
{ fprintf(stderr, "[SQL-Lexer-Error] Unterminated string\n"); return 0; }
YY_BREAK YY_BREAK
case 155: case 155:
/* rule 155 can match eol */
YY_RULE_SETUP YY_RULE_SETUP
#line 237 "flex_lexer.l" #line 235 "flex_lexer.l"
{ fprintf(stderr, "[SQL-Lexer-Error] Unknown Character: %c\n", yytext[0]); return 0; } { strbuf << yytext; }
YY_BREAK YY_BREAK
case 156: case 156:
YY_RULE_SETUP YY_RULE_SETUP
#line 240 "flex_lexer.l" #line 236 "flex_lexer.l"
{ BEGIN 0; yylval->sval = strdup(strbuf.str().c_str()); return SQL_STRING; }
YY_BREAK
case YY_STATE_EOF(singlequotedstring):
#line 237 "flex_lexer.l"
{ fprintf(stderr, "[SQL-Lexer-Error] Unterminated string\n"); return 0; }
YY_BREAK
case 157:
YY_RULE_SETUP
#line 239 "flex_lexer.l"
{ fprintf(stderr, "[SQL-Lexer-Error] Unknown Character: %c\n", yytext[0]); return 0; }
YY_BREAK
case 158:
YY_RULE_SETUP
#line 242 "flex_lexer.l"
ECHO; ECHO;
YY_BREAK YY_BREAK
#line 3138 "flex_lexer.cpp" #line 3147 "flex_lexer.cpp"
case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(INITIAL):
case YY_STATE_EOF(COMMENT): case YY_STATE_EOF(COMMENT):
yyterminate(); yyterminate();
@ -4291,7 +4301,7 @@ void yyfree (void * ptr , yyscan_t yyscanner)
#define YYTABLES_NAME "yytables" #define YYTABLES_NAME "yytables"
#line 240 "flex_lexer.l" #line 242 "flex_lexer.l"
/*************************** /***************************
** Section 3: User code ** Section 3: User code

@ -2,9 +2,9 @@
#define hsql_HEADER_H 1 #define hsql_HEADER_H 1
#define hsql_IN_HEADER 1 #define hsql_IN_HEADER 1
#line 6 "flex_lexer.h" #line 5 "flex_lexer.h"
#line 8 "flex_lexer.h" #line 7 "flex_lexer.h"
#define YY_INT_ALIGNED short int #define YY_INT_ALIGNED short int
@ -730,9 +730,9 @@ extern int yylex \
#undef yyTABLES_NAME #undef yyTABLES_NAME
#endif #endif
#line 240 "flex_lexer.l" #line 242 "flex_lexer.l"
#line 737 "flex_lexer.h" #line 736 "flex_lexer.h"
#undef hsql_IN_HEADER #undef hsql_IN_HEADER
#endif /* hsql_HEADER_H */ #endif /* hsql_HEADER_H */

@ -131,6 +131,8 @@ OUTER TOKEN(OUTER)
RIGHT TOKEN(RIGHT) RIGHT TOKEN(RIGHT)
TABLE TOKEN(TABLE) TABLE TOKEN(TABLE)
UNION TOKEN(UNION) UNION TOKEN(UNION)
INTERSECT TOKEN(INTERSECT)
EXCEPT TOKEN(EXCEPT)
USING TOKEN(USING) USING TOKEN(USING)
WHERE TOKEN(WHERE) WHERE TOKEN(WHERE)
CALL TOKEN(CALL) CALL TOKEN(CALL)

@ -11,6 +11,11 @@ namespace hsql {
kOrderDesc kOrderDesc
}; };
enum SetType {
kSetUnion,
kSetIntersect,
kSetExcept
};
// Description of the order by clause within a select statement. // Description of the order by clause within a select statement.
struct OrderDescription { struct OrderDescription {
@ -46,8 +51,20 @@ namespace hsql {
SelectStatement* select; SelectStatement* select;
}; };
struct SetOperation {
SetOperation();
virtual ~SetOperation();
SetType setType;
bool isAll;
SelectStatement* nestedSelectStatement;
std::vector<OrderDescription*>* resultOrder;
LimitDescription* resultLimit;
};
// Representation of a full SQL select statement. // Representation of a full SQL select statement.
// TODO: add union_order and union_limit.
struct SelectStatement : SQLStatement { struct SelectStatement : SQLStatement {
SelectStatement(); SelectStatement();
virtual ~SelectStatement(); virtual ~SelectStatement();
@ -58,7 +75,32 @@ namespace hsql {
Expr* whereClause; Expr* whereClause;
GroupByDescription* groupBy; GroupByDescription* groupBy;
SelectStatement* unionSelect; // Note that a SetOperation is always connected to a
// different SelectStatement. This statement can itself
// have SetOperation connections to other SelectStatements.
// To evaluate the operations in the correct order:
// Iterate over the setOperations vector:
// 1. Fully evaluate the nestedSelectStatement within the SetOperation
// 2. Connect the original statement with the
// evaluated nestedSelectStatement
// 3. Apply the resultOrder and the resultLimit
// 4. The result now functions as the the original statement
// for the next iteration
//
// Example:
//
// (SELECT * FROM students INTERSECT SELECT * FROM students_2) UNION SELECT * FROM students_3 ORDER BY grade ASC;
//
// 1. We evaluate `Select * FROM students`
// 2. Then we iterate over the setOperations vector
// 3. We evalute the nestedSelectStatement of the first entry, which is: `SELECT * FROM students_2`
// 4. We connect the result of 1. with the results of 3. using the setType, which is INTERSECT
// 5. We continue the iteration of the setOperations vector
// 6. We evaluate the new nestedSelectStatement which is: `SELECT * FROM students_3`
// 7. We apply a Union-Operation to connect the results of 4. and 6.
// 8. Finally, we apply the resultOrder of the last SetOperation (ORDER BY grade ASC)
std::vector<SetOperation*>* setOperations;
std::vector<OrderDescription*>* order; std::vector<OrderDescription*>* order;
std::vector<WithDescription*>* withDescriptions; std::vector<WithDescription*>* withDescriptions;
LimitDescription* limit; LimitDescription* limit;

@ -262,7 +262,7 @@ namespace hsql {
selectList(nullptr), selectList(nullptr),
whereClause(nullptr), whereClause(nullptr),
groupBy(nullptr), groupBy(nullptr),
unionSelect(nullptr), setOperations(nullptr),
order(nullptr), order(nullptr),
withDescriptions(nullptr), withDescriptions(nullptr),
limit(nullptr) {}; limit(nullptr) {};
@ -271,7 +271,6 @@ namespace hsql {
delete fromTable; delete fromTable;
delete whereClause; delete whereClause;
delete groupBy; delete groupBy;
delete unionSelect;
delete limit; delete limit;
// Delete each element in the select list. // Delete each element in the select list.
@ -295,6 +294,13 @@ namespace hsql {
} }
delete withDescriptions; delete withDescriptions;
} }
if (setOperations != nullptr) {
for (SetOperation* setOperation : *setOperations) {
delete setOperation;
}
delete setOperations;
}
} }
// UpdateStatement // UpdateStatement
@ -381,4 +387,21 @@ namespace hsql {
delete condition; delete condition;
} }
SetOperation::SetOperation() :
nestedSelectStatement(nullptr),
resultOrder(nullptr),
resultLimit(nullptr) {}
SetOperation::~SetOperation() {
delete nestedSelectStatement;
delete resultLimit;
if (resultOrder != nullptr) {
for (OrderDescription* desc: *resultOrder) {
delete desc;
}
delete resultOrder;
}
}
} // namespace hsql } // namespace hsql

@ -168,9 +168,41 @@ namespace hsql {
} }
} }
if (stmt->unionSelect != nullptr) { if (stmt->setOperations != nullptr) {
for (SetOperation* setOperation : *stmt->setOperations) {
switch (setOperation->setType) {
case SetType::kSetIntersect:
inprint("Intersect:", numIndent + 1);
break;
case SetType::kSetUnion:
inprint("Union:", numIndent + 1); inprint("Union:", numIndent + 1);
printSelectStatementInfo(stmt->unionSelect, numIndent + 2); break;
case SetType::kSetExcept:
inprint("Except:", numIndent + 1);
break;
}
printSelectStatementInfo(setOperation->nestedSelectStatement, numIndent + 2);
if (setOperation->resultOrder != nullptr) {
inprint("SetResultOrderBy:", numIndent + 1);
printExpression(setOperation->resultOrder->at(0)->expr, numIndent + 2);
if (setOperation->resultOrder->at(0)->type == kOrderAsc) inprint("ascending", numIndent + 2);
else inprint("descending", numIndent + 2);
}
if (setOperation->resultLimit != nullptr) {
if (setOperation->resultLimit->limit != nullptr) {
inprint("SetResultLimit:", numIndent + 1);
printExpression(setOperation->resultLimit->limit, numIndent + 2);
}
if (setOperation->resultLimit->offset != nullptr) {
inprint("SetResultOffset:", numIndent + 1);
printExpression(setOperation->resultLimit->offset, numIndent + 2);
}
}
}
} }
if (stmt->order != nullptr) { if (stmt->order != nullptr) {

@ -105,7 +105,6 @@ TEST(UpdateStatementTest) {
ASSERT_STREQ(stmt->where->expr2->name, "Max O'Mustermann"); ASSERT_STREQ(stmt->where->expr2->name, "Max O'Mustermann");
} }
TEST(InsertStatementTest) { TEST(InsertStatementTest) {
TEST_PARSE_SINGLE_SQL( TEST_PARSE_SINGLE_SQL(
"INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)", "INSERT INTO students VALUES ('Max Mustermann', 12345, 'Musterhausen', 2.0)",
@ -118,7 +117,6 @@ TEST(InsertStatementTest) {
// TODO // TODO
} }
TEST(DropTableStatementTest) { TEST(DropTableStatementTest) {
TEST_PARSE_SINGLE_SQL( TEST_PARSE_SINGLE_SQL(
"DROP TABLE students", "DROP TABLE students",
@ -281,7 +279,6 @@ TEST(HintTest) {
result, result,
stmt); stmt);
ASSERT_NOTNULL(stmt->hints); ASSERT_NOTNULL(stmt->hints);
ASSERT_EQ(2, stmt->hints->size()); ASSERT_EQ(2, stmt->hints->size());
ASSERT_STREQ("NO_CACHE", stmt->hints->at(0)->name); ASSERT_STREQ("NO_CACHE", stmt->hints->at(0)->name);
@ -301,6 +298,190 @@ TEST(StringLengthTest) {
ASSERT_EQ(result.getStatement(2)->stringLength, 21); ASSERT_EQ(result.getStatement(2)->stringLength, 21);
} }
TEST(ExceptOperatorTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students EXCEPT SELECT * FROM students_2;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
ASSERT_STREQ(stmt->fromTable->name, "students");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
}
TEST(IntersectOperatorTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students INTERSECT SELECT * FROM students_2;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
ASSERT_STREQ(stmt->fromTable->name, "students");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetIntersect);
}
TEST(UnionOperatorTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students UNION SELECT * FROM students_2;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
ASSERT_STREQ(stmt->fromTable->name, "students");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetUnion);
ASSERT_FALSE(stmt->setOperations->back()->isAll);
}
TEST(UnionAllOperatorTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students UNION ALL SELECT * FROM students_2;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
ASSERT_STREQ(stmt->fromTable->name, "students");
ASSERT_TRUE(stmt->setOperations->back()->isAll);
}
TEST(NestedSetOperationTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students INTERSECT SELECT grade FROM students_2 UNION SELECT * FROM employees;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->setOperations->back()->nestedSelectStatement->fromTable->name, "employees");
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "students_2");
ASSERT_STREQ(stmt->fromTable->name, "students");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetIntersect);
ASSERT_EQ(stmt->setOperations->back()->nestedSelectStatement->setOperations->back()->setType, kSetUnion);
ASSERT_FALSE(stmt->setOperations->back()->isAll);
}
TEST(OrderByFullStatementTest) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students INTERSECT SELECT grade FROM students_2 UNION SELECT * FROM employees ORDER BY grade ASC;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_EQ(stmt->setOperations->back()->resultOrder->at(0)->type, kOrderAsc);
ASSERT_STREQ(stmt->setOperations->back()->resultOrder->at(0)->expr->name, "grade");
ASSERT_FALSE(stmt->setOperations->back()->isAll);
}
TEST(SetOperationSubQueryOrder) {
TEST_PARSE_SINGLE_SQL(
"(SELECT * FROM students ORDER BY name DESC) INTERSECT SELECT grade FROM students_2 UNION SELECT * FROM employees ORDER BY grade ASC;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_EQ(stmt->order->at(0)->type, kOrderDesc);
ASSERT_STREQ(stmt->order->at(0)->expr->name, "name");
ASSERT_EQ(stmt->setOperations->back()->resultOrder->at(0)->type, kOrderAsc);
ASSERT_STREQ(stmt->setOperations->back()->resultOrder->at(0)->expr->name, "grade");
ASSERT_FALSE(stmt->setOperations->back()->isAll);
}
TEST(SetOperationLastSubQueryOrder) {
TEST_PARSE_SINGLE_SQL(
"SELECT * FROM students INTERSECT SELECT grade FROM students_2 UNION (SELECT * FROM employees ORDER BY name DESC) ORDER BY grade ASC;",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_EQ(stmt->setOperations->back()->nestedSelectStatement->setOperations->back()->nestedSelectStatement->order->at(0)->type, kOrderDesc);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->setOperations->back()->nestedSelectStatement->order->at(0)->expr->name, "name");
ASSERT_EQ(stmt->setOperations->back()->resultOrder->at(0)->type, kOrderAsc);
ASSERT_STREQ(stmt->setOperations->back()->resultOrder->at(0)->expr->name, "grade");
ASSERT_FALSE(stmt->setOperations->back()->isAll);
}
TEST(NestedDifferentSetOperationsWithWithClause) {
TEST_PARSE_SINGLE_SQL("WITH UNION_FIRST AS (SELECT * FROM A UNION SELECT * FROM B) SELECT * FROM UNION_FIRST EXCEPT SELECT * FROM C",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->withDescriptions->back()->alias, "UNION_FIRST");
ASSERT_EQ(stmt->withDescriptions->back()->select->setOperations->back()->setType, kSetUnion);
ASSERT_STREQ(stmt->withDescriptions->back()->select->fromTable->name, "A");
ASSERT_STREQ(stmt->withDescriptions->back()->select->setOperations->back()->nestedSelectStatement->fromTable->name, "B");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
ASSERT_STREQ(stmt->fromTable->name, "UNION_FIRST");
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "C");
}
TEST(NestedAllSetOperationsWithWithClause) {
TEST_PARSE_SINGLE_SQL("WITH UNION_FIRST AS (SELECT * FROM A UNION SELECT * FROM B) SELECT * FROM UNION_FIRST EXCEPT SELECT * FROM (SELECT * FROM C INTERSECT SELECT * FROM D)",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->withDescriptions->back()->alias, "UNION_FIRST");
ASSERT_EQ(stmt->withDescriptions->back()->select->setOperations->back()->setType, kSetUnion);
ASSERT_STREQ(stmt->withDescriptions->back()->select->fromTable->name, "A");
ASSERT_STREQ(stmt->withDescriptions->back()->select->setOperations->back()->nestedSelectStatement->fromTable->name, "B");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
ASSERT_STREQ(stmt->fromTable->name, "UNION_FIRST");
ASSERT_EQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->select->setOperations->back()->setType, kSetIntersect);
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->select->fromTable->name, "C");
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->select->setOperations->back()->nestedSelectStatement->fromTable->name, "D");
}
TEST(NestedSetOperationsWithMultipleWithClauses) {
TEST_PARSE_SINGLE_SQL(
"WITH UNION_FIRST AS (SELECT * FROM A UNION SELECT * FROM B),INTERSECT_SECOND AS (SELECT * FROM UNION_FIRST INTERSECT SELECT * FROM C) SELECT * FROM UNION_FIRST EXCEPT SELECT * FROM INTERSECT_SECOND",
kStmtSelect,
SelectStatement,
result,
stmt);
ASSERT_STREQ(stmt->withDescriptions->at(0)->alias, "UNION_FIRST");
ASSERT_STREQ(stmt->withDescriptions->back()->alias, "INTERSECT_SECOND");
ASSERT_EQ(stmt->withDescriptions->at(0)->select->setOperations->back()->setType, kSetUnion);
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->fromTable->name, "A");
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->setOperations->back()->nestedSelectStatement->fromTable->name, "B");
ASSERT_EQ(stmt->withDescriptions->back()->select->setOperations->back()->setType, kSetIntersect);
ASSERT_STREQ(stmt->withDescriptions->back()->select->fromTable->name, "UNION_FIRST");
ASSERT_STREQ(stmt->withDescriptions->back()->select->setOperations->back()->nestedSelectStatement->fromTable->name, "C");
ASSERT_EQ(stmt->setOperations->back()->setType, kSetExcept);
ASSERT_STREQ(stmt->fromTable->name, "UNION_FIRST");
ASSERT_STREQ(stmt->setOperations->back()->nestedSelectStatement->fromTable->name, "INTERSECT_SECOND");
}
TEST(WrongOrderByStatementTest) {
SQLParserResult res = parse_and_move("SELECT * FROM students ORDER BY name INTERSECT SELECT grade FROM students_2;");
ASSERT_FALSE(res.isValid());
}
TEST(BeginTransactionTest) { TEST(BeginTransactionTest) {
{ {
TEST_PARSE_SINGLE_SQL( TEST_PARSE_SINGLE_SQL(