Support WITH (#125)
* Add struct WithDescription in SelectStatement.h * Add test for With statements * Implement With draft * tm * Fix Grammar * Fix commented code * naming improvements * naming improvements * introduce memory leak1 * removed memory leak * Create two WITH-tests * Add bad queries reg. WITH
This commit is contained in:
parent
ab1e6b4192
commit
6003ab58d1
File diff suppressed because it is too large
Load Diff
|
@ -255,6 +255,7 @@ union HSQL_STYPE
|
|||
hsql::Expr* expr;
|
||||
hsql::OrderDescription* order;
|
||||
hsql::OrderType order_type;
|
||||
hsql::WithDescription* with_description_t;
|
||||
hsql::DatetimeField datetime_field;
|
||||
hsql::LimitDescription* limit;
|
||||
hsql::ColumnDefinition* column_t;
|
||||
|
@ -271,8 +272,9 @@ union HSQL_STYPE
|
|||
std::vector<hsql::UpdateClause*>* update_vec;
|
||||
std::vector<hsql::Expr*>* expr_vec;
|
||||
std::vector<hsql::OrderDescription*>* order_vec;
|
||||
std::vector<hsql::WithDescription*>* with_description_vec;
|
||||
|
||||
#line 276 "bison_parser.h" /* yacc.c:1909 */
|
||||
#line 278 "bison_parser.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union HSQL_STYPE HSQL_STYPE;
|
||||
|
|
|
@ -116,6 +116,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
|||
hsql::Expr* expr;
|
||||
hsql::OrderDescription* order;
|
||||
hsql::OrderType order_type;
|
||||
hsql::WithDescription* with_description_t;
|
||||
hsql::DatetimeField datetime_field;
|
||||
hsql::LimitDescription* limit;
|
||||
hsql::ColumnDefinition* column_t;
|
||||
|
@ -132,6 +133,7 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
|||
std::vector<hsql::UpdateClause*>* update_vec;
|
||||
std::vector<hsql::Expr*>* expr_vec;
|
||||
std::vector<hsql::OrderDescription*>* order_vec;
|
||||
std::vector<hsql::WithDescription*>* with_description_vec;
|
||||
}
|
||||
|
||||
|
||||
|
@ -212,11 +214,13 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
|||
%type <update_t> update_clause
|
||||
%type <group_t> opt_group
|
||||
%type <alias_t> opt_table_alias table_alias opt_alias alias
|
||||
%type <with_description_t> with_description
|
||||
|
||||
%type <str_vec> ident_commalist opt_column_list
|
||||
%type <expr_vec> expr_list select_list opt_literal_list literal_list hint_list opt_hints
|
||||
%type <table_vec> table_ref_commalist
|
||||
%type <order_vec> opt_order order_list
|
||||
%type <with_description_vec> opt_with_clause with_clause with_description_list
|
||||
%type <update_vec> update_clause_commalist
|
||||
%type <column_vec> column_def_commalist
|
||||
|
||||
|
@ -583,20 +587,27 @@ update_clause:
|
|||
******************************/
|
||||
|
||||
select_statement:
|
||||
select_with_paren
|
||||
| select_no_paren
|
||||
| select_with_paren set_operator select_paren_or_clause opt_order opt_limit {
|
||||
opt_with_clause select_with_paren {
|
||||
$$ = $2;
|
||||
$$->withDescriptions = $1;
|
||||
}
|
||||
| opt_with_clause select_no_paren {
|
||||
$$ = $2;
|
||||
$$->withDescriptions = $1;
|
||||
}
|
||||
| opt_with_clause select_with_paren set_operator select_paren_or_clause 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;
|
||||
$$->unionSelect = $3;
|
||||
$$->order = $4;
|
||||
$$ = $2;
|
||||
$$->withDescriptions = $1;
|
||||
$$->unionSelect = $4;
|
||||
$$->order = $5;
|
||||
|
||||
// Limit could have been set by TOP.
|
||||
if ($5 != nullptr) {
|
||||
if ($6 != nullptr) {
|
||||
delete $$->limit;
|
||||
$$->limit = $5;
|
||||
$$->limit = $6;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
@ -1012,6 +1023,39 @@ opt_alias:
|
|||
| /* empty */ { $$ = nullptr; }
|
||||
|
||||
|
||||
/******************************
|
||||
* With Descriptions
|
||||
******************************/
|
||||
|
||||
opt_with_clause:
|
||||
with_clause
|
||||
| /* empty */ { $$ = nullptr; }
|
||||
;
|
||||
|
||||
with_clause:
|
||||
WITH with_description_list { $$ = $2; }
|
||||
;
|
||||
|
||||
with_description_list:
|
||||
with_description {
|
||||
$$ = new std::vector<WithDescription*>();
|
||||
$$->push_back($1);
|
||||
}
|
||||
| with_description_list ',' with_description {
|
||||
$1->push_back($3);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
with_description:
|
||||
IDENTIFIER AS select_with_paren {
|
||||
$$ = new WithDescription();
|
||||
$$->alias = $1;
|
||||
$$->select = $3;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/******************************
|
||||
* Join Statements
|
||||
******************************/
|
||||
|
|
|
@ -39,6 +39,13 @@ namespace hsql {
|
|||
Expr* having;
|
||||
};
|
||||
|
||||
struct WithDescription {
|
||||
~WithDescription();
|
||||
|
||||
char* alias;
|
||||
SelectStatement* select;
|
||||
};
|
||||
|
||||
// Representation of a full SQL select statement.
|
||||
// TODO: add union_order and union_limit.
|
||||
struct SelectStatement : SQLStatement {
|
||||
|
@ -53,9 +60,11 @@ namespace hsql {
|
|||
|
||||
SelectStatement* unionSelect;
|
||||
std::vector<OrderDescription*>* order;
|
||||
std::vector<WithDescription*>* withDescriptions;
|
||||
LimitDescription* limit;
|
||||
};
|
||||
|
||||
|
||||
} // namespace hsql
|
||||
|
||||
#endif
|
||||
|
|
|
@ -227,6 +227,11 @@ namespace hsql {
|
|||
}
|
||||
}
|
||||
|
||||
WithDescription::~WithDescription() {
|
||||
free(alias);
|
||||
delete select;
|
||||
}
|
||||
|
||||
// SelectStatement
|
||||
SelectStatement::SelectStatement() :
|
||||
SQLStatement(kStmtSelect),
|
||||
|
@ -237,6 +242,7 @@ namespace hsql {
|
|||
groupBy(nullptr),
|
||||
unionSelect(nullptr),
|
||||
order(nullptr),
|
||||
withDescriptions(nullptr),
|
||||
limit(nullptr) {};
|
||||
|
||||
SelectStatement::~SelectStatement() {
|
||||
|
@ -260,6 +266,13 @@ namespace hsql {
|
|||
}
|
||||
delete order;
|
||||
}
|
||||
|
||||
if (withDescriptions != nullptr) {
|
||||
for (WithDescription* desc : *withDescriptions) {
|
||||
delete desc;
|
||||
}
|
||||
delete withDescriptions;
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateStatement
|
||||
|
|
|
@ -10,3 +10,7 @@
|
|||
!SELECT * FROM t WHERE a = ? AND b = ?;gibberish;
|
||||
!SHOW COLUMNS;
|
||||
!select a + 2 as b(spam, eggs) from B;
|
||||
!WITH a AS SELECT 1 SELECT 1;
|
||||
!WITH a AS (SELECT ) SELECT 1;
|
||||
!WITH a AS (WITH b AS (SELECT 1) SELECT 1) SELECT 1; # We do not support nested WITH clauses
|
||||
!WITH a AS (SELECT ) b AS (SELECT ) SELECT 1; # Missing comma between WITH descriptions
|
|
@ -681,3 +681,60 @@ TEST(NoFromClause) {
|
|||
ASSERT_EQ(stmt->selectList->at(0)->expr->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->selectList->at(0)->expr2->type, kExprLiteralInt);
|
||||
}
|
||||
|
||||
|
||||
TEST(WithClauseSingle) {
|
||||
TEST_PARSE_SINGLE_SQL("WITH "
|
||||
"a AS (SELECT name FROM peopleA)"
|
||||
"SELECT name FROM a;",
|
||||
kStmtSelect,
|
||||
SelectStatement,
|
||||
result,
|
||||
stmt)
|
||||
|
||||
// with_description_list – count
|
||||
ASSERT_EQ(stmt->withDescriptions->size(), 1);
|
||||
|
||||
// with_description – alias
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->alias, "a");
|
||||
|
||||
// with_description – select stmt
|
||||
ASSERT_EQ(stmt->withDescriptions->at(0)->select->selectList->size(), 1)
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->selectList->at(0)->name, std::string("name"));
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->fromTable->name, std::string("peopleA"));
|
||||
|
||||
// main select
|
||||
ASSERT_EQ(stmt->selectList->size(), 1);
|
||||
ASSERT_STREQ(stmt->selectList->at(0)->name, "name");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "a");
|
||||
|
||||
}
|
||||
|
||||
TEST(WithClauseDouble) {
|
||||
TEST_PARSE_SINGLE_SQL("WITH "
|
||||
"a AS (SELECT nameA FROM peopleA), "
|
||||
"b AS (SELECT nameB, cityB FROM peopleB) "
|
||||
"SELECT nameA FROM a;",
|
||||
kStmtSelect,
|
||||
SelectStatement,
|
||||
result,
|
||||
stmt)
|
||||
|
||||
// with_description_list – count
|
||||
ASSERT_EQ(stmt->withDescriptions->size(), 2);
|
||||
|
||||
// with_description – aliases
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->alias, "a");
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(1)->alias, "b");
|
||||
|
||||
// with_description – select stmts
|
||||
ASSERT_EQ(stmt->withDescriptions->at(0)->select->selectList->size(), 1)
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(0)->select->fromTable->name, "peopleA");
|
||||
ASSERT_EQ(stmt->withDescriptions->at(1)->select->selectList->size(), 2)
|
||||
ASSERT_STREQ(stmt->withDescriptions->at(1)->select->fromTable->name, "peopleB");
|
||||
|
||||
// main select
|
||||
ASSERT_EQ(stmt->selectList->size(), 1);
|
||||
ASSERT_STREQ(stmt->selectList->at(0)->name, "nameA");
|
||||
ASSERT_STREQ(stmt->fromTable->name, "a");
|
||||
}
|
Loading…
Reference in New Issue