Skip to content

Commit 0663319

Browse files
authored
Support NULLS FIRST and NULLS LAST in ORDER BY clause (#257)
1 parent 87e6eac commit 0663319

File tree

7 files changed

+1670
-1583
lines changed

7 files changed

+1670
-1583
lines changed

src/parser/bison_parser.cpp

Lines changed: 1620 additions & 1575 deletions
Large diffs are not rendered by default.

src/parser/bison_parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ union HSQL_STYPE
318318
hsql::LockingClause* locking_t;
319319
hsql::OrderDescription* order;
320320
hsql::OrderType order_type;
321+
hsql::NullOrdering null_ordering_t;
321322
hsql::ReferencesSpecification* references_spec_t;
322323
hsql::SetOperation* set_operator_t;
323324
hsql::TableConstraint* table_constraint_t;
@@ -347,7 +348,7 @@ union HSQL_STYPE
347348

348349
// clang-format off
349350

350-
#line 351 "bison_parser.h"
351+
#line 352 "bison_parser.h"
351352

352353
};
353354
typedef union HSQL_STYPE HSQL_STYPE;

src/parser/bison_parser.y

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@
142142
hsql::LockingClause* locking_t;
143143
hsql::OrderDescription* order;
144144
hsql::OrderType order_type;
145+
hsql::NullOrdering null_ordering_t;
145146
hsql::ReferencesSpecification* references_spec_t;
146147
hsql::SetOperation* set_operator_t;
147148
hsql::TableConstraint* table_constraint_t;
@@ -176,7 +177,7 @@
176177
** Destructor symbols
177178
*********************************/
178179

179-
%destructor { } <fval> <ival> <bval> <join_type> <order_type> <datetime_field> <column_type_t> <column_constraint_t> <import_type_t> <lock_mode_t> <lock_wait_policy_t> <frame_type>
180+
%destructor { } <fval> <ival> <bval> <join_type> <order_type> <datetime_field> <column_type_t> <column_constraint_t> <import_type_t> <lock_mode_t> <lock_wait_policy_t> <frame_type> <null_ordering_t>
180181
%destructor {
181182
free($$.name);
182183
free($$.schema);
@@ -270,6 +271,7 @@
270271
%type <limit> opt_limit opt_top
271272
%type <order> order_desc
272273
%type <order_type> opt_order_type
274+
%type <null_ordering_t> opt_null_ordering
273275
%type <datetime_field> datetime_field datetime_field_plural duration_field
274276
%type <column_t> column_def
275277
%type <table_element_t> table_elem
@@ -953,12 +955,33 @@ order_list : order_desc {
953955
$$ = $1;
954956
};
955957

956-
order_desc : expr opt_order_type { $$ = new OrderDescription($2, $1); };
958+
order_desc : expr opt_order_type opt_null_ordering { $$ = new OrderDescription($2, $1, $3); };
957959

958960
opt_order_type : ASC { $$ = kOrderAsc; }
959961
| DESC { $$ = kOrderDesc; }
960962
| /* empty */ { $$ = kOrderAsc; };
961963

964+
opt_null_ordering : /* empty */ { $$ = NullOrdering::Undefined; }
965+
| IDENTIFIER IDENTIFIER {
966+
auto null_ordering = NullOrdering::Undefined;
967+
if (strcasecmp($1, "nulls") == 0) {
968+
if (strcasecmp($2, "first") == 0) {
969+
null_ordering = NullOrdering::First;
970+
} else if (strcasecmp($2, "last") == 0) {
971+
null_ordering = NullOrdering::Last;
972+
}
973+
}
974+
free($1);
975+
free($2);
976+
977+
if (null_ordering == NullOrdering::Undefined) {
978+
yyerror(&yyloc, result, scanner, "Expected NULLS FIRST or NULLS LAST ordering.");
979+
YYERROR;
980+
}
981+
982+
$$ = null_ordering;
983+
};
984+
962985
// TODO: TOP and LIMIT can take more than just int literals.
963986

964987
opt_top : TOP int_literal { $$ = new LimitDescription($2, nullptr); }

src/sql/SelectStatement.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace hsql {
99
enum OrderType { kOrderAsc, kOrderDesc };
10+
enum NullOrdering { Undefined, First, Last };
1011

1112
enum SetType { kSetUnion, kSetIntersect, kSetExcept };
1213

@@ -15,11 +16,12 @@ enum RowLockWaitPolicy { NoWait, SkipLocked, None };
1516

1617
// Description of the order by clause within a select statement.
1718
struct OrderDescription {
18-
OrderDescription(OrderType type, Expr* expr);
19+
OrderDescription(OrderType type, Expr* expr, NullOrdering null_ordering);
1920
virtual ~OrderDescription();
2021

2122
OrderType type;
2223
Expr* expr;
24+
NullOrdering null_ordering;
2325
};
2426

2527
// Description of the limit clause within a select statement.

src/sql/statements.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ ShowStatement::~ShowStatement() {
213213
// SelectStatement.h
214214

215215
// OrderDescription
216-
OrderDescription::OrderDescription(OrderType type, Expr* expr) : type(type), expr(expr) {}
216+
OrderDescription::OrderDescription(OrderType type, Expr* expr, NullOrdering null_ordering)
217+
: type(type), expr(expr), null_ordering(null_ordering) {}
217218

218219
OrderDescription::~OrderDescription() { delete expr; }
219220

test/queries/queries-bad.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,12 @@
9393
!SELECT * FROM foo WITH HINT (?);
9494
!SELECT * FROM foo WITH HINT (CAST(column_a AS INT));
9595
!SELECT * FROM foo WITH HINT (AVG(another_column));
96+
# ORDER BY with NULL ordering.
97+
!SELECT * FROM students ORDER BY name ASC NULL FIRST;
98+
!SELECT * FROM students ORDER BY name ASC gibberish LAST;
99+
!SELECT * FROM students ORDER BY name NULLS FIRS;
100+
!SELECT * FROM students ORDER BY name NULLS;
101+
!SELECT * FROM students ORDER BY name ASC NULLS;
102+
!SELECT * FROM students ORDER BY name FIRST;
103+
!SELECT * FROM students ORDER BY name ASC LAST;
104+
!SELECT * FROM students ORDER BY name DESC NULLS gibberish;

test/select_tests.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,18 +172,24 @@ TEST(SelectGroupDistinctTest) {
172172
}
173173

174174
TEST(OrderByTest) {
175-
TEST_PARSE_SINGLE_SQL("SELECT grade, city FROM students ORDER BY grade, city DESC;", kStmtSelect, SelectStatement,
176-
result, stmt);
175+
TEST_PARSE_SINGLE_SQL("SELECT grade, city FROM students ORDER BY grade, city DESC NULLS FIRST, name NULLS LAST;",
176+
kStmtSelect, SelectStatement, result, stmt);
177177

178178
ASSERT_NULL(stmt->whereClause);
179179
ASSERT_NOTNULL(stmt->order);
180180

181-
ASSERT_EQ(stmt->order->size(), 2);
181+
ASSERT_EQ(stmt->order->size(), 3);
182182
ASSERT_EQ(stmt->order->at(0)->type, kOrderAsc);
183183
ASSERT_STREQ(stmt->order->at(0)->expr->name, "grade");
184+
ASSERT_EQ(stmt->order->at(0)->null_ordering, NullOrdering::Undefined);
184185

185186
ASSERT_EQ(stmt->order->at(1)->type, kOrderDesc);
186187
ASSERT_STREQ(stmt->order->at(1)->expr->name, "city");
188+
ASSERT_EQ(stmt->order->at(1)->null_ordering, NullOrdering::First);
189+
190+
ASSERT_EQ(stmt->order->at(2)->type, kOrderAsc);
191+
ASSERT_STREQ(stmt->order->at(2)->expr->name, "name");
192+
ASSERT_EQ(stmt->order->at(2)->null_ordering, NullOrdering::Last);
187193
}
188194

189195
TEST(SelectBetweenTest) {

0 commit comments

Comments
 (0)