提交 86098d30 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Use AggregateDataCollecting for MEDIAN aggregate

上级 f49d2b6a
...@@ -402,7 +402,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -402,7 +402,7 @@ public class Aggregate extends AbstractAggregate {
return v; return v;
} }
case MEDIAN: case MEDIAN:
return AggregateDataMedian.getResultFromIndex(session, on, dataType); return AggregateMedian.medianFromIndex(session, on, dataType);
case ENVELOPE: case ENVELOPE:
return ((MVSpatialIndex) AggregateDataEnvelope.getGeometryColumnIndex(on)).getBounds(session); return ((MVSpatialIndex) AggregateDataEnvelope.getGeometryColumnIndex(on)).getBounds(session);
default: default:
...@@ -459,6 +459,13 @@ public class Aggregate extends AbstractAggregate { ...@@ -459,6 +459,13 @@ public class Aggregate extends AbstractAggregate {
} }
return ValueArray.get(array); return ValueArray.get(array);
} }
case MEDIAN: {
Value[] array = ((AggregateDataCollecting) data).getArray();
if (array == null) {
return ValueNull.INSTANCE;
}
return AggregateMedian.median(session.getDatabase(), array, dataType);
}
case MODE: case MODE:
if (orderByList != null) { if (orderByList != null) {
return ((AggregateDataMode) data).getOrderedValue(session.getDatabase(), dataType, return ((AggregateDataMode) data).getOrderedValue(session.getDatabase(), dataType,
...@@ -762,7 +769,7 @@ public class Aggregate extends AbstractAggregate { ...@@ -762,7 +769,7 @@ public class Aggregate extends AbstractAggregate {
if (distinct) { if (distinct) {
return false; return false;
} }
return AggregateDataMedian.getMedianColumnIndex(on) != null; return AggregateMedian.getMedianColumnIndex(on) != null;
case ENVELOPE: case ENVELOPE:
return AggregateDataEnvelope.getGeometryColumnIndex(on) != null; return AggregateDataEnvelope.getGeometryColumnIndex(on) != null;
default: default:
......
...@@ -26,6 +26,7 @@ abstract class AggregateData { ...@@ -26,6 +26,7 @@ abstract class AggregateData {
return new AggregateDataSelectivity(); return new AggregateDataSelectivity();
case GROUP_CONCAT: case GROUP_CONCAT:
case ARRAY_AGG: case ARRAY_AGG:
case MEDIAN:
return new AggregateDataCollecting(); return new AggregateDataCollecting();
case COUNT_ALL: case COUNT_ALL:
return new AggregateDataCountAll(); return new AggregateDataCountAll();
...@@ -33,8 +34,6 @@ abstract class AggregateData { ...@@ -33,8 +34,6 @@ abstract class AggregateData {
return new AggregateDataCount(); return new AggregateDataCount();
case HISTOGRAM: case HISTOGRAM:
return new AggregateDataHistogram(); return new AggregateDataHistogram();
case MEDIAN:
return new AggregateDataMedian();
case MODE: case MODE:
return new AggregateDataMode(); return new AggregateDataMode();
case ENVELOPE: case ENVELOPE:
......
...@@ -20,8 +20,7 @@ import org.h2.value.ValueNull; ...@@ -20,8 +20,7 @@ import org.h2.value.ValueNull;
* <p> * <p>
* NULL values are not collected. {@link #getValue(Database, int, boolean)} * NULL values are not collected. {@link #getValue(Database, int, boolean)}
* method returns {@code null}. Use {@link #getArray()} for instances of this * method returns {@code null}. Use {@link #getArray()} for instances of this
* class instead. Notice that subclasses like {@link AggregateDataMedian} may * class instead.
* override {@link #getValue(Database, int, boolean)} to return useful result.
* </p> * </p>
*/ */
class AggregateDataCollecting extends AggregateData { class AggregateDataCollecting extends AggregateData {
......
...@@ -41,9 +41,10 @@ import org.h2.value.ValueTimestamp; ...@@ -41,9 +41,10 @@ import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone; import org.h2.value.ValueTimestampTimeZone;
/** /**
* Data stored while calculating a MEDIAN aggregate. * MEDIAN aggregate.
*/ */
class AggregateDataMedian extends AggregateDataCollecting { final class AggregateMedian {
private static boolean isNullsLast(Index index) { private static boolean isNullsLast(Index index) {
IndexColumn ic = index.getIndexColumns()[0]; IndexColumn ic = index.getIndexColumns()[0];
int sortType = ic.sortType; int sortType = ic.sortType;
...@@ -91,14 +92,34 @@ class AggregateDataMedian extends AggregateDataCollecting { ...@@ -91,14 +92,34 @@ class AggregateDataMedian extends AggregateDataCollecting {
} }
/** /**
* Get the result from the index. * Get the median from the array of values.
*
* @param database the database
* @param array array with values
* @param dataType the data type
* @return the result
*/
static Value median(Database database, Value[] array, int dataType) {
final CompareMode compareMode = database.getCompareMode();
Arrays.sort(array, compareMode);
int len = array.length;
int idx = len / 2;
Value v1 = array[idx];
if ((len & 1) == 1) {
return v1.convertTo(dataType);
}
return getMedian(array[idx - 1], v1, dataType, database.getMode(), compareMode);
}
/**
* Get the median from the index.
* *
* @param session the session * @param session the session
* @param on the expression * @param on the expression
* @param dataType the data type * @param dataType the data type
* @return the result * @return the result
*/ */
static Value getResultFromIndex(Session session, Expression on, int dataType) { static Value medianFromIndex(Session session, Expression on, int dataType) {
Index index = getMedianColumnIndex(on); Index index = getMedianColumnIndex(on);
long count = index.getRowCount(session); long count = index.getRowCount(session);
if (count == 0) { if (count == 0) {
...@@ -172,25 +193,9 @@ class AggregateDataMedian extends AggregateDataCollecting { ...@@ -172,25 +193,9 @@ class AggregateDataMedian extends AggregateDataCollecting {
return v; return v;
} }
@Override
Value getValue(Database database, int dataType, boolean distinct) {
Value[] a = getArray();
if (a == null) {
return ValueNull.INSTANCE;
}
final CompareMode compareMode = database.getCompareMode();
Arrays.sort(a, compareMode);
int len = a.length;
int idx = len / 2;
Value v1 = a[idx];
if ((len & 1) == 1) {
return v1.convertTo(dataType);
}
return getMedian(a[idx - 1], v1, dataType, database.getMode(), compareMode);
}
private static Value getMedian(Value v0, Value v1, int dataType, Mode databaseMode, CompareMode compareMode) { private static Value getMedian(Value v0, Value v1, int dataType, Mode databaseMode, CompareMode compareMode) {
if (v0.compareTo(v1, databaseMode, compareMode) == 0) { int cmp = v0.compareTo(v1, databaseMode, compareMode);
if (cmp == 0) {
return v0.convertTo(dataType); return v0.convertTo(dataType);
} }
switch (dataType) { switch (dataType) {
...@@ -266,11 +271,14 @@ class AggregateDataMedian extends AggregateDataCollecting { ...@@ -266,11 +271,14 @@ class AggregateDataMedian extends AggregateDataCollecting {
case Value.INTERVAL_MINUTE_TO_SECOND: case Value.INTERVAL_MINUTE_TO_SECOND:
return IntervalUtils.intervalFromAbsolute(IntervalQualifier.valueOf(dataType - Value.INTERVAL_YEAR), return IntervalUtils.intervalFromAbsolute(IntervalQualifier.valueOf(dataType - Value.INTERVAL_YEAR),
IntervalUtils.intervalToAbsolute((ValueInterval) v0) IntervalUtils.intervalToAbsolute((ValueInterval) v0)
.add(IntervalUtils.intervalToAbsolute((ValueInterval) v1)).shiftRight(1)); .add(IntervalUtils.intervalToAbsolute((ValueInterval) v1)).shiftRight(1));
default: default:
// Just return first // Just return smaller
return v0.convertTo(dataType); return (cmp < 0 ? v0 : v1).convertTo(dataType);
} }
} }
private AggregateMedian() {
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论