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

Merge pull request #1705 from katzyn/aggregate

Fix GROUP_CONCAT with variable separator
......@@ -3545,6 +3545,7 @@ GROUP_CONCAT ( [ DISTINCT|ALL ] string
[FILTER (WHERE expression)] [OVER windowNameOrSpecification]
","
Concatenates strings with a separator.
Separator must be the same for all rows in the same group.
The default separator is a ',' (without space).
This method returns a string.
If no rows are selected, the result is NULL.
......
......@@ -3041,43 +3041,50 @@ public class Parser {
switch (aggregateType) {
case COUNT:
if (readIf(ASTERISK)) {
r = new Aggregate(AggregateType.COUNT_ALL, null, currentSelect, false);
r = new Aggregate(AggregateType.COUNT_ALL, new Expression[0], currentSelect, false);
} else {
boolean distinct = readDistinctAgg();
Expression on = readExpression();
if (on instanceof Wildcard && !distinct) {
// PostgreSQL compatibility: count(t.*)
r = new Aggregate(AggregateType.COUNT_ALL, null, currentSelect, false);
r = new Aggregate(AggregateType.COUNT_ALL, new Expression[0], currentSelect, false);
} else {
r = new Aggregate(AggregateType.COUNT, on, currentSelect, distinct);
r = new Aggregate(AggregateType.COUNT, new Expression[] { on }, currentSelect, distinct);
}
}
break;
case GROUP_CONCAT: {
boolean distinct = readDistinctAgg();
r = new Aggregate(AggregateType.GROUP_CONCAT, readExpression(), currentSelect, distinct);
Expression arg = readExpression(), separator = null;
ArrayList<SelectOrderBy> orderByList = null;
if (equalsToken("STRING_AGG", aggregateName)) {
// PostgreSQL compatibility: string_agg(expression, delimiter)
read(COMMA);
r.setGroupConcatSeparator(readExpression());
separator = readExpression();
if (readIf(ORDER)) {
read("BY");
r.setOrderByList(parseSimpleOrderList());
orderByList = parseSimpleOrderList();
}
} else {
if (readIf(ORDER)) {
read("BY");
r.setOrderByList(parseSimpleOrderList());
orderByList = parseSimpleOrderList();
}
if (readIf("SEPARATOR")) {
r.setGroupConcatSeparator(readExpression());
separator = readExpression();
}
}
r = new Aggregate(AggregateType.GROUP_CONCAT,
separator == null ? new Expression[] { arg } : new Expression[] { arg, separator },
currentSelect, distinct);
if (orderByList != null) {
r.setOrderByList(orderByList);
}
break;
}
case ARRAY_AGG: {
boolean distinct = readDistinctAgg();
r = new Aggregate(AggregateType.ARRAY_AGG, readExpression(), currentSelect, distinct);
r = new Aggregate(AggregateType.ARRAY_AGG, new Expression[] { readExpression() }, currentSelect, distinct);
if (readIf(ORDER)) {
read("BY");
r.setOrderByList(parseSimpleOrderList());
......@@ -3088,15 +3095,15 @@ public class Parser {
case PERCENTILE_DISC: {
Expression num = readExpression();
read(CLOSE_PAREN);
r = readWithinGroup(aggregateType, num);
r = readWithinGroup(aggregateType, new Expression[] { num });
break;
}
case MODE: {
if (readIf(CLOSE_PAREN)) {
r = readWithinGroup(AggregateType.MODE, null);
r = readWithinGroup(AggregateType.MODE, new Expression[0]);
} else {
Expression expr = readExpression();
r = new Aggregate(aggregateType, null, currentSelect, false);
r = new Aggregate(aggregateType, new Expression[0], currentSelect, false);
if (readIf(ORDER)) {
read("BY");
Expression expr2 = readExpression();
......@@ -3114,7 +3121,7 @@ public class Parser {
}
default:
boolean distinct = readDistinctAgg();
r = new Aggregate(aggregateType, readExpression(), currentSelect, distinct);
r = new Aggregate(aggregateType, new Expression[] { readExpression() }, currentSelect, distinct);
break;
}
read(CLOSE_PAREN);
......@@ -3122,7 +3129,7 @@ public class Parser {
return r;
}
private Aggregate readWithinGroup(AggregateType aggregateType, Expression argument) {
private Aggregate readWithinGroup(AggregateType aggregateType, Expression[] args) {
Aggregate r;
read("WITHIN");
read(GROUP);
......@@ -3130,7 +3137,7 @@ public class Parser {
read(ORDER);
read("BY");
Expression expr = readExpression();
r = new Aggregate(aggregateType, argument, currentSelect, false);
r = new Aggregate(aggregateType, args, currentSelect, false);
readAggregateOrder(r, expr, true);
return r;
}
......
......@@ -22,6 +22,7 @@ import org.h2.expression.analysis.WindowFrameExclusion;
import org.h2.expression.analysis.WindowFrameUnits;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
/**
......@@ -34,13 +35,24 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
*/
protected final boolean distinct;
/**
* The arguments.
*/
protected final Expression[] args;
/**
* FILTER condition for aggregate
*/
protected Expression filterCondition;
AbstractAggregate(Select select, boolean distinct) {
/**
* The type of the result.
*/
protected TypeInfo type;
AbstractAggregate(Select select, Expression[] args, boolean distinct) {
super(select);
this.args = args;
this.distinct = distinct;
}
......@@ -59,8 +71,16 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
this.filterCondition = filterCondition;
}
@Override
public TypeInfo getType() {
return type;
}
@Override
public void mapColumnsAnalysis(ColumnResolver resolver, int level, int innerState) {
for (Expression arg : args) {
arg.mapColumns(resolver, level, innerState);
}
if (filterCondition != null) {
filterCondition.mapColumns(resolver, level, innerState);
}
......@@ -69,6 +89,9 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
@Override
public Expression optimize(Session session) {
for (int i = 0; i < args.length; i++) {
args[i] = args[i].optimize(session);
}
if (filterCondition != null) {
filterCondition = filterCondition.optimize(session);
}
......@@ -77,6 +100,9 @@ public abstract class AbstractAggregate extends DataAnalysisOperation {
@Override
public void setEvaluatable(TableFilter tableFilter, boolean b) {
for (Expression arg : args) {
arg.setEvaluatable(tableFilter, b);
}
if (filterCondition != null) {
filterCondition.setEvaluatable(tableFilter, b);
}
......
......@@ -15,8 +15,6 @@ import org.h2.engine.UserAggregate;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor;
import org.h2.message.DbException;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.DataType;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
......@@ -30,16 +28,13 @@ import org.h2.value.ValueRow;
public class JavaAggregate extends AbstractAggregate {
private final UserAggregate userAggregate;
private final Expression[] args;
private int[] argTypes;
private TypeInfo type;
private int dataType;
private Connection userConnection;
public JavaAggregate(UserAggregate userAggregate, Expression[] args, Select select, boolean distinct) {
super(select, distinct);
super(select, args, distinct);
this.userAggregate = userAggregate;
this.args = args;
}
@Override
......@@ -62,11 +57,6 @@ public class JavaAggregate extends AbstractAggregate {
return appendTailConditions(builder);
}
@Override
public TypeInfo getType() {
return type;
}
@Override
public boolean isEverything(ExpressionVisitor visitor) {
if (!super.isEverything(visitor)) {
......@@ -92,14 +82,6 @@ public class JavaAggregate extends AbstractAggregate {
return filterCondition == null || filterCondition.isEverything(visitor);
}
@Override
public void mapColumnsAnalysis(ColumnResolver resolver, int level, int innerState) {
for (Expression arg : args) {
arg.mapColumns(resolver, level, innerState);
}
super.mapColumnsAnalysis(resolver, level, innerState);
}
@Override
public Expression optimize(Session session) {
super.optimize(session);
......@@ -107,9 +89,7 @@ public class JavaAggregate extends AbstractAggregate {
int len = args.length;
argTypes = new int[len];
for (int i = 0; i < len; i++) {
Expression expr = args[i];
args[i] = expr.optimize(session);
int type = expr.getType().getValueType();
int type = args[i].getType().getValueType();
argTypes[i] = type;
}
try {
......@@ -122,14 +102,6 @@ public class JavaAggregate extends AbstractAggregate {
return this;
}
@Override
public void setEvaluatable(TableFilter tableFilter, boolean b) {
for (Expression e : args) {
e.setEvaluatable(tableFilter, b);
}
super.setEvaluatable(tableFilter, b);
}
private Aggregate getInstance() {
Aggregate agg = userAggregate.getInstance();
try {
......
......@@ -67,3 +67,32 @@ select group_concat(distinct v order by v desc) from test;
drop table test;
> ok
create table test(g varchar, v int) as values ('-', 1), ('-', 2), ('-', 3), ('|', 4), ('|', 5), ('|', 6), ('*', null);
> ok
select g, group_concat(v separator g) from test group by g;
> G GROUP_CONCAT(V SEPARATOR G)
> - ---------------------------
> * null
> - 1-2-3
> | 4|5|6
> rows: 3
select g, group_concat(v separator g) over (partition by g) from test order by v;
> G GROUP_CONCAT(V SEPARATOR G) OVER (PARTITION BY G)
> - -------------------------------------------------
> * null
> - 1-2-3
> - 1-2-3
> - 1-2-3
> | 4|5|6
> | 4|5|6
> | 4|5|6
> rows (ordered): 7
select g, group_concat(v separator v) from test group by g;
> exception INVALID_VALUE_2
drop table test;
> ok
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论