001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.expression;
007:
008: import java.sql.Connection;
009: import java.sql.SQLException;
010: import java.util.HashMap;
011:
012: import org.h2.api.AggregateFunction;
013: import org.h2.command.Parser;
014: import org.h2.command.dml.Select;
015: import org.h2.constant.ErrorCode;
016: import org.h2.engine.Session;
017: import org.h2.engine.UserAggregate;
018: import org.h2.message.Message;
019: import org.h2.table.ColumnResolver;
020: import org.h2.table.TableFilter;
021: import org.h2.value.DataType;
022: import org.h2.value.Value;
023: import org.h2.value.ValueNull;
024:
025: /**
026: * This class wraps a user defined aggregate.
027: */
028: public class JavaAggregate extends Expression {
029:
030: private final UserAggregate userAggregate;
031: private final Select select;
032: private AggregateFunction aggregate;
033: private Expression[] args;
034: private int[] argTypes;
035: private int dataType;
036: private Connection userConnection;
037:
038: public JavaAggregate(UserAggregate userAggregate,
039: Expression[] args, Select select) throws SQLException {
040: this .userAggregate = userAggregate;
041: this .args = args;
042: this .select = select;
043: }
044:
045: public int getCost() {
046: int cost = 5;
047: for (int i = 0; i < args.length; i++) {
048: cost += args[i].getCost();
049: }
050: return cost;
051: }
052:
053: public long getPrecision() {
054: return Integer.MAX_VALUE;
055: }
056:
057: public int getDisplaySize() {
058: return Integer.MAX_VALUE;
059: }
060:
061: public int getScale() {
062: return 0;
063: }
064:
065: public String getSQL() {
066: StringBuffer buff = new StringBuffer();
067: buff.append(Parser.quoteIdentifier(userAggregate.getName()));
068: buff.append('(');
069: for (int i = 0; i < args.length; i++) {
070: if (i > 0) {
071: buff.append(", ");
072: }
073: Expression e = args[i];
074: buff.append(e.getSQL());
075: }
076: buff.append(')');
077: return buff.toString();
078: }
079:
080: public int getType() {
081: return dataType;
082: }
083:
084: public boolean isEverything(ExpressionVisitor visitor) {
085: switch (visitor.type) {
086: case ExpressionVisitor.DETERMINISTIC:
087: // TODO optimization: some functions are deterministic, but we don't
088: // know (no setting for that)
089: return false;
090: case ExpressionVisitor.GET_DEPENDENCIES:
091: visitor.addDependency(userAggregate);
092: break;
093: }
094: for (int i = 0; i < args.length; i++) {
095: Expression e = args[i];
096: if (e != null && !e.isEverything(visitor)) {
097: return false;
098: }
099: }
100: return true;
101: }
102:
103: public void mapColumns(ColumnResolver resolver, int level)
104: throws SQLException {
105: for (int i = 0; i < args.length; i++) {
106: args[i].mapColumns(resolver, level);
107: }
108: }
109:
110: public Expression optimize(Session session) throws SQLException {
111: userConnection = session.createConnection(false);
112: argTypes = new int[args.length];
113: for (int i = 0; i < args.length; i++) {
114: Expression expr = args[i];
115: args[i] = expr.optimize(session);
116: argTypes[i] = expr.getType();
117: }
118: aggregate = getInstance();
119: dataType = aggregate.getType(argTypes);
120: return this ;
121: }
122:
123: public void setEvaluatable(TableFilter tableFilter, boolean b) {
124: for (int i = 0; i < args.length; i++) {
125: args[i].setEvaluatable(tableFilter, b);
126: }
127: }
128:
129: private AggregateFunction getInstance() throws SQLException {
130: AggregateFunction agg = userAggregate.getInstance();
131: agg.init(userConnection);
132: return agg;
133: }
134:
135: public Value getValue(Session session) throws SQLException {
136: HashMap group = select.getCurrentGroup();
137: if (group == null) {
138: throw Message.getSQLException(
139: ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1,
140: getSQL());
141: }
142: AggregateFunction agg = (AggregateFunction) group.get(this );
143: if (agg == null) {
144: agg = getInstance();
145: }
146: Object obj = agg.getResult();
147: if (obj == null) {
148: return ValueNull.INSTANCE;
149: } else {
150: return DataType.convertToValue(session, obj, dataType);
151: }
152: }
153:
154: public void updateAggregate(Session session) throws SQLException {
155: HashMap group = select.getCurrentGroup();
156: if (group == null) {
157: // this is a different level (the enclosing query)
158: return;
159: }
160: AggregateFunction agg = (AggregateFunction) group.get(this );
161: if (agg == null) {
162: agg = getInstance();
163: group.put(this , agg);
164: }
165: Object[] argValues = new Object[args.length];
166: Object arg = null;
167: for (int i = 0; i < args.length; i++) {
168: Value v = args[i].getValue(session);
169: v = v.convertTo(argTypes[i]);
170: arg = v.getObject();
171: argValues[i] = arg;
172: }
173: if (args.length == 1) {
174: agg.add(arg);
175: } else {
176: agg.add(argValues);
177: }
178: }
179:
180: }
|