?? aggregate.java
字號:
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.expression;
import java.sql.SQLException;
import java.util.Comparator;
import java.util.HashMap;
import org.h2.command.dml.Select;
import org.h2.command.dml.SelectOrderBy;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.index.Index;
import org.h2.message.Message;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.util.ObjectUtils;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueDouble;
import org.h2.value.ValueInt;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueString;
/**
* Implements the integrated aggregate functions, such as COUNT, MAX, SUM.
*/
public class Aggregate extends Expression {
// TODO incompatibility to hsqldb: aggregates: hsqldb uses automatic data
// type for sum if value is too big,
// h2 uses the same type as the data
public static final int COUNT_ALL = 0, COUNT = 1, SUM = 2, MIN = 3, MAX = 4, AVG = 5;
public static final int GROUP_CONCAT = 6, STDDEV_POP = 7, STDDEV_SAMP = 8;
public static final int VAR_POP = 9, VAR_SAMP = 10, SOME = 11, EVERY = 12, SELECTIVITY = 13;
private final Database database;
private final int type;
private final Select select;
private final boolean distinct;
private Expression on;
private Expression separator;
private ObjectArray orderList;
private SortOrder sort;
private int dataType, scale;
private long precision;
private int displaySize;
private static final HashMap AGGREGATES = new HashMap();
public Aggregate(Database database, int type, Expression on, Select select, boolean distinct) {
this.database = database;
this.type = type;
this.on = on;
this.select = select;
this.distinct = distinct;
}
static {
addAggregate("COUNT", COUNT);
addAggregate("SUM", SUM);
addAggregate("MIN", MIN);
addAggregate("MAX", MAX);
addAggregate("AVG", AVG);
addAggregate("GROUP_CONCAT", GROUP_CONCAT);
addAggregate("STDDEV_SAMP", STDDEV_SAMP);
addAggregate("STDDEV", STDDEV_SAMP);
addAggregate("STDDEV_POP", STDDEV_POP);
addAggregate("STDDEVP", STDDEV_POP);
addAggregate("VAR_POP", VAR_POP);
addAggregate("VARP", VAR_POP);
addAggregate("VAR_SAMP", VAR_SAMP);
addAggregate("VAR", VAR_SAMP);
addAggregate("VARIANCE", VAR_SAMP);
addAggregate("SOME", SOME);
addAggregate("EVERY", EVERY);
addAggregate("SELECTIVITY", SELECTIVITY);
}
private static void addAggregate(String name, int type) {
AGGREGATES.put(name, ObjectUtils.getInteger(type));
}
public static int getAggregateType(String name) {
Integer type = (Integer) AGGREGATES.get(name);
return type == null ? -1 : type.intValue();
}
public void setOrder(ObjectArray orderBy) {
this.orderList = orderBy;
}
public void setSeparator(Expression separator) {
this.separator = separator;
}
private SortOrder initOrder(Session session) throws SQLException {
int[] index = new int[orderList.size()];
int[] sortType = new int[orderList.size()];
for (int i = 0; i < orderList.size(); i++) {
SelectOrderBy o = (SelectOrderBy) orderList.get(i);
index[i] = i + 1;
int type = o.descending ? SortOrder.DESCENDING : SortOrder.ASCENDING;
sortType[i] = type;
}
return new SortOrder(session.getDatabase(), index, sortType);
}
public void updateAggregate(Session session) throws SQLException {
// TODO aggregates: check nested MIN(MAX(ID)) and so on
// if(on != null) {
// on.updateAggregate();
// }
HashMap group = select.getCurrentGroup();
if (group == null) {
// this is a different level (the enclosing query)
return;
}
AggregateData data = (AggregateData) group.get(this);
if (data == null) {
data = new AggregateData(type);
group.put(this, data);
}
Value v = on == null ? null : on.getValue(session);
if (type == GROUP_CONCAT) {
if (v != ValueNull.INSTANCE) {
v = v.convertTo(Value.STRING);
if (orderList != null) {
Value[] array = new Value[1 + orderList.size()];
array[0] = v;
for (int i = 0; i < orderList.size(); i++) {
SelectOrderBy o = (SelectOrderBy) orderList.get(i);
array[i + 1] = o.expression.getValue(session);
}
v = ValueArray.get(array);
}
}
}
data.add(database, distinct, v);
}
public Value getValue(Session session) throws SQLException {
if (select.isQuickQuery()) {
switch (type) {
case COUNT_ALL:
Table table = select.getTopTableFilter().getTable();
return ValueLong.get(table.getRowCount(session));
case MIN:
case MAX:
boolean first = type == MIN;
Index index = getColumnIndex(first);
int sortType = index.getIndexColumns()[0].sortType;
if ((sortType & SortOrder.DESCENDING) != 0) {
first = !first;
}
SearchRow row = index.findFirstOrLast(session, first);
Value v;
if (row == null) {
v = ValueNull.INSTANCE;
} else {
v = row.getValue(index.getColumns()[0].getColumnId());
}
return v;
default:
throw Message.getInternalError("type=" + type);
}
}
HashMap group = select.getCurrentGroup();
if (group == null) {
throw Message.getSQLException(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, getSQL());
}
AggregateData data = (AggregateData) group.get(this);
if (data == null) {
data = new AggregateData(type);
}
Value v = data.getValue(database, distinct);
if (type == GROUP_CONCAT) {
ObjectArray list = data.getList();
if (list == null || list.size() == 0) {
return ValueNull.INSTANCE;
}
if (orderList != null) {
try {
// TODO refactor: don't use built in comparator
list.sort(new Comparator() {
public int compare(Object o1, Object o2) {
try {
Value[] a1 = ((ValueArray) o1).getList();
Value[] a2 = ((ValueArray) o2).getList();
return sort.compare(a1, a2);
} catch (SQLException e) {
throw Message.convertToInternal(e);
}
}
});
} catch (Error e) {
throw Message.convert(e);
}
}
StringBuffer buff = new StringBuffer();
String sep = separator == null ? "," : separator.getValue(session).getString();
for (int i = 0; i < list.size(); i++) {
Value val = (Value) list.get(i);
String s;
if (val.getType() == Value.ARRAY) {
s = ((ValueArray) val).getList()[0].getString();
} else {
s = val.convertTo(Value.STRING).getString();
}
if (s == null) {
continue;
}
if (i > 0 && sep != null) {
buff.append(sep);
}
buff.append(s);
}
v = ValueString.get(buff.toString());
}
return v;
}
public int getType() {
return dataType;
}
public void mapColumns(ColumnResolver resolver, int level) throws SQLException {
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -