提交 e647b73b authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Allow expressions based on DISTINCT values in ORDER BY

上级 5da46ca4
......@@ -14,9 +14,14 @@ import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.engine.Mode.ModeEnum;
import org.h2.expression.Alias;
import org.h2.expression.Comparison;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.ConditionNot;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn;
import org.h2.expression.ExpressionVisitor;
import org.h2.expression.Function;
import org.h2.expression.Operation;
import org.h2.expression.Parameter;
import org.h2.expression.ValueExpression;
import org.h2.message.DbException;
......@@ -480,9 +485,11 @@ public abstract class Query extends Prepared {
if (!isAlias) {
if (mustBeInResult) {
if (session.getDatabase().getMode().getEnum() != ModeEnum.MySQL) {
if (!checkOrderOther(session, e, expressionSQL)) {
throw DbException.get(ErrorCode.ORDER_BY_NOT_IN_RESULT, e.getSQL());
}
}
}
expressions.add(e);
String sql = e.getSQL();
expressionSQL.add(sql);
......@@ -492,6 +499,52 @@ public abstract class Query extends Prepared {
}
}
private static boolean checkOrderOther(Session session, Expression expr, ArrayList<String> expressionSQL) {
if (expr.isConstant()) {
return true;
}
if (expressionSQL != null) {
String exprSQL = expr.getSQL();
for (String sql: expressionSQL) {
if (session.getDatabase().equalsIdentifiers(exprSQL, sql)) {
return true;
}
}
}
if (expr instanceof Function) {
Function function = (Function) expr;
if (!function.isDeterministic()) {
return false;
}
for (Expression e : function.getArgs()) {
if (!checkOrderOther(session, e, expressionSQL)) {
return false;
}
}
return true;
}
if (expr instanceof Operation) {
Operation operation = (Operation) expr;
Expression right = operation.getExpression(false);
return checkOrderOther(session, operation.getExpression(true), expressionSQL)
&& (right == null || checkOrderOther(session, right, expressionSQL));
}
if (expr instanceof ConditionAndOr) {
ConditionAndOr condition = (ConditionAndOr) expr;
return checkOrderOther(session, condition.getExpression(true), expressionSQL)
&& checkOrderOther(session, condition.getExpression(false), expressionSQL);
}
if (expr instanceof ConditionNot) {
return checkOrderOther(session, ((ConditionNot) expr).getCondition(), expressionSQL);
}
if (expr instanceof Comparison) {
Comparison condition = (Comparison) expr;
return checkOrderOther(session, condition.getExpression(true), expressionSQL)
&& checkOrderOther(session, condition.getExpression(false), expressionSQL);
}
return false;
}
/**
* Create a {@link SortOrder} object given the list of {@link SelectOrderBy}
* objects. The expression list is extended if necessary.
......
......@@ -98,4 +98,13 @@ public class ConditionNot extends Condition {
return condition.getCost();
}
/**
* Get the sub-expression of this condition.
*
* @return the sub-expression
*/
public Expression getCondition() {
return condition;
}
}
......@@ -407,4 +407,15 @@ public class Operation extends Expression {
return left.getCost() + 1 + (right == null ? 0 : right.getCost());
}
/**
* Get the left or the right sub-expression of this condition.
*
* @param getLeft true to get the left sub-expression, false to get the
* right sub-expression.
* @return the sub-expression
*/
public Expression getExpression(boolean getLeft) {
return getLeft ? this.left : right;
}
}
......@@ -15,6 +15,60 @@ CREATE TABLE TEST2(ID2 BIGINT);
INSERT INTO TEST2 VALUES (1), (2);
> update count: 2
SELECT DISTINCT NAME FROM TEST ORDER BY NAME;
> NAME
> ----
> B
> a
> c
> rows (ordered): 3
SELECT DISTINCT NAME FROM TEST ORDER BY LOWER(NAME);
> NAME
> ----
> a
> B
> c
> rows (ordered): 3
SELECT DISTINCT ID FROM TEST ORDER BY ID;
> ID
> --
> 1
> 2
> 3
> rows (ordered): 3
SELECT DISTINCT ID FROM TEST ORDER BY -ID - 1;
> ID
> --
> 3
> 2
> 1
> rows (ordered): 3
SELECT DISTINCT ID FROM TEST ORDER BY (-ID + 10) > 0 AND NOT (ID = 0), ID;
> ID
> --
> 1
> 2
> 3
> rows (ordered): 3
SELECT DISTINCT NAME, ID + 1 FROM TEST ORDER BY UPPER(NAME) || (ID + 1);
> NAME ID + 1
> ---- ------
> a 2
> B 3
> c 4
> rows (ordered): 3
SELECT DISTINCT ID FROM TEST ORDER BY NAME;
> exception ORDER_BY_NOT_IN_RESULT
SELECT DISTINCT ID FROM TEST ORDER BY CURRENT_TIMESTAMP;
> exception ORDER_BY_NOT_IN_RESULT
SET MODE MySQL;
> ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论