提交 3e61ab53 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Fix RANGE BETWEEN with same direction

上级 fca685a7
...@@ -182,20 +182,16 @@ public final class WindowFrame { ...@@ -182,20 +182,16 @@ public final class WindowFrame {
return value; return value;
} }
private static Value plus(Session session, ArrayList<Value[]> orderedRows, int currentRow, WindowFrameBound bound, private static Value[] getCompareRow(Session session, ArrayList<Value[]> orderedRows, SortOrder sortOrder,
int index) { int currentRow, WindowFrameBound bound, boolean add) {
return new BinaryOperation(OpType.PLUS, // int sortIndex = sortOrder.getQueryColumnIndexes()[0];
ValueExpression.get(orderedRows.get(currentRow)[index]), OpType opType = add ^ (sortOrder.getSortTypes()[0] & SortOrder.DESCENDING) != 0 ? OpType.PLUS : OpType.MINUS;
ValueExpression.get(getValueOffset(bound, session))) // Value[] row = orderedRows.get(currentRow);
.optimize(session).getValue(session); Value[] newRow = row.clone();
} newRow[sortIndex] = new BinaryOperation(opType, //
ValueExpression.get(row[sortIndex]), ValueExpression.get(getValueOffset(bound, session))) //
private static Value minus(Session session, ArrayList<Value[]> orderedRows, int currentRow, WindowFrameBound bound,
int index) {
return new BinaryOperation(OpType.MINUS, //
ValueExpression.get(orderedRows.get(currentRow)[index]),
ValueExpression.get(getValueOffset(bound, session))) //
.optimize(session).getValue(session); .optimize(session).getValue(session);
return newRow;
} }
private static Value getValueOffset(WindowFrameBound bound, Session session) { private static Value getValueOffset(WindowFrameBound bound, Session session) {
...@@ -273,6 +269,9 @@ public final class WindowFrame { ...@@ -273,6 +269,9 @@ public final class WindowFrame {
int endIndex = following != null ? getIndex(session, orderedRows, sortOrder, currentRow, following, true) int endIndex = following != null ? getIndex(session, orderedRows, sortOrder, currentRow, following, true)
: currentRow; : currentRow;
if (endIndex < startIndex) { if (endIndex < startIndex) {
startIndex = getIndex(session, orderedRows, sortOrder, currentRow, starting, false);
endIndex = following != null ? getIndex(session, orderedRows, sortOrder, currentRow, following, true)
: currentRow;
throw DbException.get(ErrorCode.SYNTAX_ERROR_1, getSQL()); throw DbException.get(ErrorCode.SYNTAX_ERROR_1, getSQL());
} }
int size = orderedRows.size(); int size = orderedRows.size();
...@@ -334,15 +333,25 @@ public final class WindowFrame { ...@@ -334,15 +333,25 @@ public final class WindowFrame {
} }
case RANGE: { case RANGE: {
index = currentRow; index = currentRow;
int sortIndex = sortOrder.getQueryColumnIndexes()[0]; Value[] row = getCompareRow(session, orderedRows, sortOrder, index, bound, false);
if ((sortOrder.getSortTypes()[0] & SortOrder.DESCENDING) != 0) { index = Collections.binarySearch(orderedRows, row, sortOrder);
Value c = plus(session, orderedRows, currentRow, bound, sortIndex); if (index >= 0) {
while (index > 0 && session.getDatabase().compare(c, orderedRows.get(index - 1)[sortIndex]) >= 0) { if (!forFollowing) {
while (index > 0 && sortOrder.compare(row, orderedRows.get(index - 1)) == 0) {
index--; index--;
} }
} else { } else {
Value c = minus(session, orderedRows, currentRow, bound, sortIndex); while (index < last && sortOrder.compare(row, orderedRows.get(index + 1)) == 0) {
while (index > 0 && session.getDatabase().compare(c, orderedRows.get(index - 1)[sortIndex]) <= 0) { index++;
}
}
} else {
index = ~index;
if (!forFollowing) {
if (index == 0) {
index = -1;
}
} else {
index--; index--;
} }
} }
...@@ -389,18 +398,24 @@ public final class WindowFrame { ...@@ -389,18 +398,24 @@ public final class WindowFrame {
} }
case RANGE: { case RANGE: {
index = currentRow; index = currentRow;
int sortIndex = sortOrder.getQueryColumnIndexes()[0]; Value[] row = getCompareRow(session, orderedRows, sortOrder, index, bound, true);
if ((sortOrder.getSortTypes()[0] & SortOrder.DESCENDING) != 0) { index = Collections.binarySearch(orderedRows, row, sortOrder);
Value c = minus(session, orderedRows, currentRow, bound, sortIndex); if (index >= 0) {
while (index < last if (forFollowing) {
&& session.getDatabase().compare(c, orderedRows.get(index + 1)[sortIndex]) <= 0) { while (index < last && sortOrder.compare(row, orderedRows.get(index + 1)) == 0) {
index++; index++;
} }
} else { } else {
Value c = plus(session, orderedRows, currentRow, bound, sortIndex); while (index > 0 && sortOrder.compare(row, orderedRows.get(index - 1)) == 0) {
while (index < last index--;
&& session.getDatabase().compare(c, orderedRows.get(index + 1)[sortIndex]) >= 0) { }
index++; }
} else {
index = ~index;
if (forFollowing) {
if (index != size) {
index--;
}
} }
} }
break; break;
......
...@@ -332,6 +332,24 @@ SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWI ...@@ -332,6 +332,24 @@ SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID ROWS BETWEEN 1 FOLLOWING AND 2 FOLLOWI
> 8 9 null > 8 9 null
> rows (ordered): 4 > rows (ordered): 4
SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID RANGE BETWEEN 2 PRECEDING AND 1 PRECEDING) FROM TEST FETCH FIRST 4 ROWS ONLY;
> ID VALUE ARRAY_AGG(ID) OVER (ORDER BY ID RANGE 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 1 FOLLOWING AND 2 FOLLOWING) FROM TEST OFFSET 4 ROWS;
> ID VALUE ARRAY_AGG(ID) OVER (ORDER BY ID RANGE BETWEEN 1 FOLLOWING AND 2 FOLLOWING)
> -- ----- --------------------------------------------------------------------------
> 5 8 (6, 7)
> 6 8 (7, 8)
> 7 9 (8)
> 8 9 null
> rows (ordered): 4
SELECT *, SELECT *,
ARRAY_AGG(ID) OVER (ORDER BY VALUE GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) U_P, ARRAY_AGG(ID) OVER (ORDER BY VALUE GROUPS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) U_P,
ARRAY_AGG(ID) OVER (ORDER BY VALUE GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING) P, ARRAY_AGG(ID) OVER (ORDER BY VALUE GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING) P,
...@@ -371,3 +389,46 @@ SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID RANGE BETWEEN CURRENT ROW AND 1 PRECED ...@@ -371,3 +389,46 @@ SELECT *, ARRAY_AGG(ID) OVER (ORDER BY ID RANGE BETWEEN CURRENT ROW AND 1 PRECED
DROP TABLE TEST; DROP TABLE TEST;
> ok > ok
CREATE TABLE TEST (ID INT, VALUE INT);
> ok
INSERT INTO TEST VALUES
(1, 1),
(2, 1),
(3, 2),
(4, 2),
(5, 3),
(6, 3),
(7, 4),
(8, 4);
> update count: 8
SELECT *, ARRAY_AGG(ID) OVER (ORDER BY VALUE RANGE BETWEEN 2 PRECEDING AND 1 PRECEDING) FROM TEST;
> ID VALUE ARRAY_AGG(ID) OVER (ORDER BY VALUE RANGE BETWEEN 2 PRECEDING AND 1 PRECEDING)
> -- ----- -----------------------------------------------------------------------------
> 1 1 null
> 2 1 null
> 3 2 (1, 2)
> 4 2 (1, 2)
> 5 3 (1, 2, 3, 4)
> 6 3 (1, 2, 3, 4)
> 7 4 (3, 4, 5, 6)
> 8 4 (3, 4, 5, 6)
> rows (ordered): 8
SELECT *, ARRAY_AGG(ID) OVER (ORDER BY VALUE RANGE BETWEEN 1 FOLLOWING AND 2 FOLLOWING) FROM TEST;
> ID VALUE ARRAY_AGG(ID) OVER (ORDER BY VALUE RANGE BETWEEN 1 FOLLOWING AND 2 FOLLOWING)
> -- ----- -----------------------------------------------------------------------------
> 1 1 (3, 4, 5, 6)
> 2 1 (3, 4, 5, 6)
> 3 2 (5, 6, 7, 8)
> 4 2 (5, 6, 7, 8)
> 5 3 (7, 8)
> 6 3 (7, 8)
> 7 4 null
> 8 4 null
> rows (ordered): 8
DROP TABLE TEST;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论