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

Add support for both preceding or both following bounds

上级 2170322c
...@@ -2551,7 +2551,7 @@ They also may require a lot of memory for large queries. ...@@ -2551,7 +2551,7 @@ They also may require a lot of memory for large queries.
"Other Grammar","Window frame"," "Other Grammar","Window frame","
ROWS|RANGE|GROUP ROWS|RANGE|GROUP
{windowFramePreceding|BETWEEN windowFramePreceding AND windowFrameFollowing} {windowFramePreceding|BETWEEN windowFrameBound AND windowFrameBound}
[EXCLUDE {CURRENT ROW|GROUP|TIES|NO OTHERS}] [EXCLUDE {CURRENT ROW|GROUP|TIES|NO OTHERS}]
"," ","
A window frame clause. A window frame clause.
...@@ -2571,12 +2571,14 @@ UNBOUNDED PRECEDING ...@@ -2571,12 +2571,14 @@ UNBOUNDED PRECEDING
CURRENT ROW CURRENT ROW
" "
"Other Grammar","Window frame following"," "Other Grammar","Window frame bound","
UNBOUNDED FOLLOWING|value FOLLOWING|CURRENT ROW UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
|value FOLLOWING|UNBOUNDED FOLLOWING
"," ","
A window frame following clause. A window frame bound clause.
If value is specified it should be non-negative value or parameter. If value is specified it should be non-negative value or parameter.
"," ","
UNBOUNDED PRECEDING
UNBOUNDED FOLLOWING UNBOUNDED FOLLOWING
1 FOLLOWING 1 FOLLOWING
CURRENT ROW CURRENT ROW
......
...@@ -177,7 +177,7 @@ import org.h2.expression.aggregate.JavaAggregate; ...@@ -177,7 +177,7 @@ import org.h2.expression.aggregate.JavaAggregate;
import org.h2.expression.aggregate.Window; import org.h2.expression.aggregate.Window;
import org.h2.expression.aggregate.WindowFrame; import org.h2.expression.aggregate.WindowFrame;
import org.h2.expression.aggregate.WindowFrameBound; import org.h2.expression.aggregate.WindowFrameBound;
import org.h2.expression.aggregate.WindowFrameBound.WindowFrameBoundType; import org.h2.expression.aggregate.WindowFrameBoundType;
import org.h2.expression.aggregate.WindowFrameExclusion; import org.h2.expression.aggregate.WindowFrameExclusion;
import org.h2.expression.aggregate.WindowFrameUnits; import org.h2.expression.aggregate.WindowFrameUnits;
import org.h2.expression.aggregate.WindowFunction; import org.h2.expression.aggregate.WindowFunction;
...@@ -3105,9 +3105,9 @@ public class Parser { ...@@ -3105,9 +3105,9 @@ public class Parser {
} }
WindowFrameBound starting, following; WindowFrameBound starting, following;
if (readIf("BETWEEN")) { if (readIf("BETWEEN")) {
starting = readWindowFrameStarting(); starting = readWindowFrameRange();
read("AND"); read("AND");
following = readWindowFrameFollowing(); following = readWindowFrameRange();
} else { } else {
starting = readWindowFrameStarting(); starting = readWindowFrameStarting();
following = null; following = null;
...@@ -3132,7 +3132,7 @@ public class Parser { ...@@ -3132,7 +3132,7 @@ public class Parser {
private WindowFrameBound readWindowFrameStarting() { private WindowFrameBound readWindowFrameStarting() {
if (readIf("UNBOUNDED")) { if (readIf("UNBOUNDED")) {
read("PRECEDING"); read("PRECEDING");
return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED, null); return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_PRECEDING, null);
} }
if (readIf("CURRENT")) { if (readIf("CURRENT")) {
read("ROW"); read("ROW");
...@@ -3140,21 +3140,27 @@ public class Parser { ...@@ -3140,21 +3140,27 @@ public class Parser {
} }
Expression value = readValueOrParameter(); Expression value = readValueOrParameter();
read("PRECEDING"); read("PRECEDING");
return new WindowFrameBound(WindowFrameBoundType.VALUE, value); return new WindowFrameBound(WindowFrameBoundType.PRECEDING, value);
} }
private WindowFrameBound readWindowFrameFollowing() { private WindowFrameBound readWindowFrameRange() {
if (readIf("UNBOUNDED")) { if (readIf("UNBOUNDED")) {
if (readIf("PRECEDING")) {
return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_PRECEDING, null);
}
read("FOLLOWING"); read("FOLLOWING");
return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED, null); return new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_FOLLOWING, null);
} }
if (readIf("CURRENT")) { if (readIf("CURRENT")) {
read("ROW"); read("ROW");
return new WindowFrameBound(WindowFrameBoundType.CURRENT_ROW, null); return new WindowFrameBound(WindowFrameBoundType.CURRENT_ROW, null);
} }
Expression value = readValueOrParameter(); Expression value = readValueOrParameter();
if (readIf("PRECEDING")) {
return new WindowFrameBound(WindowFrameBoundType.PRECEDING, value);
}
read("FOLLOWING"); read("FOLLOWING");
return new WindowFrameBound(WindowFrameBoundType.VALUE, value); return new WindowFrameBound(WindowFrameBoundType.FOLLOWING, value);
} }
private Expression readValueOrParameter() { private Expression readValueOrParameter() {
......
...@@ -10,7 +10,6 @@ import java.util.ArrayList; ...@@ -10,7 +10,6 @@ import java.util.ArrayList;
import org.h2.command.dml.SelectOrderBy; import org.h2.command.dml.SelectOrderBy;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.expression.aggregate.WindowFrameBound.WindowFrameBoundType;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
...@@ -66,8 +65,9 @@ public final class Window { ...@@ -66,8 +65,9 @@ public final class Window {
this.partitionBy = partitionBy; this.partitionBy = partitionBy;
this.orderBy = orderBy; this.orderBy = orderBy;
if (frame == null) { if (frame == null) {
frame = new WindowFrame(WindowFrameUnits.RANGE, new WindowFrameBound(WindowFrameBoundType.UNBOUNDED, null), frame = new WindowFrame(WindowFrameUnits.RANGE,
null, WindowFrameExclusion.EXCLUDE_NO_OTHERS); new WindowFrameBound(WindowFrameBoundType.UNBOUNDED_PRECEDING, null), null,
WindowFrameExclusion.EXCLUDE_NO_OTHERS);
} }
this.frame = frame; this.frame = frame;
} }
......
...@@ -6,35 +6,12 @@ ...@@ -6,35 +6,12 @@
package org.h2.expression.aggregate; package org.h2.expression.aggregate;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.message.DbException;
/** /**
* Window frame bound. * Window frame bound.
*/ */
public class WindowFrameBound { public class WindowFrameBound {
/**
* Window frame bound type.
*/
public enum WindowFrameBoundType {
/**
* UNBOUNDED PRECEDING or UNBOUNDED FOLLOWING clause.
*/
UNBOUNDED,
/**
* CURRENT_ROW clause.
*/
CURRENT_ROW,
/**
* PRECEDING or FOLLOWING clause.
*/
VALUE;
}
private final WindowFrameBoundType type; private final WindowFrameBoundType type;
private final Expression value; private final Expression value;
...@@ -49,7 +26,7 @@ public class WindowFrameBound { ...@@ -49,7 +26,7 @@ public class WindowFrameBound {
*/ */
public WindowFrameBound(WindowFrameBoundType type, Expression value) { public WindowFrameBound(WindowFrameBoundType type, Expression value) {
this.type = type; this.type = type;
if (type == WindowFrameBoundType.VALUE) { if (type == WindowFrameBoundType.PRECEDING || type == WindowFrameBoundType.FOLLOWING) {
this.value = value; this.value = value;
} else { } else {
this.value = null; this.value = null;
...@@ -84,16 +61,10 @@ public class WindowFrameBound { ...@@ -84,16 +61,10 @@ public class WindowFrameBound {
* @see Expression#getSQL() * @see Expression#getSQL()
*/ */
public String getSQL(boolean following) { public String getSQL(boolean following) {
switch (type) { if (type == WindowFrameBoundType.PRECEDING || type == WindowFrameBoundType.FOLLOWING) {
case UNBOUNDED: return value.getSQL() + ' ' + type.getSQL();
return following ? "UNBOUNDED FOLLOWING" : "UNBOUNDED PRECEDING";
case CURRENT_ROW:
return "CURRENT ROW";
case VALUE:
return value.getSQL() + (following ? " FOLLOWING" : " PRECEDING");
default:
throw DbException.throwInternalError("type=" + type);
} }
return type.getSQL();
} }
} }
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.expression.aggregate;
/**
* Window frame bound type.
*/
public enum WindowFrameBoundType {
/**
* UNBOUNDED PRECEDING clause.
*/
UNBOUNDED_PRECEDING("UNBOUNDED PRECEDING"),
/**
* PRECEDING clause.
*/
PRECEDING("PRECEDING"),
/**
* CURRENT_ROW clause.
*/
CURRENT_ROW("CURRENT_ROW"),
/**
* FOLLOWING clause.
*/
FOLLOWING("FOLLOWING"),
/**
* UNBOUNDED FOLLOWING clause.
*/
UNBOUNDED_FOLLOWING("UNBOUNDED FOLLOWING");
private final String sql;
private WindowFrameBoundType(String sql) {
this.sql = sql;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public String getSQL() {
return sql;
}
}
...@@ -314,5 +314,17 @@ SELECT *, ...@@ -314,5 +314,17 @@ SELECT *,
SELECT *, ARRAY_AGG(ID) OVER (ORDER BY VALUE ROWS -1 PRECEDING) FROM TEST; SELECT *, ARRAY_AGG(ID) OVER (ORDER BY VALUE ROWS -1 PRECEDING) FROM TEST;
> exception INVALID_VALUE_2 > exception INVALID_VALUE_2
SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) FROM TEST FETCH FIRST 4 ROWS ONLY;
> ID VALUE ARRAY_AGG(ID) OVER (ORDER BY ID ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING)
> -- ----- -------------------------------------------------------------------------
> 1 1 null
> 2 1 (1)
> 3 5 (1, 2)
> 4 8 (2, 3)
> rows (ordered): 4
SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID RANGE BETWEEN CURRENT ROW AND 1 PRECEDING) FROM TEST;
> exception SYNTAX_ERROR_1
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论