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::Expr* expr;
|
||||||
hsql::OrderDescription* order;
|
hsql::OrderDescription* order;
|
||||||
hsql::OrderType order_type;
|
hsql::OrderType order_type;
|
||||||
|
hsql::WithDescription* with_description_t;
|
||||||
hsql::DatetimeField datetime_field;
|
hsql::DatetimeField datetime_field;
|
||||||
hsql::LimitDescription* limit;
|
hsql::LimitDescription* limit;
|
||||||
hsql::ColumnDefinition* column_t;
|
hsql::ColumnDefinition* column_t;
|
||||||
|
@ -271,8 +272,9 @@ union HSQL_STYPE
|
||||||
std::vector<hsql::UpdateClause*>* update_vec;
|
std::vector<hsql::UpdateClause*>* update_vec;
|
||||||
std::vector<hsql::Expr*>* expr_vec;
|
std::vector<hsql::Expr*>* expr_vec;
|
||||||
std::vector<hsql::OrderDescription*>* order_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;
|
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::Expr* expr;
|
||||||
hsql::OrderDescription* order;
|
hsql::OrderDescription* order;
|
||||||
hsql::OrderType order_type;
|
hsql::OrderType order_type;
|
||||||
|
hsql::WithDescription* with_description_t;
|
||||||
hsql::DatetimeField datetime_field;
|
hsql::DatetimeField datetime_field;
|
||||||
hsql::LimitDescription* limit;
|
hsql::LimitDescription* limit;
|
||||||
hsql::ColumnDefinition* column_t;
|
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::UpdateClause*>* update_vec;
|
||||||
std::vector<hsql::Expr*>* expr_vec;
|
std::vector<hsql::Expr*>* expr_vec;
|
||||||
std::vector<hsql::OrderDescription*>* order_vec;
|
std::vector<hsql::OrderDescription*>* order_vec;
|
||||||
|
std::vector<hsql::WithDescription*>* with_description_vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,13 +214,15 @@ int yyerror(YYLTYPE* llocp, SQLParserResult* result, yyscan_t scanner, const cha
|
||||||
%type <update_t> update_clause
|
%type <update_t> update_clause
|
||||||
%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 <str_vec> ident_commalist opt_column_list
|
%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 <expr_vec> expr_list select_list opt_literal_list literal_list hint_list opt_hints
|
||||||
%type <table_vec> table_ref_commalist
|
%type <table_vec> table_ref_commalist
|
||||||
%type <order_vec> opt_order order_list
|
%type <order_vec> opt_order order_list
|
||||||
%type <update_vec> update_clause_commalist
|
%type <with_description_vec> opt_with_clause with_clause with_description_list
|
||||||
%type <column_vec> column_def_commalist
|
%type <update_vec> update_clause_commalist
|
||||||
|
%type <column_vec> column_def_commalist
|
||||||
|
|
||||||
/******************************
|
/******************************
|
||||||
** Token Precedence and Associativity
|
** Token Precedence and Associativity
|
||||||
|
@ -583,20 +587,27 @@ update_clause:
|
||||||
******************************/
|
******************************/
|
||||||
|
|
||||||
select_statement:
|
select_statement:
|
||||||
select_with_paren
|
opt_with_clause select_with_paren {
|
||||||
| select_no_paren
|
$$ = $2;
|
||||||
| select_with_paren set_operator select_paren_or_clause opt_order opt_limit {
|
$$->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: allow multiple unions (through linked list)
|
||||||
// TODO: capture type of set_operator
|
// TODO: capture type of set_operator
|
||||||
// TODO: might overwrite order and limit of first select here
|
// TODO: might overwrite order and limit of first select here
|
||||||
$$ = $1;
|
$$ = $2;
|
||||||
$$->unionSelect = $3;
|
$$->withDescriptions = $1;
|
||||||
$$->order = $4;
|
$$->unionSelect = $4;
|
||||||
|
$$->order = $5;
|
||||||
|
|
||||||
// Limit could have been set by TOP.
|
// Limit could have been set by TOP.
|
||||||
if ($5 != nullptr) {
|
if ($6 != nullptr) {
|
||||||
delete $$->limit;
|
delete $$->limit;
|
||||||
$$->limit = $5;
|
$$->limit = $6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -1012,6 +1023,39 @@ opt_alias:
|
||||||
| /* empty */ { $$ = nullptr; }
|
| /* 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
|
* Join Statements
|
||||||
******************************/
|
******************************/
|
||||||
|
|
|
@ -39,6 +39,13 @@ namespace hsql {
|
||||||
Expr* having;
|
Expr* having;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WithDescription {
|
||||||
|
~WithDescription();
|
||||||
|
|
||||||
|
char* alias;
|
||||||
|
SelectStatement* select;
|
||||||
|
};
|
||||||
|
|
||||||
// Representation of a full SQL select statement.
|
// Representation of a full SQL select statement.
|
||||||
// TODO: add union_order and union_limit.
|
// TODO: add union_order and union_limit.
|
||||||
struct SelectStatement : SQLStatement {
|
struct SelectStatement : SQLStatement {
|
||||||
|
@ -53,9 +60,11 @@ namespace hsql {
|
||||||
|
|
||||||
SelectStatement* unionSelect;
|
SelectStatement* unionSelect;
|
||||||
std::vector<OrderDescription*>* order;
|
std::vector<OrderDescription*>* order;
|
||||||
|
std::vector<WithDescription*>* withDescriptions;
|
||||||
LimitDescription* limit;
|
LimitDescription* limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace hsql
|
} // namespace hsql
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -227,6 +227,11 @@ namespace hsql {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WithDescription::~WithDescription() {
|
||||||
|
free(alias);
|
||||||
|
delete select;
|
||||||
|
}
|
||||||
|
|
||||||
// SelectStatement
|
// SelectStatement
|
||||||
SelectStatement::SelectStatement() :
|
SelectStatement::SelectStatement() :
|
||||||
SQLStatement(kStmtSelect),
|
SQLStatement(kStmtSelect),
|
||||||
|
@ -237,6 +242,7 @@ namespace hsql {
|
||||||
groupBy(nullptr),
|
groupBy(nullptr),
|
||||||
unionSelect(nullptr),
|
unionSelect(nullptr),
|
||||||
order(nullptr),
|
order(nullptr),
|
||||||
|
withDescriptions(nullptr),
|
||||||
limit(nullptr) {};
|
limit(nullptr) {};
|
||||||
|
|
||||||
SelectStatement::~SelectStatement() {
|
SelectStatement::~SelectStatement() {
|
||||||
|
@ -260,6 +266,13 @@ namespace hsql {
|
||||||
}
|
}
|
||||||
delete order;
|
delete order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (withDescriptions != nullptr) {
|
||||||
|
for (WithDescription* desc : *withDescriptions) {
|
||||||
|
delete desc;
|
||||||
|
}
|
||||||
|
delete withDescriptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatement
|
// UpdateStatement
|
||||||
|
|
|
@ -10,3 +10,7 @@
|
||||||
!SELECT * FROM t WHERE a = ? AND b = ?;gibberish;
|
!SELECT * FROM t WHERE a = ? AND b = ?;gibberish;
|
||||||
!SHOW COLUMNS;
|
!SHOW COLUMNS;
|
||||||
!select a + 2 as b(spam, eggs) from B;
|
!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)->expr->type, kExprLiteralInt);
|
||||||
ASSERT_EQ(stmt->selectList->at(0)->expr2->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