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

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

View File

@ -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;

View File

@ -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:

View File

@ -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

View File

@ -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 */

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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(