Unverified 提交 8949f340 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1447 from katzyn/aggregate

Refactor OVER() processing code and fix some issues
...@@ -276,8 +276,9 @@ public abstract class Query extends Prepared { ...@@ -276,8 +276,9 @@ public abstract class Query extends Prepared {
* Update all aggregate function values. * Update all aggregate function values.
* *
* @param s the session * @param s the session
* @param window true for window processing stage, false for group stage
*/ */
public abstract void updateAggregate(Session s); public abstract void updateAggregate(Session s, boolean window);
/** /**
* Call the before triggers on all tables. * Call the before triggers on all tables.
......
...@@ -8,7 +8,6 @@ package org.h2.command.dml; ...@@ -8,7 +8,6 @@ package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.Trigger; import org.h2.api.Trigger;
...@@ -105,7 +104,8 @@ public class Select extends Query { ...@@ -105,7 +104,8 @@ public class Select extends Query {
SelectGroups groupData; SelectGroups groupData;
private int havingIndex; private int havingIndex;
private boolean isGroupQuery, isGroupSortedQuery; boolean isGroupQuery;
private boolean isGroupSortedQuery;
private boolean isWindowQuery; private boolean isWindowQuery;
private boolean isForUpdate, isForUpdateMvcc; private boolean isForUpdate, isForUpdateMvcc;
private double cost; private double cost;
...@@ -177,8 +177,8 @@ public class Select extends Query { ...@@ -177,8 +177,8 @@ public class Select extends Query {
return group; return group;
} }
public SelectGroups getGroupDataIfCurrent(boolean forAggregate) { public SelectGroups getGroupDataIfCurrent(boolean window) {
return groupData != null && (forAggregate || !isWindowQuery) && groupData.isCurrentGroup() ? groupData : null; return groupData != null && (window || groupData.isCurrentGroup()) ? groupData : null;
} }
@Override @Override
...@@ -357,10 +357,9 @@ public class Select extends Query { ...@@ -357,10 +357,9 @@ public class Select extends Query {
private void queryWindow(int columnCount, LocalResult result, long offset, boolean quickOffset) { private void queryWindow(int columnCount, LocalResult result, long offset, boolean quickOffset) {
if (groupData == null) { if (groupData == null) {
groupData = new SelectGroups(session, expressions, groupIndex); groupData = SelectGroups.getInstance(session, expressions, isGroupQuery, groupIndex);
} }
groupData.reset(); groupData.reset();
HashMap<ValueArray, ArrayList<Row>> rows = new HashMap<>();
try { try {
int rowNumber = 0; int rowNumber = 0;
setCurrentRowNumber(0); setCurrentRowNumber(0);
...@@ -369,14 +368,8 @@ public class Select extends Query { ...@@ -369,14 +368,8 @@ public class Select extends Query {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
if (isConditionMet()) { if (isConditionMet()) {
rowNumber++; rowNumber++;
ValueArray key = groupData.nextSource(); groupData.nextSource();
ArrayList<Row> groupRows = rows.get(key); updateAgg(columnCount, true);
if (groupRows == null) {
groupRows = Utils.newSmallArrayList();
rows.put(key, groupRows);
}
groupRows.add(topTableFilter.get());
updateAgg(columnCount);
if (sampleSize > 0 && rowNumber >= sampleSize) { if (sampleSize > 0 && rowNumber >= sampleSize) {
break; break;
} }
...@@ -384,10 +377,7 @@ public class Select extends Query { ...@@ -384,10 +377,7 @@ public class Select extends Query {
} }
groupData.done(); groupData.done();
for (ValueArray currentGroupsKey; (currentGroupsKey = groupData.next()) != null;) { for (ValueArray currentGroupsKey; (currentGroupsKey = groupData.next()) != null;) {
for (Row originalRow : rows.get(currentGroupsKey)) { offset = processGroupedRow(columnCount, result, offset, quickOffset, currentGroupsKey);
topTableFilter.set(originalRow);
offset = processGroupedRow(columnCount, result, offset, quickOffset, currentGroupsKey);
}
} }
} finally { } finally {
groupData.reset(); groupData.reset();
...@@ -396,7 +386,7 @@ public class Select extends Query { ...@@ -396,7 +386,7 @@ public class Select extends Query {
private void queryGroup(int columnCount, LocalResult result, long offset, boolean quickOffset) { private void queryGroup(int columnCount, LocalResult result, long offset, boolean quickOffset) {
if (groupData == null) { if (groupData == null) {
groupData = new SelectGroups(session, expressions, groupIndex); groupData = SelectGroups.getInstance(session, expressions, isGroupQuery, groupIndex);
} }
groupData.reset(); groupData.reset();
try { try {
...@@ -408,7 +398,7 @@ public class Select extends Query { ...@@ -408,7 +398,7 @@ public class Select extends Query {
if (isConditionMet()) { if (isConditionMet()) {
rowNumber++; rowNumber++;
groupData.nextSource(); groupData.nextSource();
updateAgg(columnCount); updateAgg(columnCount, false);
if (sampleSize > 0 && rowNumber >= sampleSize) { if (sampleSize > 0 && rowNumber >= sampleSize) {
break; break;
} }
...@@ -423,11 +413,11 @@ public class Select extends Query { ...@@ -423,11 +413,11 @@ public class Select extends Query {
} }
} }
private void updateAgg(int columnCount) { private void updateAgg(int columnCount, boolean window) {
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
if (groupByExpression == null || !groupByExpression[i]) { if (groupByExpression == null || !groupByExpression[i]) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
expr.updateAggregate(session); expr.updateAggregate(session, window);
} }
} }
} }
...@@ -1492,15 +1482,15 @@ public class Select extends Query { ...@@ -1492,15 +1482,15 @@ public class Select extends Query {
} }
@Override @Override
public void updateAggregate(Session s) { public void updateAggregate(Session s, boolean window) {
for (Expression e : expressions) { for (Expression e : expressions) {
e.updateAggregate(s); e.updateAggregate(s, window);
} }
if (condition != null) { if (condition != null) {
condition.updateAggregate(s); condition.updateAggregate(s, window);
} }
if (having != null) { if (having != null) {
having.updateAggregate(s); having.updateAggregate(s, window);
} }
} }
...@@ -1654,7 +1644,7 @@ public class Select extends Query { ...@@ -1654,7 +1644,7 @@ public class Select extends Query {
LazyResultGroupSorted(Expression[] expressions, int columnCount) { LazyResultGroupSorted(Expression[] expressions, int columnCount) {
super(expressions, columnCount); super(expressions, columnCount);
if (groupData == null) { if (groupData == null) {
groupData = new SelectGroups(getSession(), Select.this.expressions, groupIndex); groupData = SelectGroups.getInstance(getSession(), Select.this.expressions, isGroupQuery, groupIndex);
} else { } else {
// TODO is this branch possible? // TODO is this branch possible?
groupData.resetLazy(); groupData.resetLazy();
...@@ -1696,7 +1686,7 @@ public class Select extends Query { ...@@ -1696,7 +1686,7 @@ public class Select extends Query {
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
if (groupByExpression == null || !groupByExpression[i]) { if (groupByExpression == null || !groupByExpression[i]) {
Expression expr = expressions.get(i); Expression expr = expressions.get(i);
expr.updateAggregate(getSession()); expr.updateAggregate(getSession(), false);
} }
} }
if (row != null) { if (row != null) {
......
...@@ -24,7 +24,7 @@ import org.h2.value.ValueArray; ...@@ -24,7 +24,7 @@ import org.h2.value.ValueArray;
* Call sequence: * Call sequence:
* </p> * </p>
* <ul> * <ul>
* <li>{@link #reset()} (not required before the first execution).</li> * <li>{@link #reset()}.</li>
* <li>For each source row {@link #nextSource()} should be invoked.</li> * <li>For each source row {@link #nextSource()} should be invoked.</li>
* <li>{@link #done()}.</li> * <li>{@link #done()}.</li>
* <li>{@link #next()} is invoked inside a loop until it returns null.</li> * <li>{@link #next()} is invoked inside a loop until it returns null.</li>
...@@ -39,51 +39,179 @@ import org.h2.value.ValueArray; ...@@ -39,51 +39,179 @@ import org.h2.value.ValueArray;
* can have one or more rows.</li> * can have one or more rows.</li>
* </ul> * </ul>
*/ */
public final class SelectGroups { public abstract class SelectGroups {
private final Session session; private static final class Grouped extends SelectGroups {
private final ArrayList<Expression> expressions; private final int[] groupIndex;
private final int[] groupIndex; /**
* Map of group-by key to group-by expression data e.g. AggregateData
*/
private HashMap<ValueArray, Object[]> groupByData;
/**
* Key into groupByData that produces currentGroupByExprData. Not used
* in lazy mode.
*/
private ValueArray currentGroupsKey;
/**
* Cursor for {@link #next()} method.
*/
private Iterator<Entry<ValueArray, Object[]>> cursor;
/**
* The key for the default group.
*/
// Can be static, but TestClearReferences complains about it
private final ValueArray defaultGroup = ValueArray.get(new Value[0]);
Grouped(Session session, ArrayList<Expression> expressions, int[] groupIndex) {
super(session, expressions);
this.groupIndex = groupIndex;
}
@Override
public void reset() {
super.reset();
groupByData = new HashMap<>();
currentGroupsKey = null;
cursor = null;
}
@Override
public void nextSource() {
if (groupIndex == null) {
currentGroupsKey = defaultGroup;
} else {
Value[] keyValues = new Value[groupIndex.length];
// update group
for (int i = 0; i < groupIndex.length; i++) {
int idx = groupIndex[i];
Expression expr = expressions.get(idx);
keyValues[i] = expr.getValue(session);
}
currentGroupsKey = ValueArray.get(keyValues);
}
Object[] values = groupByData.get(currentGroupsKey);
if (values == null) {
values = new Object[Math.max(exprToIndexInGroupByData.size(), expressions.size())];
groupByData.put(currentGroupsKey, values);
}
currentGroupByExprData = values;
currentGroupRowId++;
}
@Override
void updateCurrentGroupExprData() {
// this can be null in lazy mode
if (currentGroupsKey != null) {
// since we changed the size of the array, update the object in
// the groups map
groupByData.put(currentGroupsKey, currentGroupByExprData);
}
}
@Override
public void done() {
if (groupIndex == null && groupByData.size() == 0) {
groupByData.put(defaultGroup,
new Object[Math.max(exprToIndexInGroupByData.size(), expressions.size())]);
}
cursor = groupByData.entrySet().iterator();
}
@Override
public ValueArray next() {
if (cursor.hasNext()) {
Map.Entry<ValueArray, Object[]> entry = cursor.next();
currentGroupByExprData = entry.getValue();
return entry.getKey();
}
return null;
}
@Override
public void resetLazy() {
super.resetLazy();
currentGroupsKey = null;
}
}
private static final class Plain extends SelectGroups {
private ArrayList<Object[]> rows;
/**
* Cursor for {@link #next()} method.
*/
private Iterator<Object[]> cursor;
Plain(Session session, ArrayList<Expression> expressions) {
super(session, expressions);
}
@Override
public void reset() {
super.reset();
rows = new ArrayList<>();
cursor = null;
}
@Override
public void nextSource() {
Object[] values = new Object[Math.max(exprToIndexInGroupByData.size(), expressions.size())];
rows.add(values);
currentGroupByExprData = values;
currentGroupRowId++;
}
@Override
void updateCurrentGroupExprData() {
rows.set(rows.size() - 1, currentGroupByExprData);
}
@Override
public void done() {
cursor = rows.iterator();
}
@Override
public ValueArray next() {
if (cursor.hasNext()) {
Object[] values = cursor.next();
currentGroupByExprData = values;
return ValueArray.get(new Value[0]);
}
return null;
}
}
final Session session;
final ArrayList<Expression> expressions;
/** /**
* The array of current group-by expression data e.g. AggregateData. * The array of current group-by expression data e.g. AggregateData.
*/ */
private Object[] currentGroupByExprData; Object[] currentGroupByExprData;
/** /**
* Maps an expression object to an index, to use in accessing the Object[] * Maps an expression object to an index, to use in accessing the Object[]
* pointed to by groupByData. * pointed to by groupByData.
*/ */
private final HashMap<Expression, Integer> exprToIndexInGroupByData = new HashMap<>(); final HashMap<Expression, Integer> exprToIndexInGroupByData = new HashMap<>();
/** /**
* Map of group-by key to group-by expression data e.g. AggregateData * Maps an expression object to its data.
*/ */
private HashMap<ValueArray, Object[]> groupByData; private final HashMap<Expression, Object> windowData = new HashMap<>();
/**
* Key into groupByData that produces currentGroupByExprData. Not used in
* lazy mode.
*/
private ValueArray currentGroupsKey;
/** /**
* The id of the current group. * The id of the current group.
*/ */
private int currentGroupRowId; int currentGroupRowId;
/**
* The key for the default group.
*/
// Can be static, but TestClearReferences complains about it
private ValueArray defaultGroup = ValueArray.get(new Value[0]);
/**
* Cursor for {@link #next()} method.
*/
private Iterator<Entry<ValueArray, Object[]>> cursor;
/** /**
* Creates new instance of grouped data. * Creates new instance of grouped data.
...@@ -92,13 +220,19 @@ public final class SelectGroups { ...@@ -92,13 +220,19 @@ public final class SelectGroups {
* the session * the session
* @param expressions * @param expressions
* the expressions * the expressions
* @param isGroupQuery
* is this query is a group query
* @param groupIndex * @param groupIndex
* the indexes of group expressions, or null * the indexes of group expressions, or null
*/ */
public SelectGroups(Session session, ArrayList<Expression> expressions, int[] groupIndex) { public static SelectGroups getInstance(Session session, ArrayList<Expression> expressions, boolean isGroupQuery,
int[] groupIndex) {
return isGroupQuery ? new Grouped(session, expressions, groupIndex) : new Plain(session, expressions);
}
SelectGroups(Session session, ArrayList<Expression> expressions) {
this.session = session; this.session = session;
this.expressions = expressions; this.expressions = expressions;
this.groupIndex = groupIndex;
} }
/** /**
...@@ -110,8 +244,17 @@ public final class SelectGroups { ...@@ -110,8 +244,17 @@ public final class SelectGroups {
/** /**
* Get the group-by data for the current group and the passed in expression. * Get the group-by data for the current group and the passed in expression.
*
* @param expr
* expression
* @param window
* true if expression is a window expression
* @return expression data or null
*/ */
public Object getCurrentGroupExprData(Expression expr) { public Object getCurrentGroupExprData(Expression expr, boolean window) {
if (window) {
return windowData.get(expr);
}
Integer index = exprToIndexInGroupByData.get(expr); Integer index = exprToIndexInGroupByData.get(expr);
if (index == null) { if (index == null) {
return null; return null;
...@@ -121,8 +264,20 @@ public final class SelectGroups { ...@@ -121,8 +264,20 @@ public final class SelectGroups {
/** /**
* Set the group-by data for the current group and the passed in expression. * Set the group-by data for the current group and the passed in expression.
*
* @param expr
* expression
* @param object
* expression data to set
* @param window
* true if expression is a window expression
*/ */
public void setCurrentGroupExprData(Expression expr, Object obj) { public void setCurrentGroupExprData(Expression expr, Object obj, boolean window) {
if (window) {
Object old = windowData.put(expr, obj);
assert old == null;
return;
}
Integer index = exprToIndexInGroupByData.get(expr); Integer index = exprToIndexInGroupByData.get(expr);
if (index != null) { if (index != null) {
assert currentGroupByExprData[index] == null; assert currentGroupByExprData[index] == null;
...@@ -133,16 +288,13 @@ public final class SelectGroups { ...@@ -133,16 +288,13 @@ public final class SelectGroups {
exprToIndexInGroupByData.put(expr, index); exprToIndexInGroupByData.put(expr, index);
if (index >= currentGroupByExprData.length) { if (index >= currentGroupByExprData.length) {
currentGroupByExprData = Arrays.copyOf(currentGroupByExprData, currentGroupByExprData.length * 2); currentGroupByExprData = Arrays.copyOf(currentGroupByExprData, currentGroupByExprData.length * 2);
// this can be null in lazy mode updateCurrentGroupExprData();
if (currentGroupsKey != null) {
// since we changed the size of the array, update the object in
// the groups map
groupByData.put(currentGroupsKey, currentGroupByExprData);
}
} }
currentGroupByExprData[index] = obj; currentGroupByExprData[index] = obj;
} }
abstract void updateCurrentGroupExprData();
/** /**
* Returns identity of the current row. Used by aggregates to check whether * Returns identity of the current row. Used by aggregates to check whether
* they already processed this row or not. * they already processed this row or not.
...@@ -157,72 +309,34 @@ public final class SelectGroups { ...@@ -157,72 +309,34 @@ public final class SelectGroups {
* Resets this group data for reuse. * Resets this group data for reuse.
*/ */
public void reset() { public void reset() {
groupByData = new HashMap<>();
currentGroupByExprData = null; currentGroupByExprData = null;
currentGroupsKey = null;
exprToIndexInGroupByData.clear(); exprToIndexInGroupByData.clear();
cursor = null; windowData.clear();
} }
/** /**
* Invoked for each source row to evaluate group key and setup all necessary * Invoked for each source row to evaluate group key and setup all necessary
* data for aggregates. * data for aggregates.
* */
* @return key of the current group public abstract void nextSource();
*/
public ValueArray nextSource() {
if (groupIndex == null) {
currentGroupsKey = defaultGroup;
} else {
Value[] keyValues = new Value[groupIndex.length];
// update group
for (int i = 0; i < groupIndex.length; i++) {
int idx = groupIndex[i];
Expression expr = expressions.get(idx);
keyValues[i] = expr.getValue(session);
}
currentGroupsKey = ValueArray.get(keyValues);
}
Object[] values = groupByData.get(currentGroupsKey);
if (values == null) {
values = new Object[Math.max(exprToIndexInGroupByData.size(), expressions.size())];
groupByData.put(currentGroupsKey, values);
}
currentGroupByExprData = values;
currentGroupRowId++;
return currentGroupsKey;
}
/** /**
* Invoked after all source rows are evaluated. * Invoked after all source rows are evaluated.
*/ */
public void done() { public abstract void done();
if (groupIndex == null && groupByData.size() == 0) {
groupByData.put(defaultGroup, new Object[Math.max(exprToIndexInGroupByData.size(), expressions.size())]);
}
cursor = groupByData.entrySet().iterator();
}
/** /**
* Returns the key of the next group. * Returns the key of the next group.
* *
* @return the key of the next group, or null * @return the key of the next group, or null
*/ */
public ValueArray next() { public abstract ValueArray next();
if (cursor.hasNext()) {
Map.Entry<ValueArray, Object[]> entry = cursor.next();
currentGroupByExprData = entry.getValue();
return entry.getKey();
}
return null;
}
/** /**
* Resets this group data for reuse in lazy mode. * Resets this group data for reuse in lazy mode.
*/ */
public void resetLazy() { public void resetLazy() {
currentGroupByExprData = null; currentGroupByExprData = null;
currentGroupsKey = null;
} }
/** /**
......
...@@ -449,9 +449,9 @@ public class SelectUnion extends Query { ...@@ -449,9 +449,9 @@ public class SelectUnion extends Query {
} }
@Override @Override
public void updateAggregate(Session s) { public void updateAggregate(Session s, boolean window) {
left.updateAggregate(s); left.updateAggregate(s, window);
right.updateAggregate(s); right.updateAggregate(s, window);
} }
@Override @Override
......
...@@ -83,8 +83,8 @@ public class Alias extends Expression { ...@@ -83,8 +83,8 @@ public class Alias extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
expr.updateAggregate(session); expr.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -436,9 +436,9 @@ public class BinaryOperation extends Expression { ...@@ -436,9 +436,9 @@ public class BinaryOperation extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
right.updateAggregate(session); right.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -495,11 +495,11 @@ public class CompareLike extends Condition { ...@@ -495,11 +495,11 @@ public class CompareLike extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
right.updateAggregate(session); right.updateAggregate(session, window);
if (escape != null) { if (escape != null) {
escape.updateAggregate(session); escape.updateAggregate(session, window);
} }
} }
......
...@@ -475,10 +475,10 @@ public class Comparison extends Condition { ...@@ -475,10 +475,10 @@ public class Comparison extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
if (right != null) { if (right != null) {
right.updateAggregate(session); right.updateAggregate(session, window);
} }
} }
......
...@@ -268,9 +268,9 @@ public class ConditionAndOr extends Condition { ...@@ -268,9 +268,9 @@ public class ConditionAndOr extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
right.updateAggregate(session); right.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -46,7 +46,7 @@ public class ConditionExists extends Condition { ...@@ -46,7 +46,7 @@ public class ConditionExists extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
// TODO exists: is it allowed that the subquery contains aggregates? // TODO exists: is it allowed that the subquery contains aggregates?
// probably not // probably not
// select id from test group by id having exists (select * from test2 // select id from test group by id having exists (select * from test2
......
...@@ -163,10 +163,10 @@ public class ConditionIn extends Condition { ...@@ -163,10 +163,10 @@ public class ConditionIn extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
for (Expression e : valueList) { for (Expression e : valueList) {
e.updateAggregate(session); e.updateAggregate(session, window);
} }
} }
......
...@@ -125,8 +125,8 @@ public class ConditionInConstantSet extends Condition { ...@@ -125,8 +125,8 @@ public class ConditionInConstantSet extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -145,8 +145,8 @@ public class ConditionInParameter extends Condition { ...@@ -145,8 +145,8 @@ public class ConditionInParameter extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -146,9 +146,9 @@ public class ConditionInSelect extends Condition { ...@@ -146,9 +146,9 @@ public class ConditionInSelect extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
query.updateAggregate(session); query.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -70,8 +70,8 @@ public class ConditionNot extends Condition { ...@@ -70,8 +70,8 @@ public class ConditionNot extends Condition {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
condition.updateAggregate(session); condition.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -105,8 +105,9 @@ public abstract class Expression { ...@@ -105,8 +105,9 @@ public abstract class Expression {
* be used to make sure the internal state is only updated once. * be used to make sure the internal state is only updated once.
* *
* @param session the session * @param session the session
* @param window true for window processing stage, false for group stage
*/ */
public abstract void updateAggregate(Session session); public abstract void updateAggregate(Session session, boolean window);
/** /**
* Check if this expression and all sub-expressions can fulfill a criteria. * Check if this expression and all sub-expressions can fulfill a criteria.
......
...@@ -153,7 +153,7 @@ public class ExpressionColumn extends Expression { ...@@ -153,7 +153,7 @@ public class ExpressionColumn extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
Value now = columnResolver.getValue(column); Value now = columnResolver.getValue(column);
Select select = columnResolver.getSelect(); Select select = columnResolver.getSelect();
if (select == null) { if (select == null) {
...@@ -164,9 +164,9 @@ public class ExpressionColumn extends Expression { ...@@ -164,9 +164,9 @@ public class ExpressionColumn extends Expression {
// this is a different level (the enclosing query) // this is a different level (the enclosing query)
return; return;
} }
Value v = (Value) groupData.getCurrentGroupExprData(this); Value v = (Value) groupData.getCurrentGroupExprData(this, false);
if (v == null) { if (v == null) {
groupData.setCurrentGroupExprData(this, now); groupData.setCurrentGroupExprData(this, now, false);
} else { } else {
if (!database.areEqual(now, v)) { if (!database.areEqual(now, v)) {
throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL()); throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
...@@ -180,7 +180,7 @@ public class ExpressionColumn extends Expression { ...@@ -180,7 +180,7 @@ public class ExpressionColumn extends Expression {
if (select != null) { if (select != null) {
SelectGroups groupData = select.getGroupDataIfCurrent(false); SelectGroups groupData = select.getGroupDataIfCurrent(false);
if (groupData != null) { if (groupData != null) {
Value v = (Value) groupData.getCurrentGroupExprData(this); Value v = (Value) groupData.getCurrentGroupExprData(this, false);
if (v != null) { if (v != null) {
return v; return v;
} }
......
...@@ -98,9 +98,9 @@ public class ExpressionList extends Expression { ...@@ -98,9 +98,9 @@ public class ExpressionList extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
for (Expression e : list) { for (Expression e : list) {
e.updateAggregate(session); e.updateAggregate(session, window);
} }
} }
......
...@@ -2633,10 +2633,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -2633,10 +2633,10 @@ public class Function extends Expression implements FunctionCall {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
for (Expression e : args) { for (Expression e : args) {
if (e != null) { if (e != null) {
e.updateAggregate(session); e.updateAggregate(session, window);
} }
} }
} }
......
...@@ -291,9 +291,9 @@ public class IntervalOperation extends Expression { ...@@ -291,9 +291,9 @@ public class IntervalOperation extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
left.updateAggregate(session); left.updateAggregate(session, window);
right.updateAggregate(session); right.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -107,10 +107,10 @@ public class JavaFunction extends Expression implements FunctionCall { ...@@ -107,10 +107,10 @@ public class JavaFunction extends Expression implements FunctionCall {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
for (Expression e : args) { for (Expression e : args) {
if (e != null) { if (e != null) {
e.updateAggregate(session); e.updateAggregate(session, window);
} }
} }
} }
......
...@@ -141,7 +141,7 @@ public class Parameter extends Expression implements ParameterInterface { ...@@ -141,7 +141,7 @@ public class Parameter extends Expression implements ParameterInterface {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
// nothing to do // nothing to do
} }
......
...@@ -73,7 +73,7 @@ public class Rownum extends Expression { ...@@ -73,7 +73,7 @@ public class Rownum extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
// nothing to do // nothing to do
} }
......
...@@ -72,7 +72,7 @@ public class SequenceValue extends Expression { ...@@ -72,7 +72,7 @@ public class SequenceValue extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
// nothing to do // nothing to do
} }
......
...@@ -94,8 +94,8 @@ public class Subquery extends Expression { ...@@ -94,8 +94,8 @@ public class Subquery extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
query.updateAggregate(session); query.updateAggregate(session, window);
} }
private Expression getExpression() { private Expression getExpression() {
......
...@@ -82,8 +82,8 @@ public class UnaryOperation extends Expression { ...@@ -82,8 +82,8 @@ public class UnaryOperation extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
arg.updateAggregate(session); arg.updateAggregate(session, window);
} }
@Override @Override
......
...@@ -143,7 +143,7 @@ public class ValueExpression extends Expression { ...@@ -143,7 +143,7 @@ public class ValueExpression extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
// nothing to do // nothing to do
} }
......
...@@ -101,7 +101,7 @@ public class Variable extends Expression { ...@@ -101,7 +101,7 @@ public class Variable extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
// nothing to do // nothing to do
} }
......
...@@ -91,7 +91,7 @@ public class Wildcard extends Expression { ...@@ -91,7 +91,7 @@ public class Wildcard extends Expression {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
DbException.throwInternalError(toString()); DbException.throwInternalError(toString());
} }
......
...@@ -7,6 +7,7 @@ package org.h2.expression.aggregate; ...@@ -7,6 +7,7 @@ package org.h2.expression.aggregate;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
/** /**
* A base class for aggregates. * A base class for aggregates.
...@@ -47,4 +48,24 @@ public abstract class AbstractAggregate extends Expression { ...@@ -47,4 +48,24 @@ public abstract class AbstractAggregate extends Expression {
} }
} }
@Override
public void setEvaluatable(TableFilter tableFilter, boolean b) {
if (filterCondition != null) {
filterCondition.setEvaluatable(tableFilter, b);
}
if (over != null) {
over.setEvaluatable(tableFilter, b);
}
}
protected StringBuilder appendTailConditions(StringBuilder builder) {
if (filterCondition != null) {
builder.append(" FILTER (WHERE ").append(filterCondition.getSQL()).append(')');
}
if (over != null) {
builder.append(' ').append(over.getSQL());
}
return builder;
}
} }
...@@ -170,10 +170,14 @@ public class Aggregate extends AbstractAggregate { ...@@ -170,10 +170,14 @@ public class Aggregate extends AbstractAggregate {
/** /**
* Create a new aggregate object. * Create a new aggregate object.
* *
* @param type the aggregate type * @param type
* @param on the aggregated expression * the aggregate type
* @param select the select statement * @param on
* @param distinct if distinct is used * the aggregated expression
* @param select
* the select statement
* @param distinct
* if distinct is used
*/ */
public Aggregate(AggregateType type, Expression on, Select select, boolean distinct) { public Aggregate(AggregateType type, Expression on, Select select, boolean distinct) {
this.type = type; this.type = type;
...@@ -229,8 +233,10 @@ public class Aggregate extends AbstractAggregate { ...@@ -229,8 +233,10 @@ public class Aggregate extends AbstractAggregate {
* Get the aggregate type for this name, or -1 if no aggregate has been * Get the aggregate type for this name, or -1 if no aggregate has been
* found. * found.
* *
* @param name the aggregate function name * @param name
* @return null if no aggregate function has been found, or the aggregate type * the aggregate function name
* @return null if no aggregate function has been found, or the aggregate
* type
*/ */
public static AggregateType getAggregateType(String name) { public static AggregateType getAggregateType(String name) {
return AGGREGATES.get(name); return AGGREGATES.get(name);
...@@ -239,7 +245,8 @@ public class Aggregate extends AbstractAggregate { ...@@ -239,7 +245,8 @@ public class Aggregate extends AbstractAggregate {
/** /**
* Set the order for ARRAY_AGG() or GROUP_CONCAT() aggregate. * Set the order for ARRAY_AGG() or GROUP_CONCAT() aggregate.
* *
* @param orderByList the order by list * @param orderByList
* the order by list
*/ */
public void setOrderByList(ArrayList<SelectOrderBy> orderByList) { public void setOrderByList(ArrayList<SelectOrderBy> orderByList) {
this.orderByList = orderByList; this.orderByList = orderByList;
...@@ -248,7 +255,8 @@ public class Aggregate extends AbstractAggregate { ...@@ -248,7 +255,8 @@ public class Aggregate extends AbstractAggregate {
/** /**
* Set the separator for the GROUP_CONCAT() aggregate. * Set the separator for the GROUP_CONCAT() aggregate.
* *
* @param separator the separator expression * @param separator
* the separator expression
*/ */
public void setGroupConcatSeparator(Expression separator) { public void setGroupConcatSeparator(Expression separator) {
this.groupConcatSeparator = separator; this.groupConcatSeparator = separator;
...@@ -281,12 +289,15 @@ public class Aggregate extends AbstractAggregate { ...@@ -281,12 +289,15 @@ public class Aggregate extends AbstractAggregate {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
if (window != (over != null)) {
return;
}
// TODO aggregates: check nested MIN(MAX(ID)) and so on // TODO aggregates: check nested MIN(MAX(ID)) and so on
// if (on != null) { // if (on != null) {
// on.updateAggregate(); // on.updateAggregate();
// } // }
SelectGroups groupData = select.getGroupDataIfCurrent(true); SelectGroups groupData = select.getGroupDataIfCurrent(window);
if (groupData == null) { if (groupData == null) {
// this is a different level (the enclosing query) // this is a different level (the enclosing query)
return; return;
...@@ -299,6 +310,9 @@ public class Aggregate extends AbstractAggregate { ...@@ -299,6 +310,9 @@ public class Aggregate extends AbstractAggregate {
} }
lastGroupRowId = groupRowId; lastGroupRowId = groupRowId;
if (over != null) {
over.updateAggregate(session, true);
}
if (filterCondition != null) { if (filterCondition != null) {
if (!filterCondition.getBooleanValue(session)) { if (!filterCondition.getBooleanValue(session)) {
return; return;
...@@ -366,7 +380,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -366,7 +380,7 @@ public class Aggregate extends AbstractAggregate {
DbException.throwInternalError("type=" + type); DbException.throwInternalError("type=" + type);
} }
} }
SelectGroups groupData = select.getGroupDataIfCurrent(true); SelectGroups groupData = select.getGroupDataIfCurrent(over != null);
if (groupData == null) { if (groupData == null) {
throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, getSQL()); throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, getSQL());
} }
...@@ -381,8 +395,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -381,8 +395,7 @@ public class Aggregate extends AbstractAggregate {
sortWithOrderBy(array); sortWithOrderBy(array);
} }
StatementBuilder buff = new StatementBuilder(); StatementBuilder buff = new StatementBuilder();
String sep = groupConcatSeparator == null ? String sep = groupConcatSeparator == null ? "," : groupConcatSeparator.getValue(session).getString();
"," : groupConcatSeparator.getValue(session).getString();
for (Value val : array) { for (Value val : array) {
String s; String s;
if (val.getType() == Value.ARRAY) { if (val.getType() == Value.ARRAY) {
...@@ -431,10 +444,11 @@ public class Aggregate extends AbstractAggregate { ...@@ -431,10 +444,11 @@ public class Aggregate extends AbstractAggregate {
ValueArray key; ValueArray key;
if (over != null && (key = over.getCurrentKey(session)) != null) { if (over != null && (key = over.getCurrentKey(session)) != null) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ValueHashMap<AggregateData> map = (ValueHashMap<AggregateData>) groupData.getCurrentGroupExprData(this); ValueHashMap<AggregateData> map = (ValueHashMap<AggregateData>) groupData.getCurrentGroupExprData(this,
true);
if (map == null) { if (map == null) {
map = new ValueHashMap<>(); map = new ValueHashMap<>();
groupData.setCurrentGroupExprData(this, map); groupData.setCurrentGroupExprData(this, map, true);
} }
data = map.get(key); data = map.get(key);
if (data == null) { if (data == null) {
...@@ -442,10 +456,10 @@ public class Aggregate extends AbstractAggregate { ...@@ -442,10 +456,10 @@ public class Aggregate extends AbstractAggregate {
map.put(key, data); map.put(key, data);
} }
} else { } else {
data = (AggregateData) groupData.getCurrentGroupExprData(this); data = (AggregateData) groupData.getCurrentGroupExprData(this, over != null);
if (data == null) { if (data == null) {
data = AggregateData.create(type); data = AggregateData.create(type);
groupData.setCurrentGroupExprData(this, data); groupData.setCurrentGroupExprData(this, data, over != null);
} }
} }
return data; return data;
...@@ -588,9 +602,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -588,9 +602,7 @@ public class Aggregate extends AbstractAggregate {
if (groupConcatSeparator != null) { if (groupConcatSeparator != null) {
groupConcatSeparator.setEvaluatable(tableFilter, b); groupConcatSeparator.setEvaluatable(tableFilter, b);
} }
if (filterCondition != null) { super.setEvaluatable(tableFilter, b);
filterCondition.setEvaluatable(tableFilter, b);
}
} }
@Override @Override
...@@ -626,13 +638,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -626,13 +638,7 @@ public class Aggregate extends AbstractAggregate {
buff.append(" SEPARATOR ").append(groupConcatSeparator.getSQL()); buff.append(" SEPARATOR ").append(groupConcatSeparator.getSQL());
} }
buff.append(')'); buff.append(')');
if (filterCondition != null) { return appendTailConditions(buff.builder()).toString();
buff.append(" FILTER (WHERE ").append(filterCondition.getSQL()).append(')');
}
if (over != null) {
buff.append(' ').append(over.getSQL());
}
return buff.toString();
} }
private String getSQLArrayAggregate() { private String getSQLArrayAggregate() {
...@@ -650,13 +656,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -650,13 +656,7 @@ public class Aggregate extends AbstractAggregate {
} }
} }
buff.append(')'); buff.append(')');
if (filterCondition != null) { return appendTailConditions(buff.builder()).toString();
buff.append(" FILTER (WHERE ").append(filterCondition.getSQL()).append(')');
}
if (over != null) {
buff.append(' ').append(over.getSQL());
}
return buff.toString();
} }
@Override @Override
...@@ -666,7 +666,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -666,7 +666,7 @@ public class Aggregate extends AbstractAggregate {
case GROUP_CONCAT: case GROUP_CONCAT:
return getSQLGroupConcat(); return getSQLGroupConcat();
case COUNT_ALL: case COUNT_ALL:
return "COUNT(*)"; return appendTailConditions(new StringBuilder().append("COUNT(*)")).toString();
case COUNT: case COUNT:
text = "COUNT"; text = "COUNT";
break; break;
...@@ -726,18 +726,13 @@ public class Aggregate extends AbstractAggregate { ...@@ -726,18 +726,13 @@ public class Aggregate extends AbstractAggregate {
default: default:
throw DbException.throwInternalError("type=" + type); throw DbException.throwInternalError("type=" + type);
} }
StringBuilder builder = new StringBuilder().append(text);
if (distinct) { if (distinct) {
text += "(DISTINCT " + on.getSQL() + ')'; builder.append("(DISTINCT ").append(on.getSQL()).append(')');
} else { } else {
text += StringUtils.enclose(on.getSQL()); builder.append(StringUtils.enclose(on.getSQL()));
}
if (filterCondition != null) {
text += " FILTER (WHERE " + filterCondition.getSQL() + ')';
}
if (over != null) {
text += ' ' + over.getSQL();
} }
return text; return appendTailConditions(builder).toString();
} }
private Index getMinMaxColumnIndex() { private Index getMinMaxColumnIndex() {
...@@ -785,8 +780,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -785,8 +780,7 @@ public class Aggregate extends AbstractAggregate {
if (on != null && !on.isEverything(visitor)) { if (on != null && !on.isEverything(visitor)) {
return false; return false;
} }
if (groupConcatSeparator != null && if (groupConcatSeparator != null && !groupConcatSeparator.isEverything(visitor)) {
!groupConcatSeparator.isEverything(visitor)) {
return false; return false;
} }
if (orderByList != null) { if (orderByList != null) {
......
...@@ -83,13 +83,7 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -83,13 +83,7 @@ public class JavaAggregate extends AbstractAggregate {
buff.append(e.getSQL()); buff.append(e.getSQL());
} }
buff.append(')'); buff.append(')');
if (filterCondition != null) { return appendTailConditions(buff.builder()).toString();
buff.append(" FILTER (WHERE ").append(filterCondition.getSQL()).append(')');
}
if (over != null) {
buff.append(' ').append(over.getSQL());
}
return buff.toString();
} }
@Override @Override
...@@ -155,9 +149,7 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -155,9 +149,7 @@ public class JavaAggregate extends AbstractAggregate {
for (Expression e : args) { for (Expression e : args) {
e.setEvaluatable(tableFilter, b); e.setEvaluatable(tableFilter, b);
} }
if (filterCondition != null) { super.setEvaluatable(tableFilter, b);
filterCondition.setEvaluatable(tableFilter, b);
}
} }
private Aggregate getInstance() throws SQLException { private Aggregate getInstance() throws SQLException {
...@@ -168,7 +160,7 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -168,7 +160,7 @@ public class JavaAggregate extends AbstractAggregate {
@Override @Override
public Value getValue(Session session) { public Value getValue(Session session) {
SelectGroups groupData = select.getGroupDataIfCurrent(true); SelectGroups groupData = select.getGroupDataIfCurrent(over != null);
if (groupData == null) { if (groupData == null) {
throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, getSQL()); throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, getSQL());
} }
...@@ -208,8 +200,11 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -208,8 +200,11 @@ public class JavaAggregate extends AbstractAggregate {
} }
@Override @Override
public void updateAggregate(Session session) { public void updateAggregate(Session session, boolean window) {
SelectGroups groupData = select.getGroupDataIfCurrent(true); if (window != (over != null)) {
return;
}
SelectGroups groupData = select.getGroupDataIfCurrent(window);
if (groupData == null) { if (groupData == null) {
// this is a different level (the enclosing query) // this is a different level (the enclosing query)
return; return;
...@@ -222,6 +217,9 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -222,6 +217,9 @@ public class JavaAggregate extends AbstractAggregate {
} }
lastGroupRowId = groupRowId; lastGroupRowId = groupRowId;
if (over != null) {
over.updateAggregate(session, true);
}
if (filterCondition != null) { if (filterCondition != null) {
if (!filterCondition.getBooleanValue(session)) { if (!filterCondition.getBooleanValue(session)) {
return; return;
...@@ -261,13 +259,13 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -261,13 +259,13 @@ public class JavaAggregate extends AbstractAggregate {
ValueArray key; ValueArray key;
if (over != null && (key = over.getCurrentKey(session)) != null) { if (over != null && (key = over.getCurrentKey(session)) != null) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ValueHashMap<Aggregate> map = (ValueHashMap<Aggregate>) groupData.getCurrentGroupExprData(this); ValueHashMap<Aggregate> map = (ValueHashMap<Aggregate>) groupData.getCurrentGroupExprData(this, true);
if (map == null) { if (map == null) {
if (ifExists) { if (ifExists) {
return null; return null;
} }
map = new ValueHashMap<>(); map = new ValueHashMap<>();
groupData.setCurrentGroupExprData(this, map); groupData.setCurrentGroupExprData(this, map, true);
} }
data = map.get(key); data = map.get(key);
if (data == null) { if (data == null) {
...@@ -278,13 +276,13 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -278,13 +276,13 @@ public class JavaAggregate extends AbstractAggregate {
map.put(key, data); map.put(key, data);
} }
} else { } else {
data = (Aggregate) groupData.getCurrentGroupExprData(this); data = (Aggregate) groupData.getCurrentGroupExprData(this, over != null);
if (data == null) { if (data == null) {
if (ifExists) { if (ifExists) {
return null; return null;
} }
data = getInstance(); data = getInstance();
groupData.setCurrentGroupExprData(this, data); groupData.setCurrentGroupExprData(this, data, over != null);
} }
} }
return data; return data;
...@@ -295,14 +293,14 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -295,14 +293,14 @@ public class JavaAggregate extends AbstractAggregate {
ValueArray key; ValueArray key;
if (over != null && (key = over.getCurrentKey(session)) != null) { if (over != null && (key = over.getCurrentKey(session)) != null) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ValueHashMap<AggregateDataCollecting> map = ValueHashMap<AggregateDataCollecting> map = (ValueHashMap<AggregateDataCollecting>) groupData
(ValueHashMap<AggregateDataCollecting>) groupData.getCurrentGroupExprData(this); .getCurrentGroupExprData(this, true);
if (map == null) { if (map == null) {
if (ifExists) { if (ifExists) {
return null; return null;
} }
map = new ValueHashMap<>(); map = new ValueHashMap<>();
groupData.setCurrentGroupExprData(this, map); groupData.setCurrentGroupExprData(this, map, true);
} }
data = map.get(key); data = map.get(key);
if (data == null) { if (data == null) {
...@@ -313,13 +311,13 @@ public class JavaAggregate extends AbstractAggregate { ...@@ -313,13 +311,13 @@ public class JavaAggregate extends AbstractAggregate {
map.put(key, data); map.put(key, data);
} }
} else { } else {
data = (AggregateDataCollecting) groupData.getCurrentGroupExprData(this); data = (AggregateDataCollecting) groupData.getCurrentGroupExprData(this, over != null);
if (data == null) { if (data == null) {
if (ifExists) { if (ifExists) {
return null; return null;
} }
data = new AggregateDataCollecting(); data = new AggregateDataCollecting();
groupData.setCurrentGroupExprData(this, data); groupData.setCurrentGroupExprData(this, data, over != null);
} }
} }
return data; return data;
......
...@@ -10,6 +10,7 @@ import java.util.ArrayList; ...@@ -10,6 +10,7 @@ import java.util.ArrayList;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
...@@ -38,6 +39,7 @@ public final class Window { ...@@ -38,6 +39,7 @@ public final class Window {
* the column resolver * the column resolver
* @param level * @param level
* the subquery nesting level * the subquery nesting level
* @see Expression#mapColumns(ColumnResolver, int)
*/ */
public void mapColumns(ColumnResolver resolver, int level) { public void mapColumns(ColumnResolver resolver, int level) {
if (partitionBy != null) { if (partitionBy != null) {
...@@ -47,6 +49,24 @@ public final class Window { ...@@ -47,6 +49,24 @@ public final class Window {
} }
} }
/**
* Tell the expression columns whether the table filter can return values
* now. This is used when optimizing the query.
*
* @param tableFilter
* the table filter
* @param value
* true if the table filter can return value
* @see Expression#setEvaluatable(TableFilter, boolean)
*/
public void setEvaluatable(TableFilter tableFilter, boolean value) {
if (partitionBy != null) {
for (Expression e : partitionBy) {
e.setEvaluatable(tableFilter, value);
}
}
}
/** /**
* Returns the key for the current group. * Returns the key for the current group.
* *
...@@ -72,6 +92,7 @@ public final class Window { ...@@ -72,6 +92,7 @@ public final class Window {
* Returns SQL representation. * Returns SQL representation.
* *
* @return SQL representation. * @return SQL representation.
* @see Expression#getSQL()
*/ */
public String getSQL() { public String getSQL() {
if (partitionBy == null) { if (partitionBy == null) {
...@@ -87,6 +108,22 @@ public final class Window { ...@@ -87,6 +108,22 @@ public final class Window {
return builder.append(')').toString(); return builder.append(')').toString();
} }
/**
* Update an aggregate value.
*
* @param session
* the session
* @param window true for window processing stage, false for group stage
* @see Expression#updateAggregate(Session, boolean)
*/
public void updateAggregate(Session session, boolean window) {
if (partitionBy != null) {
for (Expression expr : partitionBy) {
expr.updateAggregate(session, window);
}
}
}
@Override @Override
public String toString() { public String toString() {
return getSQL(); return getSQL();
......
...@@ -107,6 +107,17 @@ SELECT ARRAY_AGG(ID) OVER (PARTITION BY NAME), NAME FROM TEST; ...@@ -107,6 +107,17 @@ SELECT ARRAY_AGG(ID) OVER (PARTITION BY NAME), NAME FROM TEST;
> (4, 5, 6) c > (4, 5, 6) c
> rows: 6 > rows: 6
SELECT ARRAY_AGG(ID) FILTER (WHERE ID < 3 OR ID > 4) OVER (PARTITION BY NAME), NAME FROM TEST ORDER BY NAME;
> ARRAY_AGG(ID) FILTER (WHERE ((ID < 3) OR (ID > 4))) OVER (PARTITION BY NAME) NAME
> ---------------------------------------------------------------------------- ----
> (1, 2) a
> (1, 2) a
> null b
> (5, 6) c
> (5, 6) c
> (5, 6) c
> rows (ordered): 6
SELECT ARRAY_AGG(SUM(ID)) OVER () FROM TEST; SELECT ARRAY_AGG(SUM(ID)) OVER () FROM TEST;
> exception FEATURE_NOT_SUPPORTED_1 > exception FEATURE_NOT_SUPPORTED_1
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
create table test(v int); create table test(v int);
> ok > ok
insert into test values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12); insert into test values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (null);
> update count: 12 > update count: 13
select count(v), count(v) filter (where v >= 4) from test where v <= 10; select count(v), count(v) filter (where v >= 4) from test where v <= 10;
> COUNT(V) COUNT(V) FILTER (WHERE (V >= 4)) > COUNT(V) COUNT(V) FILTER (WHERE (V >= 4))
...@@ -17,6 +17,19 @@ select count(v), count(v) filter (where v >= 4) from test where v <= 10; ...@@ -17,6 +17,19 @@ select count(v), count(v) filter (where v >= 4) from test where v <= 10;
> 10 7 > 10 7
> rows: 1 > rows: 1
select count(*), count(*) filter (where v >= 4) from test;
> COUNT(*) COUNT(*) FILTER (WHERE (V >= 4))
> -------- --------------------------------
> 13 9
> rows: 1
select count(*), count(*) filter (where v >= 4) from test where v <= 10;
> COUNT(*) COUNT(*) FILTER (WHERE (V >= 4))
> -------- --------------------------------
> 10 7
> rows: 1
create index test_idx on test(v); create index test_idx on test(v);
> ok > ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论