Unverified 提交 5b560a41 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1098 from katzyn/nulls

Fix some issues with NULLS FIRST / LAST
...@@ -882,24 +882,30 @@ public class Parser { ...@@ -882,24 +882,30 @@ public class Parser {
do { do {
IndexColumn column = new IndexColumn(); IndexColumn column = new IndexColumn();
column.columnName = readColumnIdentifier(); column.columnName = readColumnIdentifier();
column.sortType = parseSortType();
columns.add(column); columns.add(column);
if (readIf("ASC")) {
// ignore
} else if (readIf("DESC")) {
column.sortType = SortOrder.DESCENDING;
}
if (readIf("NULLS")) {
if (readIf("FIRST")) {
column.sortType |= SortOrder.NULLS_FIRST;
} else {
read("LAST");
column.sortType |= SortOrder.NULLS_LAST;
}
}
} while (readIfMore(true)); } while (readIfMore(true));
return columns.toArray(new IndexColumn[0]); return columns.toArray(new IndexColumn[0]);
} }
private int parseSortType() {
int sortType = 0;
if (readIf("ASC")) {
// ignore
} else if (readIf("DESC")) {
sortType = SortOrder.DESCENDING;
}
if (readIf("NULLS")) {
if (readIf("FIRST")) {
sortType |= SortOrder.NULLS_FIRST;
} else {
read("LAST");
sortType |= SortOrder.NULLS_LAST;
}
}
return sortType;
}
private String[] parseColumnList() { private String[] parseColumnList() {
ArrayList<String> columns = Utils.newSmallArrayList(); ArrayList<String> columns = Utils.newSmallArrayList();
do { do {
...@@ -2029,19 +2035,7 @@ public class Parser { ...@@ -2029,19 +2035,7 @@ public class Parser {
} else { } else {
order.expression = expr; order.expression = expr;
} }
if (readIf("DESC")) { order.sortType = parseSortType();
order.descending = true;
} else {
readIf("ASC");
}
if (readIf("NULLS")) {
if (readIf("FIRST")) {
order.nullsFirst = true;
} else {
read("LAST");
order.nullsLast = true;
}
}
orderList.add(order); orderList.add(order);
} while (readIf(",")); } while (readIf(","));
command.setOrder(orderList); command.setOrder(orderList);
...@@ -2701,11 +2695,7 @@ public class Parser { ...@@ -2701,11 +2695,7 @@ public class Parser {
do { do {
SelectOrderBy order = new SelectOrderBy(); SelectOrderBy order = new SelectOrderBy();
order.expression = readExpression(); order.expression = readExpression();
if (readIf("DESC")) { order.sortType = parseSortType();
order.descending = true;
} else {
readIf("ASC");
}
orderList.add(order); orderList.add(order);
} while (readIf(",")); } while (readIf(","));
return orderList; return orderList;
......
...@@ -524,15 +524,14 @@ public abstract class Query extends Prepared { ...@@ -524,15 +524,14 @@ public abstract class Query extends Prepared {
} }
} }
index[i] = idx; index[i] = idx;
boolean desc = o.descending; int type = o.sortType;
if (reverse) { if (reverse) {
desc = !desc; // TODO NULLS FIRST / LAST should be inverted too?
} if ((type & SortOrder.DESCENDING) != 0) {
int type = desc ? SortOrder.DESCENDING : SortOrder.ASCENDING; type &= ~SortOrder.DESCENDING;
if (o.nullsFirst) { } else {
type += SortOrder.NULLS_FIRST; type |= SortOrder.DESCENDING;
} else if (o.nullsLast) { }
type += SortOrder.NULLS_LAST;
} }
sortType[i] = type; sortType[i] = type;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.command.dml; package org.h2.command.dml;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.result.SortOrder;
/** /**
* Describes one element of the ORDER BY clause of a query. * Describes one element of the ORDER BY clause of a query.
...@@ -25,19 +26,9 @@ public class SelectOrderBy { ...@@ -25,19 +26,9 @@ public class SelectOrderBy {
public Expression columnIndexExpr; public Expression columnIndexExpr;
/** /**
* If the column should be sorted descending. * Sort type for this column.
*/ */
public boolean descending; public int sortType;
/**
* If NULL should be appear first.
*/
public boolean nullsFirst;
/**
* If NULL should be appear at the end.
*/
public boolean nullsLast;
public String getSQL() { public String getSQL() {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
...@@ -46,14 +37,7 @@ public class SelectOrderBy { ...@@ -46,14 +37,7 @@ public class SelectOrderBy {
} else { } else {
buff.append(columnIndexExpr.getSQL()); buff.append(columnIndexExpr.getSQL());
} }
if (descending) { SortOrder.typeToString(buff, sortType);
buff.append(" DESC");
}
if (nullsFirst) {
buff.append(" NULLS FIRST");
} else if (nullsLast) {
buff.append(" NULLS LAST");
}
return buff.toString(); return buff.toString();
} }
......
...@@ -252,8 +252,7 @@ public class Aggregate extends Expression { ...@@ -252,8 +252,7 @@ public class Aggregate extends Expression {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
SelectOrderBy o = orderByList.get(i); SelectOrderBy o = orderByList.get(i);
index[i] = i + 1; index[i] = i + 1;
int order = o.descending ? SortOrder.DESCENDING : SortOrder.ASCENDING; sortType[i] = o.sortType;
sortType[i] = order;
} }
return new SortOrder(session.getDatabase(), index, sortType, null); return new SortOrder(session.getDatabase(), index, sortType, null);
} }
...@@ -590,9 +589,7 @@ public class Aggregate extends Expression { ...@@ -590,9 +589,7 @@ public class Aggregate extends Expression {
for (SelectOrderBy o : orderByList) { for (SelectOrderBy o : orderByList) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(o.expression.getSQL()); buff.append(o.expression.getSQL());
if (o.descending) { SortOrder.typeToString(buff.builder(), o.sortType);
buff.append(" DESC");
}
} }
} }
if (groupConcatSeparator != null) { if (groupConcatSeparator != null) {
...@@ -616,9 +613,7 @@ public class Aggregate extends Expression { ...@@ -616,9 +613,7 @@ public class Aggregate extends Expression {
for (SelectOrderBy o : orderByList) { for (SelectOrderBy o : orderByList) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
buff.append(o.expression.getSQL()); buff.append(o.expression.getSQL());
if (o.descending) { SortOrder.typeToString(buff.builder(), o.sortType);
buff.append(" DESC");
}
} }
} }
buff.append(')'); buff.append(')');
......
...@@ -12,6 +12,7 @@ import java.util.Comparator; ...@@ -12,6 +12,7 @@ import java.util.Comparator;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.engine.SysProperties;
import org.h2.index.Cursor; import org.h2.index.Cursor;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
...@@ -42,7 +43,8 @@ class AggregateDataMedian extends AggregateDataCollecting { ...@@ -42,7 +43,8 @@ class AggregateDataMedian extends AggregateDataCollecting {
IndexColumn ic = index.getIndexColumns()[0]; IndexColumn ic = index.getIndexColumns()[0];
int sortType = ic.sortType; int sortType = ic.sortType;
return (sortType & SortOrder.NULLS_LAST) != 0 return (sortType & SortOrder.NULLS_LAST) != 0
|| (sortType & SortOrder.DESCENDING) != 0 && (sortType & SortOrder.NULLS_FIRST) == 0; || (sortType & SortOrder.NULLS_FIRST) == 0
&& ((sortType & SortOrder.DESCENDING) != 0 ^ SysProperties.SORT_NULLS_HIGH);
} }
/** /**
......
...@@ -364,6 +364,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -364,6 +364,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
if (a == b) { if (a == b) {
return 0; return 0;
} }
boolean aNull = a == ValueNull.INSTANCE;
boolean bNull = b == ValueNull.INSTANCE;
if (aNull || bNull) {
return SortOrder.compareNull(aNull, sortType);
}
int comp = table.compareTypeSafe(a, b); int comp = table.compareTypeSafe(a, b);
if ((sortType & SortOrder.DESCENDING) != 0) { if ((sortType & SortOrder.DESCENDING) != 0) {
comp = -comp; comp = -comp;
......
...@@ -50,20 +50,31 @@ public class SortOrder implements Comparator<Value[]> { ...@@ -50,20 +50,31 @@ public class SortOrder implements Comparator<Value[]> {
public static final int NULLS_LAST = 4; public static final int NULLS_LAST = 4;
/** /**
* The default sort order for NULL. * The default comparison result for NULL, either 1 or -1.
*/ */
private static final int DEFAULT_NULL_SORT = private static final int DEFAULT_NULL_SORT;
SysProperties.SORT_NULLS_HIGH ? 1 : -1;
/** /**
* The default sort order bit for NULLs last. * The default NULLs sort order bit for ASC indexes.
*/ */
private static final int DEFAULT_NULLS_LAST = SysProperties.SORT_NULLS_HIGH ? NULLS_LAST : NULLS_FIRST; private static final int DEFAULT_ASC_NULLS;
/** /**
* The default sort order bit for NULLs first. * The default NULLs sort order bit for DESC indexes.
*/ */
private static final int DEFAULT_NULLS_FIRST = SysProperties.SORT_NULLS_HIGH ? NULLS_FIRST : NULLS_LAST; private static final int DEFAULT_DESC_NULLS;
static {
if (SysProperties.SORT_NULLS_HIGH) {
DEFAULT_NULL_SORT = 1;
DEFAULT_ASC_NULLS = NULLS_LAST;
DEFAULT_DESC_NULLS = NULLS_FIRST;
} else { // default
DEFAULT_NULL_SORT = -1;
DEFAULT_ASC_NULLS = NULLS_FIRST;
DEFAULT_DESC_NULLS = NULLS_LAST;
}
}
private final Database database; private final Database database;
...@@ -116,19 +127,27 @@ public class SortOrder implements Comparator<Value[]> { ...@@ -116,19 +127,27 @@ public class SortOrder implements Comparator<Value[]> {
} else { } else {
buff.append('=').append(StringUtils.unEnclose(list[idx].getSQL())); buff.append('=').append(StringUtils.unEnclose(list[idx].getSQL()));
} }
int type = sortTypes[i++]; typeToString(buff.builder(), sortTypes[i++]);
if ((type & DESCENDING) != 0) {
buff.append(" DESC");
}
if ((type & NULLS_FIRST) != 0) {
buff.append(" NULLS FIRST");
} else if ((type & NULLS_LAST) != 0) {
buff.append(" NULLS LAST");
}
} }
return buff.toString(); return buff.toString();
} }
/**
* Appends type information (DESC, NULLS FIRST, NULLS LAST) to the specified statement builder.
* @param builder statement builder
* @param type sort type
*/
public static void typeToString(StringBuilder builder, int type) {
if ((type & DESCENDING) != 0) {
builder.append(" DESC");
}
if ((type & NULLS_FIRST) != 0) {
builder.append(" NULLS FIRST");
} else if ((type & NULLS_LAST) != 0) {
builder.append(" NULLS LAST");
}
}
/** /**
* Compare two expressions where one of them is NULL. * Compare two expressions where one of them is NULL.
* *
...@@ -292,9 +311,9 @@ public class SortOrder implements Comparator<Value[]> { ...@@ -292,9 +311,9 @@ public class SortOrder implements Comparator<Value[]> {
* @param sortType sort type bit mask * @param sortType sort type bit mask
* @return bit mask with either {@link #NULLS_FIRST} or {@link #NULLS_LAST} explicitly set. * @return bit mask with either {@link #NULLS_FIRST} or {@link #NULLS_LAST} explicitly set.
*/ */
public static int addExplicitNullPosition(final int sortType) { public static int addExplicitNullPosition(int sortType) {
if ((sortType & NULLS_FIRST) != NULLS_FIRST && (sortType & NULLS_LAST) != NULLS_LAST) { if ((sortType & (NULLS_FIRST | NULLS_LAST)) == 0) {
return sortType | ((sortType & DESCENDING) == ASCENDING ? DEFAULT_NULLS_LAST : DEFAULT_NULLS_FIRST); return sortType | ((sortType & DESCENDING) == 0 ? DEFAULT_ASC_NULLS : DEFAULT_DESC_NULLS);
} else { } else {
return sortType; return sortType;
} }
......
...@@ -36,14 +36,7 @@ public class IndexColumn { ...@@ -36,14 +36,7 @@ public class IndexColumn {
*/ */
public String getSQL() { public String getSQL() {
StringBuilder buff = new StringBuilder(column.getSQL()); StringBuilder buff = new StringBuilder(column.getSQL());
if ((sortType & SortOrder.DESCENDING) != 0) { SortOrder.typeToString(buff, sortType);
buff.append(" DESC");
}
if ((sortType & SortOrder.NULLS_FIRST) != 0) {
buff.append(" NULLS FIRST");
} else if ((sortType & SortOrder.NULLS_LAST) != 0) {
buff.append(" NULLS LAST");
}
return buff.toString(); return buff.toString();
} }
......
...@@ -127,4 +127,12 @@ public class StatementBuilder { ...@@ -127,4 +127,12 @@ public class StatementBuilder {
return builder.length(); return builder.length();
} }
/**
* Return underlying builder.
* @return underlying builder
*/
public StringBuilder builder() {
return builder;
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论