Allow Expressions in LIMIT and OFFSET. (#111)
* Allow Expressions in LIMIT and OFFSET. * Make NULL distinguishable from nullptr (not present) for LIMIT and OFFSET.
This commit is contained in:
parent
9701403ff5
commit
e0e58d0876
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
|||
/* A Bison parser, made by GNU Bison 3.1. */
|
||||
/* A Bison parser, made by GNU Bison 3.0.4. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc.
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -48,7 +48,7 @@
|
|||
extern int hsql_debug;
|
||||
#endif
|
||||
/* "%code requires" blocks. */
|
||||
#line 35 "bison_parser.y" /* yacc.c:1919 */
|
||||
#line 35 "bison_parser.y" /* yacc.c:1909 */
|
||||
|
||||
// %code requires block
|
||||
|
||||
|
@ -72,7 +72,7 @@ extern int hsql_debug;
|
|||
} \
|
||||
}
|
||||
|
||||
#line 76 "bison_parser.h" /* yacc.c:1919 */
|
||||
#line 76 "bison_parser.h" /* yacc.c:1909 */
|
||||
|
||||
/* Token type. */
|
||||
#ifndef HSQL_TOKENTYPE
|
||||
|
@ -230,7 +230,7 @@ extern int hsql_debug;
|
|||
|
||||
union HSQL_STYPE
|
||||
{
|
||||
#line 95 "bison_parser.y" /* yacc.c:1919 */
|
||||
#line 95 "bison_parser.y" /* yacc.c:1909 */
|
||||
|
||||
double fval;
|
||||
int64_t ival;
|
||||
|
@ -272,7 +272,7 @@ union HSQL_STYPE
|
|||
std::vector<hsql::Expr*>* expr_vec;
|
||||
std::vector<hsql::OrderDescription*>* order_vec;
|
||||
|
||||
#line 276 "bison_parser.h" /* yacc.c:1919 */
|
||||
#line 276 "bison_parser.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union HSQL_STYPE HSQL_STYPE;
|
||||
|
|
|
@ -724,18 +724,16 @@ opt_order_type:
|
|||
// TODO: TOP and LIMIT can take more than just int literals.
|
||||
|
||||
opt_top:
|
||||
TOP int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
||||
TOP int_literal { $$ = new LimitDescription($2, nullptr); }
|
||||
| /* empty */ { $$ = nullptr; }
|
||||
;
|
||||
|
||||
opt_limit:
|
||||
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; }
|
||||
| LIMIT int_literal OFFSET int_literal { $$ = new LimitDescription($2->ival, $4->ival); delete $2; delete $4; }
|
||||
| OFFSET int_literal { $$ = new LimitDescription(kNoLimit, $2->ival); delete $2; }
|
||||
| LIMIT ALL { $$ = nullptr; }
|
||||
| LIMIT NULL { $$ = nullptr; }
|
||||
| LIMIT ALL OFFSET int_literal { $$ = new LimitDescription(kNoLimit, $4->ival); delete $4; }
|
||||
| LIMIT NULL OFFSET int_literal { $$ = new LimitDescription(kNoLimit, $4->ival); delete $4; }
|
||||
LIMIT expr { $$ = new LimitDescription($2, nullptr); }
|
||||
| OFFSET expr { $$ = new LimitDescription(nullptr, $2); }
|
||||
| LIMIT expr OFFSET expr { $$ = new LimitDescription($2, $4); }
|
||||
| LIMIT ALL { $$ = new LimitDescription(nullptr, nullptr); }
|
||||
| LIMIT ALL OFFSET expr { $$ = new LimitDescription(nullptr, $4); }
|
||||
| /* empty */ { $$ = nullptr; }
|
||||
;
|
||||
|
||||
|
|
|
@ -21,15 +21,13 @@ namespace hsql {
|
|||
Expr* expr;
|
||||
};
|
||||
|
||||
const int64_t kNoLimit = -1;
|
||||
const int64_t kNoOffset = -1;
|
||||
|
||||
// Description of the limit clause within a select statement.
|
||||
struct LimitDescription {
|
||||
LimitDescription(int64_t limit, int64_t offset);
|
||||
LimitDescription(Expr* limit, Expr* offset);
|
||||
virtual ~LimitDescription();
|
||||
|
||||
int64_t limit;
|
||||
int64_t offset;
|
||||
Expr* limit;
|
||||
Expr* offset;
|
||||
};
|
||||
|
||||
// Description of the group-by clause within a select statement.
|
||||
|
|
|
@ -202,9 +202,14 @@ namespace hsql {
|
|||
}
|
||||
|
||||
// LimitDescription
|
||||
LimitDescription::LimitDescription(int64_t limit, int64_t offset) :
|
||||
limit(limit >= 0 ? limit : kNoLimit),
|
||||
offset(offset > 0 ? offset : kNoOffset) {}
|
||||
LimitDescription::LimitDescription(Expr* limit, Expr* offset) :
|
||||
limit(limit),
|
||||
offset(offset) {}
|
||||
|
||||
LimitDescription::~LimitDescription() {
|
||||
delete limit;
|
||||
delete offset;
|
||||
}
|
||||
|
||||
// GroypByDescription
|
||||
GroupByDescription::GroupByDescription() :
|
||||
|
|
|
@ -190,7 +190,9 @@ namespace hsql {
|
|||
|
||||
if (stmt->limit != nullptr) {
|
||||
inprint("Limit:", numIndent + 1);
|
||||
inprint(stmt->limit->limit, numIndent + 2);
|
||||
printExpression(stmt->limit->limit, numIndent + 2);
|
||||
inprint("Offset:", numIndent + 1);
|
||||
printExpression(stmt->limit->offset, numIndent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -534,56 +534,97 @@ TEST(SetLimitOffset) {
|
|||
SelectStatement* stmt;
|
||||
|
||||
TEST_PARSE_SQL_QUERY("select a from t1 limit 1; \
|
||||
select a from t1 limit 1 + 2; \
|
||||
select a from t1 offset 1; \
|
||||
select a from t1 offset 1 + 2; \
|
||||
select a from t1 limit 1 offset 1; \
|
||||
select a from t1 limit 0; \
|
||||
select a from t1 limit 0 offset 1; \
|
||||
select a from t1 limit 1 offset 0; \
|
||||
select a from t1 limit 1 + 2 offset 1 + 2; \
|
||||
select a from t1 limit 1 offset NULL; \
|
||||
select a from t1 limit ALL; \
|
||||
select a from t1 limit NULL; \
|
||||
select a from t1 limit ALL offset 1; \
|
||||
select a from t1 limit NULL offset 1; \
|
||||
select a from t1 offset 1; \
|
||||
select top 10 a from t1; \
|
||||
select top 20 a from t1 limit 10;",
|
||||
result, 10);
|
||||
select top 20 a from t1 limit 10; \
|
||||
select a from t1 limit (SELECT MAX(b) FROM t1) offset (SELECT MIN(b) FROM t1);",
|
||||
result, 14);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(0);
|
||||
ASSERT_EQ(stmt->limit->limit, 1);
|
||||
ASSERT_EQ(stmt->limit->offset, kNoOffset);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->limit->ival, 1);
|
||||
ASSERT_NULL(stmt->limit->offset);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(1);
|
||||
ASSERT_EQ(stmt->limit->limit, 1);
|
||||
ASSERT_EQ(stmt->limit->offset, 1);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprOperator);
|
||||
ASSERT_EQ(stmt->limit->limit->opType, kOpPlus);
|
||||
ASSERT_EQ(stmt->limit->limit->expr->ival, 1);
|
||||
ASSERT_EQ(stmt->limit->limit->expr2->ival, 2);
|
||||
ASSERT_NULL(stmt->limit->offset);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(2);
|
||||
ASSERT_EQ(stmt->limit->limit, 0);
|
||||
ASSERT_EQ(stmt->limit->offset, kNoOffset);
|
||||
ASSERT_NULL(stmt->limit->limit);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->offset->ival, 1);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(3);
|
||||
ASSERT_EQ(stmt->limit->limit, 0);
|
||||
ASSERT_EQ(stmt->limit->offset, 1);
|
||||
ASSERT_NULL(stmt->limit->limit);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprOperator);
|
||||
ASSERT_EQ(stmt->limit->offset->opType, kOpPlus);
|
||||
ASSERT_EQ(stmt->limit->offset->expr->ival, 1);
|
||||
ASSERT_EQ(stmt->limit->offset->expr2->ival, 2);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(4);
|
||||
ASSERT_EQ(stmt->limit->limit, 1);
|
||||
ASSERT_EQ(stmt->limit->offset, kNoOffset);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->limit->ival, 1);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->offset->ival, 1);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(5);
|
||||
ASSERT_EQ(stmt->limit->limit, kNoLimit);
|
||||
ASSERT_EQ(stmt->limit->offset, 1);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprOperator);
|
||||
ASSERT_EQ(stmt->limit->limit->opType, kOpPlus);
|
||||
ASSERT_EQ(stmt->limit->limit->expr->ival, 1);
|
||||
ASSERT_EQ(stmt->limit->limit->expr2->ival, 2);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprOperator);
|
||||
ASSERT_EQ(stmt->limit->offset->opType, kOpPlus);
|
||||
ASSERT_EQ(stmt->limit->offset->expr->ival, 1);
|
||||
ASSERT_EQ(stmt->limit->offset->expr2->ival, 2);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(6);
|
||||
ASSERT_EQ(stmt->limit->limit, kNoLimit);
|
||||
ASSERT_EQ(stmt->limit->offset, 1);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->limit->ival, 1);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprLiteralNull);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(7);
|
||||
ASSERT_EQ(stmt->limit->limit, kNoLimit);
|
||||
ASSERT_EQ(stmt->limit->offset, 1);
|
||||
ASSERT_NULL(stmt->limit->limit);
|
||||
ASSERT_NULL(stmt->limit->offset);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(8);
|
||||
ASSERT_EQ(stmt->limit->limit, 10);
|
||||
ASSERT_EQ(stmt->limit->offset, kNoOffset);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralNull);
|
||||
ASSERT_NULL(stmt->limit->offset);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(9);
|
||||
ASSERT_EQ(stmt->limit->limit, 10);
|
||||
ASSERT_EQ(stmt->limit->offset, kNoOffset);
|
||||
ASSERT_NULL(stmt->limit->limit);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->offset->ival, 1);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(10);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralNull);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->offset->ival, 1);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(11);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->limit->ival, 10);
|
||||
ASSERT_NULL(stmt->limit->offset);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(12);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
|
||||
ASSERT_EQ(stmt->limit->limit->ival, 10);
|
||||
ASSERT_NULL(stmt->limit->offset);
|
||||
|
||||
stmt = (SelectStatement*) result.getStatement(13);
|
||||
ASSERT_EQ(stmt->limit->limit->type, kExprSelect);
|
||||
ASSERT_EQ(stmt->limit->offset->type, kExprSelect);
|
||||
}
|
||||
|
||||
TEST(Extract) {
|
||||
|
|
Loading…
Reference in New Issue