提交 32d3ca3f authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add WindowFrame class and move some logic into it

上级 249129a2
...@@ -175,7 +175,8 @@ import org.h2.expression.aggregate.Aggregate; ...@@ -175,7 +175,8 @@ import org.h2.expression.aggregate.Aggregate;
import org.h2.expression.aggregate.Aggregate.AggregateType; import org.h2.expression.aggregate.Aggregate.AggregateType;
import org.h2.expression.aggregate.JavaAggregate; import org.h2.expression.aggregate.JavaAggregate;
import org.h2.expression.aggregate.Window; import org.h2.expression.aggregate.Window;
import org.h2.expression.aggregate.Window.SimpleWindowFrame; import org.h2.expression.aggregate.WindowFrame;
import org.h2.expression.aggregate.WindowFrame.SimpleExtent;
import org.h2.expression.aggregate.WindowFunction; import org.h2.expression.aggregate.WindowFunction;
import org.h2.expression.aggregate.WindowFunction.WindowFunctionType; import org.h2.expression.aggregate.WindowFunction.WindowFunctionType;
import org.h2.index.Index; import org.h2.index.Index;
...@@ -3062,7 +3063,7 @@ public class Parser { ...@@ -3062,7 +3063,7 @@ public class Parser {
} else if (!isAggregate) { } else if (!isAggregate) {
orderBy = new ArrayList<>(0); orderBy = new ArrayList<>(0);
} }
SimpleWindowFrame frame; WindowFrame frame;
if (aggregate instanceof WindowFunction) { if (aggregate instanceof WindowFunction) {
WindowFunction w = (WindowFunction) aggregate; WindowFunction w = (WindowFunction) aggregate;
switch (w.getFunctionType()) { switch (w.getFunctionType()) {
...@@ -3072,7 +3073,7 @@ public class Parser { ...@@ -3072,7 +3073,7 @@ public class Parser {
frame = readWindowFrame(); frame = readWindowFrame();
break; break;
default: default:
frame = SimpleWindowFrame.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW; frame = new WindowFrame(SimpleExtent.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW);
} }
} else { } else {
frame = readWindowFrame(); frame = readWindowFrame();
...@@ -3088,8 +3089,8 @@ public class Parser { ...@@ -3088,8 +3089,8 @@ public class Parser {
} }
} }
private SimpleWindowFrame readWindowFrame() { private WindowFrame readWindowFrame() {
SimpleWindowFrame frame; SimpleExtent extent;
if (readIf("RANGE")) { if (readIf("RANGE")) {
read("BETWEEN"); read("BETWEEN");
if (readIf("UNBOUNDED")) { if (readIf("UNBOUNDED")) {
...@@ -3097,11 +3098,11 @@ public class Parser { ...@@ -3097,11 +3098,11 @@ public class Parser {
read("AND"); read("AND");
if (readIf("CURRENT")) { if (readIf("CURRENT")) {
read("ROW"); read("ROW");
frame = SimpleWindowFrame.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW; extent = SimpleExtent.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW;
} else { } else {
read("UNBOUNDED"); read("UNBOUNDED");
read("FOLLOWING"); read("FOLLOWING");
frame = SimpleWindowFrame.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING; extent = SimpleExtent.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING;
} }
} else { } else {
read("CURRENT"); read("CURRENT");
...@@ -3109,12 +3110,12 @@ public class Parser { ...@@ -3109,12 +3110,12 @@ public class Parser {
read("AND"); read("AND");
read("UNBOUNDED"); read("UNBOUNDED");
read("FOLLOWING"); read("FOLLOWING");
frame = SimpleWindowFrame.RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING; extent = SimpleExtent.RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING;
} }
} else { } else {
frame = SimpleWindowFrame.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW; extent = SimpleExtent.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW;
} }
return frame; return new WindowFrame(extent);
} }
private AggregateType getAggregateType(String name) { private AggregateType getAggregateType(String name) {
......
...@@ -424,16 +424,23 @@ public abstract class AbstractAggregate extends Expression { ...@@ -424,16 +424,23 @@ public abstract class AbstractAggregate extends Expression {
*/ */
protected void getOrderedResultLoop(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered, protected void getOrderedResultLoop(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered,
int rowIdColumn) { int rowIdColumn) {
switch (over.getWindowFrame()) { WindowFrame frame = over.getWindowFrame();
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW: { if (frame.isDefault()) {
Object aggregateData = createAggregateData(); Object aggregateData = createAggregateData();
for (Value[] row : ordered) { for (Value[] row : ordered) {
updateFromExpressions(session, aggregateData, row); updateFromExpressions(session, aggregateData, row);
result.put(row[rowIdColumn].getInt(), getAggregatedValue(session, aggregateData)); result.put(row[rowIdColumn].getInt(), getAggregatedValue(session, aggregateData));
} }
break; } else if (frame.isFullPartition()) {
Object aggregateData = createAggregateData();
for (Value[] row : ordered) {
updateFromExpressions(session, aggregateData, row);
} }
case RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING: { Value value = getAggregatedValue(session, aggregateData);
for (Value[] row : ordered) {
result.put(row[rowIdColumn].getInt(), value);
}
} else {
// TODO optimize unordered aggregates // TODO optimize unordered aggregates
int size = ordered.size(); int size = ordered.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
...@@ -443,18 +450,6 @@ public abstract class AbstractAggregate extends Expression { ...@@ -443,18 +450,6 @@ public abstract class AbstractAggregate extends Expression {
} }
result.put(ordered.get(i)[rowIdColumn].getInt(), getAggregatedValue(session, aggregateData)); result.put(ordered.get(i)[rowIdColumn].getInt(), getAggregatedValue(session, aggregateData));
} }
break;
}
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING: {
Object aggregateData = createAggregateData();
for (Value[] row : ordered) {
updateFromExpressions(session, aggregateData, row);
}
Value value = getAggregatedValue(session, aggregateData);
for (Value[] row : ordered) {
result.put(row[rowIdColumn].getInt(), value);
}
}
} }
} }
......
...@@ -22,53 +22,11 @@ import org.h2.value.ValueArray; ...@@ -22,53 +22,11 @@ import org.h2.value.ValueArray;
*/ */
public final class Window { public final class Window {
/**
* Simple window frame.
*/
public enum SimpleWindowFrame {
/**
* RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW frame specification.
*/
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW("RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"),
/**
* RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING frame specification.
*/
RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING("RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING"),
/**
* RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING frame
* specification.
*/
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING(
"RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"),
;
private final String sql;
private SimpleWindowFrame(String sql) {
this.sql = sql;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see Expression#getSQL()
*/
public String getSQL() {
return sql;
}
}
private final ArrayList<Expression> partitionBy; private final ArrayList<Expression> partitionBy;
private final ArrayList<SelectOrderBy> orderBy; private final ArrayList<SelectOrderBy> orderBy;
private final SimpleWindowFrame frame; private final WindowFrame frame;
/** /**
* @param builder * @param builder
...@@ -100,7 +58,7 @@ public final class Window { ...@@ -100,7 +58,7 @@ public final class Window {
* @param frame * @param frame
* window frame clause * window frame clause
*/ */
public Window(ArrayList<Expression> partitionBy, ArrayList<SelectOrderBy> orderBy, SimpleWindowFrame frame) { public Window(ArrayList<Expression> partitionBy, ArrayList<SelectOrderBy> orderBy, WindowFrame frame) {
this.partitionBy = partitionBy; this.partitionBy = partitionBy;
this.orderBy = orderBy; this.orderBy = orderBy;
this.frame = frame; this.frame = frame;
...@@ -184,7 +142,7 @@ public final class Window { ...@@ -184,7 +142,7 @@ public final class Window {
* *
* @return window frame * @return window frame
*/ */
public SimpleWindowFrame getWindowFrame() { public WindowFrame getWindowFrame() {
return frame; return frame;
} }
...@@ -229,7 +187,7 @@ public final class Window { ...@@ -229,7 +187,7 @@ public final class Window {
builder.append(StringUtils.unEnclose(partitionBy.get(i).getSQL())); builder.append(StringUtils.unEnclose(partitionBy.get(i).getSQL()));
} }
} }
if (frame != SimpleWindowFrame.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW) { if (!frame.isDefault()) {
builder.append(' ').append(frame.getSQL()); builder.append(' ').append(frame.getSQL());
} }
appendOrderBy(builder, orderBy); appendOrderBy(builder, orderBy);
......
/*
* 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;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.h2.message.DbException;
import org.h2.value.Value;
/**
* Window frame clause.
*/
public final class WindowFrame {
/**
* Simple extent.
*/
public enum SimpleExtent {
/**
* RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW frame specification.
*/
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW("RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"),
/**
* RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING frame specification.
*/
RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING("RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING"),
/**
* RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING frame
* specification.
*/
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING(
"RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"),
;
private final String sql;
private SimpleExtent(String sql) {
this.sql = sql;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public String getSQL() {
return sql;
}
}
private final SimpleExtent extent;
/**
* Creates new instance of window frame clause.
*
* @param extent
* window frame extent
*/
public WindowFrame(SimpleExtent extent) {
this.extent = extent;
}
/**
* Returns whether window frame specification can be omitted.
*
* @return whether window frame specification can be omitted
*/
public boolean isDefault() {
return extent == SimpleExtent.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW;
}
/**
* Returns whether window frame specification contains all rows in
* partition.
*
* @return whether window frame specification contains all rows in partition
*/
public boolean isFullPartition() {
return extent == SimpleExtent.RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING;
}
/**
* Returns iterator.
*
* @param orderedRows
* ordered rows
* @param currentRow
* index of the current row
* @return iterator
*/
public Iterator<Value[]> iterator(final ArrayList<Value[]> orderedRows, int currentRow) {
int size = orderedRows.size();
final int startIndex, endIndex;
switch (extent) {
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW:
startIndex = 0;
endIndex = currentRow;
break;
case RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING:
startIndex = currentRow;
endIndex = size - 1;
break;
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING:
startIndex = 0;
endIndex = size - 1;
break;
default:
throw DbException.getUnsupportedException("window frame extent =" + extent);
}
return new Iterator<Value[]>() {
private int cursor = startIndex;
@Override
public boolean hasNext() {
return cursor <= endIndex;
}
@Override
public Value[] next() {
if (cursor > endIndex) {
throw new NoSuchElementException();
}
return orderedRows.get(cursor++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Returns iterator in descending order.
*
* @param orderedRows
* ordered rows
* @param currentRow
* index of the current row
* @return iterator in descending order
*/
public Iterator<Value[]> reverseIterator(final ArrayList<Value[]> orderedRows, int currentRow) {
int size = orderedRows.size();
final int startIndex, endIndex;
switch (extent) {
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW:
startIndex = 0;
endIndex = currentRow;
break;
case RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING:
startIndex = currentRow;
endIndex = size - 1;
break;
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING:
startIndex = 0;
endIndex = size - 1;
break;
default:
throw DbException.getUnsupportedException("window frame extent =" + extent);
}
return new Iterator<Value[]>() {
private int cursor = endIndex;
@Override
public boolean hasNext() {
return cursor >= startIndex;
}
@Override
public Value[] next() {
if (cursor < startIndex) {
throw new NoSuchElementException();
}
return orderedRows.get(cursor--);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public String getSQL() {
return extent.getSQL();
}
}
...@@ -7,6 +7,7 @@ package org.h2.expression.aggregate; ...@@ -7,6 +7,7 @@ package org.h2.expression.aggregate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import org.h2.command.dml.Select; import org.h2.command.dml.Select;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -130,37 +131,18 @@ public class WindowFunction extends AbstractAggregate { ...@@ -130,37 +131,18 @@ public class WindowFunction extends AbstractAggregate {
} }
} }
private static Value getNthValue(ArrayList<Value[]> ordered, int startIndex, int endIndex, int number, private static Value getNthValue(Iterator<Value[]> iterator, int number, boolean ignoreNulls) {
boolean fromLast, boolean ignoreNulls) {
return ignoreNulls ? getNthValueIgnoreNulls(ordered, startIndex, endIndex, number, fromLast)
: ordered.get(fromLast ? endIndex - number : startIndex + number)[0];
}
private static Value getNthValueIgnoreNulls(ArrayList<Value[]> ordered, int startIndex, int endIndex, int number,
boolean fromLast) {
Value v = ValueNull.INSTANCE; Value v = ValueNull.INSTANCE;
int cnt = 0; int cnt = 0;
if (fromLast) { while (iterator.hasNext()) {
for (int i = endIndex; i >= startIndex; i--) { Value t = iterator.next()[0];
Value t = ordered.get(i)[0]; if (!ignoreNulls || t != ValueNull.INSTANCE) {
if (t != ValueNull.INSTANCE) {
if (cnt++ == number) {
v = t;
break;
}
}
}
} else {
for (int i = startIndex; i <= endIndex; i++) {
Value t = ordered.get(i)[0];
if (t != ValueNull.INSTANCE) {
if (cnt++ == number) { if (cnt++ == number) {
v = t; v = t;
break; break;
} }
} }
} }
}
return v; return v;
} }
...@@ -333,33 +315,17 @@ public class WindowFunction extends AbstractAggregate { ...@@ -333,33 +315,17 @@ public class WindowFunction extends AbstractAggregate {
private void getNth(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered, int rowIdColumn) { private void getNth(Session session, HashMap<Integer, Value> result, ArrayList<Value[]> ordered, int rowIdColumn) {
int size = ordered.size(); int size = ordered.size();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
int startIndex, endIndex; WindowFrame frame = over.getWindowFrame();
switch (over.getWindowFrame()) {
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW:
startIndex = 0;
endIndex = i;
break;
case RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING:
startIndex = i;
endIndex = size - 1;
break;
case RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING:
startIndex = 0;
endIndex = size - 1;
break;
default:
throw DbException.getUnsupportedException("window frame=" + over.getWindowFrame());
}
Value[] row = ordered.get(i); Value[] row = ordered.get(i);
int rowId = row[rowIdColumn].getInt(); int rowId = row[rowIdColumn].getInt();
Value v; Value v;
switch (type) { switch (type) {
case FIRST_VALUE: { case FIRST_VALUE: {
v = getNthValue(ordered, startIndex, endIndex, 0, false, ignoreNulls); v = getNthValue(frame.iterator(ordered, i), 0, ignoreNulls);
break; break;
} }
case LAST_VALUE: case LAST_VALUE:
v = getNthValue(ordered, startIndex, endIndex, 0, true, ignoreNulls); v = getNthValue(frame.reverseIterator(ordered, i), 0, ignoreNulls);
break; break;
case NTH_VALUE: { case NTH_VALUE: {
int n = row[1].getInt(); int n = row[1].getInt();
...@@ -367,11 +333,8 @@ public class WindowFunction extends AbstractAggregate { ...@@ -367,11 +333,8 @@ public class WindowFunction extends AbstractAggregate {
throw DbException.getInvalidValueException("nth row", n); throw DbException.getInvalidValueException("nth row", n);
} }
n--; n--;
if (n > endIndex - startIndex) { Iterator<Value[]> iter = fromLast ? frame.reverseIterator(ordered, i) : frame.iterator(ordered, i);
v = ValueNull.INSTANCE; v = getNthValue(iter, n, ignoreNulls);
} else {
v = getNthValue(ordered, startIndex, endIndex, n, fromLast, ignoreNulls);
}
break; break;
} }
default: default:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论