Skip to content

Commit 9bac49a

Browse files
committed
MB-31034. Support NULLS FIRST|LAST syntax in ORDER BY
1) ORDER BY col1 ASC (MISSING, NULL, BOOLEAN, NUMBER, STRING, ARRAY, OBJECT, BINARY) 2) ORDER BY col1 ASC NULLS FIRST -- This is same as 1st case 3) ORDER BY col1 ASC NULLS LAST Both MISSING and NULL values are placed last as MISSING followed by NULL (BOOLEAN, NUMBER, STRING, ARRAY, OBJECT, BINARY, MISSING, NULL) 4) ORDER BY col1 DESC (BINARY, OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, NULL, MISSING) 5) ORDER BY col1 DESC NULLS FIRST Both MISSING and NULL values are placed at start as NULL followed by MISSING (NULL, MISSING, BINARY, OBJECT, ARRAY, STRING, NUMBER, BOOLEAN) 6) ORDER BY col1 DESC NULLS LAST -- This is same as 4th case Change-Id: I60269c2cce6263d730d255560d997c0402e630b0 Reviewed-on: http://review.couchbase.org/98730 Reviewed-by: Johan Larson <[email protected]> Tested-by: Sitaram Vemulapalli <[email protected]>
1 parent ebe002a commit 9bac49a

File tree

15 files changed

+1262
-87
lines changed

15 files changed

+1262
-87
lines changed

algebra/order.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,18 @@ value that decides the sort order (ASC or DESC).
7575
type SortTerm struct {
7676
expr expression.Expression `json:"expr"`
7777
descending bool `json:"desc"`
78+
nullsPos bool `json:"nulls_pos"`
7879
}
7980

8081
/*
8182
The function NewSortTerm returns a pointer to the SortTerm
8283
struct that has its fields set to the input arguments.
8384
*/
84-
func NewSortTerm(expr expression.Expression, descending bool) *SortTerm {
85+
func NewSortTerm(expr expression.Expression, descending, nullsPos bool) *SortTerm {
8586
return &SortTerm{
8687
expr: expr,
8788
descending: descending,
89+
nullsPos: nullsPos,
8890
}
8991
}
9092

@@ -96,6 +98,11 @@ func (this *SortTerm) String() string {
9698

9799
if this.descending {
98100
s += " desc"
101+
if this.NullsPos() {
102+
s += " NULLS FIRST"
103+
}
104+
} else if this.NullsPos() {
105+
s += " NULLS LAST"
99106
}
100107

101108
return s
@@ -116,6 +123,10 @@ func (this *SortTerm) Descending() bool {
116123
return this.descending
117124
}
118125

126+
func (this *SortTerm) NullsPos() bool {
127+
return this.nullsPos
128+
}
129+
119130
/*
120131
Map Expressions for all sort terms in the receiver.
121132
*/
@@ -159,3 +170,26 @@ func (this SortTerms) String() string {
159170

160171
return s
161172
}
173+
174+
const (
175+
ORDER_NULLS_NONE = 1 << iota
176+
ORDER_NULLS_FIRST
177+
ORDER_NULLS_LAST
178+
)
179+
180+
func NewOrderNulls(none, nulls, last bool) (r uint32) {
181+
if none {
182+
r |= ORDER_NULLS_NONE
183+
} else if nulls {
184+
if last {
185+
r |= ORDER_NULLS_LAST
186+
} else {
187+
r |= ORDER_NULLS_FIRST
188+
}
189+
}
190+
return
191+
}
192+
193+
func NewOrderNullsPos(descending bool, nulls uint32) bool {
194+
return (!descending && (nulls&ORDER_NULLS_LAST) != 0) || (descending && (nulls&ORDER_NULLS_FIRST) != 0)
195+
}

execution/order.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,16 @@ func (this *Order) lessThan(v1 value.AnnotatedValue, v2 value.AnnotatedValue) bo
154154
v2.SetAttachment(s, ev2)
155155
}
156156

157-
c = ev1.Collate(ev2)
157+
if !term.NullsPos() || ((ev1.Type() <= value.NULL && ev2.Type() <= value.NULL) ||
158+
(ev1.Type() > value.NULL && ev2.Type() > value.NULL)) {
159+
c = ev1.Collate(ev2)
160+
} else {
161+
if ev1.Type() <= value.NULL && ev2.Type() > value.NULL {
162+
c = 1
163+
} else {
164+
c = -1
165+
}
166+
}
158167

159168
if c == 0 {
160169
continue

parser/n1ql/n1ql.nex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@
230230
/[nN][lL]/ { yylex.logToken(yylex.Text(), "NL"); return NL }
231231
/[nN][oO][tT]/ { yylex.logToken(yylex.Text(), "NOT"); return NOT }
232232
/[nN][uU][lL][lL]/ { yylex.logToken(yylex.Text(), "NULL"); return NULL }
233+
/[nN][uU][lL][lL][sS]/ { yylex.logToken(yylex.Text(), "NULLS"); return NULLS }
233234
/[nN][uN][mM][bB][eE][rR]/ { yylex.logToken(yylex.Text(), "NUMBER"); return NUMBER }
234235
/[oO][bB][jJ][eE][cC][tT]/ { yylex.logToken(yylex.Text(), "OBJECT"); return OBJECT }
235236
/[oO][fF][fF][sS][eE][tT]/ { yylex.logToken(yylex.Text(), "OFFSET"); return OFFSET }

0 commit comments

Comments
 (0)