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:
Leander Neiss 2019-04-04 12:25:15 +02:00 committed by mrks
parent 9701403ff5
commit e0e58d0876
7 changed files with 1113 additions and 1087 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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