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

Merge pull request #1448 from katzyn/aggregate

Add experimental implementation of grouped window queries
......@@ -21,6 +21,16 @@ Change Log
<h2>Next Version (unreleased)</h2>
<ul>
<li>PR #1448: Add experimental implementation of grouped window queries
</li>
<li>PR #1447: Refactor OVER() processing code and fix some issues
</li>
<li>PR #1446: fix : The French messages are bad generated (not contain DB message)
</li>
<li>PR #1445: Use PostGIS-compatible format for SRID-only constraint in GEOMETRY
</li>
<li>PR #1444: Add experimental unoptimized support for OVER ([PARTITION BY ...]) in aggregates
</li>
<li>PR #1441: Add GEOMETRY type subtypes with type and SRID constraints
</li>
<li>PR #1434: Add support for ENUM in CAST and other changes
......
......@@ -113,6 +113,8 @@ public class Select extends Query {
private boolean isPrepared, checkInit;
private boolean sortUsingIndex;
private boolean isGroupWindowStage2;
public Select(Session session) {
super(session);
}
......@@ -356,28 +358,38 @@ public class Select extends Query {
}
private void queryWindow(int columnCount, LocalResult result, long offset, boolean quickOffset) {
if (isGroupQuery) {
queryGroupWindow(columnCount, result, offset, quickOffset);
return;
}
if (groupData == null) {
groupData = SelectGroups.getInstance(session, expressions, isGroupQuery, groupIndex);
}
groupData.reset();
try {
int rowNumber = 0;
setCurrentRowNumber(0);
int sampleSize = getSampleSizeValue(session);
while (topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1);
if (isConditionMet()) {
rowNumber++;
groupData.nextSource();
updateAgg(columnCount, true);
if (sampleSize > 0 && rowNumber >= sampleSize) {
break;
}
}
gatherGroup(columnCount, true);
processGroupResult(columnCount, result, offset, quickOffset);
} finally {
groupData.reset();
}
}
private void queryGroupWindow(int columnCount, LocalResult result, long offset, boolean quickOffset) {
if (groupData == null) {
groupData = SelectGroups.getInstance(session, expressions, isGroupQuery, groupIndex);
}
groupData.reset();
try {
gatherGroup(columnCount, false);
while (groupData.next() != null) {
updateAgg(columnCount, true);
}
groupData.done();
for (ValueArray currentGroupsKey; (currentGroupsKey = groupData.next()) != null;) {
offset = processGroupedRow(columnCount, result, offset, quickOffset, currentGroupsKey);
try {
isGroupWindowStage2 = true;
processGroupResult(columnCount, result, offset, quickOffset);
} finally {
isGroupWindowStage2 = false;
}
} finally {
groupData.reset();
......@@ -390,29 +402,31 @@ public class Select extends Query {
}
groupData.reset();
try {
int rowNumber = 0;
setCurrentRowNumber(0);
int sampleSize = getSampleSizeValue(session);
while (topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1);
if (isConditionMet()) {
rowNumber++;
groupData.nextSource();
updateAgg(columnCount, false);
if (sampleSize > 0 && rowNumber >= sampleSize) {
break;
}
}
}
groupData.done();
for (ValueArray currentGroupsKey; (currentGroupsKey = groupData.next()) != null;) {
offset = processGroupedRow(columnCount, result, offset, quickOffset, currentGroupsKey);
}
gatherGroup(columnCount, false);
processGroupResult(columnCount, result, offset, quickOffset);
} finally {
groupData.reset();
}
}
private void gatherGroup(int columnCount, boolean window) {
int rowNumber = 0;
setCurrentRowNumber(0);
int sampleSize = getSampleSizeValue(session);
while (topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1);
if (isConditionMet()) {
rowNumber++;
groupData.nextSource();
updateAgg(columnCount, window);
if (sampleSize > 0 && rowNumber >= sampleSize) {
break;
}
}
}
groupData.done();
}
private void updateAgg(int columnCount, boolean window) {
for (int i = 0; i < columnCount; i++) {
if (groupByExpression == null || !groupByExpression[i]) {
......@@ -422,30 +436,30 @@ public class Select extends Query {
}
}
private long processGroupedRow(int columnCount, LocalResult result, long offset, boolean quickOffset,
ValueArray currentGroupsKey) {
Value[] keyValues = currentGroupsKey.getList();
Value[] row = new Value[columnCount];
for (int j = 0; groupIndex != null && j < groupIndex.length; j++) {
row[groupIndex[j]] = keyValues[j];
}
for (int j = 0; j < columnCount; j++) {
if (groupByExpression != null && groupByExpression[j]) {
private void processGroupResult(int columnCount, LocalResult result, long offset, boolean quickOffset) {
for (ValueArray currentGroupsKey; (currentGroupsKey = groupData.next()) != null;) {
Value[] keyValues = currentGroupsKey.getList();
Value[] row = new Value[columnCount];
for (int j = 0; groupIndex != null && j < groupIndex.length; j++) {
row[groupIndex[j]] = keyValues[j];
}
for (int j = 0; j < columnCount; j++) {
if (groupByExpression != null && groupByExpression[j]) {
continue;
}
Expression expr = expressions.get(j);
row[j] = expr.getValue(session);
}
if (isHavingNullOrFalse(row)) {
continue;
}
Expression expr = expressions.get(j);
row[j] = expr.getValue(session);
}
if (isHavingNullOrFalse(row)) {
return offset;
}
if (quickOffset && offset > 0) {
offset--;
return offset;
if (quickOffset && offset > 0) {
offset--;
continue;
}
row = keepOnlyDistinct(row, columnCount);
result.addRow(row);
}
row = keepOnlyDistinct(row, columnCount);
result.addRow(row);
return offset;
}
/**
......@@ -746,7 +760,11 @@ public class Select extends Query {
if (isQuickAggregateQuery) {
queryQuick(columnCount, to, quickOffset && offset > 0);
} else if (isWindowQuery) {
queryWindow(columnCount, result, offset, quickOffset);
if (isGroupQuery) {
queryGroupWindow(columnCount, result, offset, quickOffset);
} else {
queryWindow(columnCount, result, offset, quickOffset);
}
} else if (isGroupQuery) {
if (isGroupSortedQuery) {
lazyResult = queryGroupSorted(columnCount, to, offset, quickOffset);
......@@ -943,10 +961,6 @@ public class Select extends Query {
throw DbException.get(ErrorCode.WITH_TIES_WITHOUT_ORDER_BY);
}
if (isWindowQuery && isGroupQuery) {
throw DbException.getUnsupportedException("Window functions in group query are not currently supported.");
}
Database db = session.getDatabase();
// first the select list (visible columns),
......@@ -1437,6 +1451,34 @@ public class Select extends Query {
return isQuickAggregateQuery;
}
/**
* Checks if this query is a group query.
*
* @return whether this query is a group query.
*/
public boolean isGroupQuery() {
return isGroupQuery;
}
/**
* Checks if this query contains window functions.
*
* @return whether this query contains window functions
*/
public boolean isWindowQuery() {
return isWindowQuery;
}
/**
* Checks if window stage of group window query is performed. If true,
* column resolver may not be used.
*
* @return true if window stage of group window query is performed
*/
public boolean isGroupWindowStage2() {
return isGroupWindowStage2;
}
@Override
public void addGlobalCondition(Parameter param, int columnId,
int comparisonType) {
......
......@@ -127,6 +127,7 @@ public abstract class SelectGroups {
if (cursor.hasNext()) {
Map.Entry<ValueArray, Object[]> entry = cursor.next();
currentGroupByExprData = entry.getValue();
currentGroupRowId++;
return entry.getKey();
}
return null;
......
......@@ -184,6 +184,9 @@ public class ExpressionColumn extends Expression {
if (v != null) {
return v;
}
if (select.isGroupWindowStage2()) {
throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
}
}
}
Value value = columnResolver.getValue(column);
......
......@@ -291,6 +291,20 @@ public class Aggregate extends AbstractAggregate {
@Override
public void updateAggregate(Session session, boolean window) {
if (window != (over != null)) {
if (!window && select.isWindowQuery()) {
if (on != null) {
on.updateAggregate(session, false);
}
if (orderByList != null) {
for (SelectOrderBy orderBy : orderByList) {
orderBy.expression.updateAggregate(session, false);
}
}
if (filterCondition != null) {
filterCondition.updateAggregate(session, false);
}
over.updateAggregate(session, false);
}
return;
}
// TODO aggregates: check nested MIN(MAX(ID)) and so on
......@@ -311,7 +325,9 @@ public class Aggregate extends AbstractAggregate {
lastGroupRowId = groupRowId;
if (over != null) {
over.updateAggregate(session, true);
if (!select.isGroupQuery()) {
over.updateAggregate(session, true);
}
}
if (filterCondition != null) {
if (!filterCondition.getBooleanValue(session)) {
......
......@@ -77,52 +77,89 @@ INSERT INTO TEST VALUES (1, 'a'), (2, 'a'), (3, 'b'), (4, 'c'), (5, 'c'), (6, 'c
SELECT ARRAY_AGG(ID), NAME FROM TEST;
> exception MUST_GROUP_BY_COLUMN_1
SELECT ARRAY_AGG(ID), NAME FROM TEST GROUP BY NAME;
> ARRAY_AGG(ID) NAME
> ------------- ----
> (1, 2) a
> (3) b
> (4, 5, 6) c
SELECT ARRAY_AGG(ID ORDER /**/ BY ID), NAME FROM TEST GROUP BY NAME;
> ARRAY_AGG(ID ORDER BY ID) NAME
> ------------------------- ----
> (1, 2) a
> (3) b
> (4, 5, 6) c
> rows: 3
SELECT ARRAY_AGG(ID) OVER (), NAME FROM TEST;
> ARRAY_AGG(ID) OVER () NAME
> --------------------- ----
> (1, 2, 3, 4, 5, 6) a
> (1, 2, 3, 4, 5, 6) a
> (1, 2, 3, 4, 5, 6) b
> (1, 2, 3, 4, 5, 6) c
> (1, 2, 3, 4, 5, 6) c
> (1, 2, 3, 4, 5, 6) c
SELECT ARRAY_AGG(ID ORDER /**/ BY ID) OVER (), NAME FROM TEST;
> ARRAY_AGG(ID ORDER BY ID) OVER () NAME
> --------------------------------- ----
> (1, 2, 3, 4, 5, 6) a
> (1, 2, 3, 4, 5, 6) a
> (1, 2, 3, 4, 5, 6) b
> (1, 2, 3, 4, 5, 6) c
> (1, 2, 3, 4, 5, 6) c
> (1, 2, 3, 4, 5, 6) c
> rows: 6
SELECT ARRAY_AGG(ID) OVER (PARTITION BY NAME), NAME FROM TEST;
> ARRAY_AGG(ID) OVER (PARTITION BY NAME) NAME
> -------------------------------------- ----
> (1, 2) a
> (1, 2) a
> (3) b
> (4, 5, 6) c
> (4, 5, 6) c
> (4, 5, 6) c
SELECT ARRAY_AGG(ID ORDER /**/ BY ID) OVER (PARTITION BY NAME), NAME FROM TEST;
> ARRAY_AGG(ID ORDER BY ID) OVER (PARTITION BY NAME) NAME
> -------------------------------------------------- ----
> (1, 2) a
> (1, 2) a
> (3) b
> (4, 5, 6) c
> (4, 5, 6) c
> (4, 5, 6) c
> 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
SELECT ARRAY_AGG(ID ORDER /**/ BY ID) FILTER (WHERE ID < 3 OR ID > 4) OVER (PARTITION BY NAME), NAME FROM TEST ORDER BY NAME;
> ARRAY_AGG(ID ORDER BY 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;
> exception FEATURE_NOT_SUPPORTED_1
> ARRAY_AGG(SUM(ID)) OVER ()
> --------------------------
> (21)
> rows: 1
SELECT ARRAY_AGG(ID ORDER /**/ BY ID) OVER() FROM TEST GROUP BY ID ORDER /**/ BY ID;
> ARRAY_AGG(ID ORDER BY ID) OVER ()
> ---------------------------------
> (1, 2, 3, 4, 5, 6)
> (1, 2, 3, 4, 5, 6)
> (1, 2, 3, 4, 5, 6)
> (1, 2, 3, 4, 5, 6)
> (1, 2, 3, 4, 5, 6)
> (1, 2, 3, 4, 5, 6)
> rows: 6
SELECT ARRAY_AGG(NAME) OVER(PARTITION BY NAME) FROM TEST GROUP BY NAME;
> ARRAY_AGG(NAME) OVER (PARTITION BY NAME)
> ----------------------------------------
> (a)
> (b)
> (c)
> rows: 3
SELECT ARRAY_AGG(ID) OVER() FROM TEST GROUP BY ID;
> exception FEATURE_NOT_SUPPORTED_1
SELECT ARRAY_AGG(ARRAY_AGG(ID ORDER /**/ BY ID)) OVER (PARTITION BY NAME), NAME FROM TEST GROUP BY NAME;
> ARRAY_AGG(ARRAY_AGG(ID ORDER BY ID)) OVER (PARTITION BY NAME) NAME
> ------------------------------------------------------------- ----
> ((1, 2)) a
> ((3)) b
> ((4, 5, 6)) c
> rows: 3
SELECT ARRAY_AGG(ARRAY_AGG(ID ORDER /**/ BY ID)) OVER (PARTITION BY NAME), NAME FROM TEST GROUP BY NAME ORDER /**/ BY NAME OFFSET 1 ROW;
> ARRAY_AGG(ARRAY_AGG(ID ORDER BY ID)) OVER (PARTITION BY NAME) NAME
> ------------------------------------------------------------- ----
> ((3)) b
> ((4, 5, 6)) c
> rows: 2
SELECT ARRAY_AGG(ID) OVER() FROM TEST GROUP BY NAME;
> exception MUST_GROUP_BY_COLUMN_1
DROP TABLE TEST;
> ok
......@@ -40,3 +40,11 @@ select sum(v) from test;
drop table test;
> ok
SELECT X, COUNT(*), SUM(COUNT(*)) OVER() FROM VALUES (1), (1), (1), (1), (2), (2), (3) T(X) GROUP BY X;
> X COUNT(*) SUM(COUNT(*)) OVER ()
> - -------- ---------------------
> 1 4 7
> 2 2 7
> 3 1 7
> rows: 3
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论