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 /* 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 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 it under the terms of the GNU General Public License as published by
@ -48,7 +48,7 @@
extern int hsql_debug; extern int hsql_debug;
#endif #endif
/* "%code requires" blocks. */ /* "%code requires" blocks. */
#line 35 "bison_parser.y" /* yacc.c:1919 */ #line 35 "bison_parser.y" /* yacc.c:1909 */
// %code requires block // %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. */ /* Token type. */
#ifndef HSQL_TOKENTYPE #ifndef HSQL_TOKENTYPE
@ -230,7 +230,7 @@ extern int hsql_debug;
union HSQL_STYPE union HSQL_STYPE
{ {
#line 95 "bison_parser.y" /* yacc.c:1919 */ #line 95 "bison_parser.y" /* yacc.c:1909 */
double fval; double fval;
int64_t ival; int64_t ival;
@ -272,7 +272,7 @@ union HSQL_STYPE
std::vector<hsql::Expr*>* expr_vec; std::vector<hsql::Expr*>* expr_vec;
std::vector<hsql::OrderDescription*>* order_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; 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. // TODO: TOP and LIMIT can take more than just int literals.
opt_top: opt_top:
TOP int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; } TOP int_literal { $$ = new LimitDescription($2, nullptr); }
| /* empty */ { $$ = nullptr; } | /* empty */ { $$ = nullptr; }
; ;
opt_limit: opt_limit:
LIMIT int_literal { $$ = new LimitDescription($2->ival, kNoOffset); delete $2; } LIMIT expr { $$ = new LimitDescription($2, nullptr); }
| LIMIT int_literal OFFSET int_literal { $$ = new LimitDescription($2->ival, $4->ival); delete $2; delete $4; } | OFFSET expr { $$ = new LimitDescription(nullptr, $2); }
| OFFSET int_literal { $$ = new LimitDescription(kNoLimit, $2->ival); delete $2; } | LIMIT expr OFFSET expr { $$ = new LimitDescription($2, $4); }
| LIMIT ALL { $$ = nullptr; } | LIMIT ALL { $$ = new LimitDescription(nullptr, nullptr); }
| LIMIT NULL { $$ = nullptr; } | LIMIT ALL OFFSET expr { $$ = new LimitDescription(nullptr, $4); }
| LIMIT ALL OFFSET int_literal { $$ = new LimitDescription(kNoLimit, $4->ival); delete $4; }
| LIMIT NULL OFFSET int_literal { $$ = new LimitDescription(kNoLimit, $4->ival); delete $4; }
| /* empty */ { $$ = nullptr; } | /* empty */ { $$ = nullptr; }
; ;

View File

@ -21,15 +21,13 @@ namespace hsql {
Expr* expr; Expr* expr;
}; };
const int64_t kNoLimit = -1;
const int64_t kNoOffset = -1;
// Description of the limit clause within a select statement. // Description of the limit clause within a select statement.
struct LimitDescription { struct LimitDescription {
LimitDescription(int64_t limit, int64_t offset); LimitDescription(Expr* limit, Expr* offset);
virtual ~LimitDescription();
int64_t limit; Expr* limit;
int64_t offset; Expr* offset;
}; };
// Description of the group-by clause within a select statement. // Description of the group-by clause within a select statement.

View File

@ -202,9 +202,14 @@ namespace hsql {
} }
// LimitDescription // LimitDescription
LimitDescription::LimitDescription(int64_t limit, int64_t offset) : LimitDescription::LimitDescription(Expr* limit, Expr* offset) :
limit(limit >= 0 ? limit : kNoLimit), limit(limit),
offset(offset > 0 ? offset : kNoOffset) {} offset(offset) {}
LimitDescription::~LimitDescription() {
delete limit;
delete offset;
}
// GroypByDescription // GroypByDescription
GroupByDescription::GroupByDescription() : GroupByDescription::GroupByDescription() :

View File

@ -190,7 +190,9 @@ namespace hsql {
if (stmt->limit != nullptr) { if (stmt->limit != nullptr) {
inprint("Limit:", numIndent + 1); 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; SelectStatement* stmt;
TEST_PARSE_SQL_QUERY("select a from t1 limit 1; \ 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 1 offset 1; \
select a from t1 limit 0; \ select a from t1 limit 1 + 2 offset 1 + 2; \
select a from t1 limit 0 offset 1; \ select a from t1 limit 1 offset NULL; \
select a from t1 limit 1 offset 0; \ 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 ALL offset 1; \
select a from t1 limit NULL offset 1; \ select a from t1 limit NULL offset 1; \
select a from t1 offset 1; \
select top 10 a from t1; \ select top 10 a from t1; \
select top 20 a from t1 limit 10;", select top 20 a from t1 limit 10; \
result, 10); select a from t1 limit (SELECT MAX(b) FROM t1) offset (SELECT MIN(b) FROM t1);",
result, 14);
stmt = (SelectStatement*) result.getStatement(0); stmt = (SelectStatement*) result.getStatement(0);
ASSERT_EQ(stmt->limit->limit, 1); ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
ASSERT_EQ(stmt->limit->offset, kNoOffset); ASSERT_EQ(stmt->limit->limit->ival, 1);
ASSERT_NULL(stmt->limit->offset);
stmt = (SelectStatement*) result.getStatement(1); stmt = (SelectStatement*) result.getStatement(1);
ASSERT_EQ(stmt->limit->limit, 1); ASSERT_EQ(stmt->limit->limit->type, kExprOperator);
ASSERT_EQ(stmt->limit->offset, 1); 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); stmt = (SelectStatement*) result.getStatement(2);
ASSERT_EQ(stmt->limit->limit, 0); ASSERT_NULL(stmt->limit->limit);
ASSERT_EQ(stmt->limit->offset, kNoOffset); ASSERT_EQ(stmt->limit->offset->type, kExprLiteralInt);
ASSERT_EQ(stmt->limit->offset->ival, 1);
stmt = (SelectStatement*) result.getStatement(3); stmt = (SelectStatement*) result.getStatement(3);
ASSERT_EQ(stmt->limit->limit, 0); ASSERT_NULL(stmt->limit->limit);
ASSERT_EQ(stmt->limit->offset, 1); 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); stmt = (SelectStatement*) result.getStatement(4);
ASSERT_EQ(stmt->limit->limit, 1); ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
ASSERT_EQ(stmt->limit->offset, kNoOffset); 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); stmt = (SelectStatement*) result.getStatement(5);
ASSERT_EQ(stmt->limit->limit, kNoLimit); ASSERT_EQ(stmt->limit->limit->type, kExprOperator);
ASSERT_EQ(stmt->limit->offset, 1); 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); stmt = (SelectStatement*) result.getStatement(6);
ASSERT_EQ(stmt->limit->limit, kNoLimit); ASSERT_EQ(stmt->limit->limit->type, kExprLiteralInt);
ASSERT_EQ(stmt->limit->offset, 1); ASSERT_EQ(stmt->limit->limit->ival, 1);
ASSERT_EQ(stmt->limit->offset->type, kExprLiteralNull);
stmt = (SelectStatement*) result.getStatement(7); stmt = (SelectStatement*) result.getStatement(7);
ASSERT_EQ(stmt->limit->limit, kNoLimit); ASSERT_NULL(stmt->limit->limit);
ASSERT_EQ(stmt->limit->offset, 1); ASSERT_NULL(stmt->limit->offset);
stmt = (SelectStatement*) result.getStatement(8); stmt = (SelectStatement*) result.getStatement(8);
ASSERT_EQ(stmt->limit->limit, 10); ASSERT_EQ(stmt->limit->limit->type, kExprLiteralNull);
ASSERT_EQ(stmt->limit->offset, kNoOffset); ASSERT_NULL(stmt->limit->offset);
stmt = (SelectStatement*) result.getStatement(9); stmt = (SelectStatement*) result.getStatement(9);
ASSERT_EQ(stmt->limit->limit, 10); ASSERT_NULL(stmt->limit->limit);
ASSERT_EQ(stmt->limit->offset, kNoOffset); 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) { TEST(Extract) {