/*
 * Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.engine;

import java.sql.Connection;
import java.sql.SQLException;
import org.h2.api.Aggregate;
import org.h2.api.AggregateFunction;
import org.h2.command.Parser;
import org.h2.message.DbException;
import org.h2.message.Trace;
import org.h2.table.Table;
import org.h2.util.JdbcUtils;
import org.h2.value.DataType;

Represents a user-defined aggregate function.
/** * Represents a user-defined aggregate function. */
public class UserAggregate extends DbObjectBase { private String className; private Class<?> javaClass; public UserAggregate(Database db, int id, String name, String className, boolean force) { super(db, id, name, Trace.FUNCTION); this.className = className; if (!force) { getInstance(); } } public Aggregate getInstance() { if (javaClass == null) { javaClass = JdbcUtils.loadUserClass(className); } Object obj; try { obj = javaClass.getDeclaredConstructor().newInstance(); Aggregate agg; if (obj instanceof Aggregate) { agg = (Aggregate) obj; } else { agg = new AggregateWrapper((AggregateFunction) obj); } return agg; } catch (Exception e) { throw DbException.convert(e); } } @Override public String getCreateSQLForCopy(Table table, String quotedName) { throw DbException.throwInternalError(toString()); } @Override public String getDropSQL() { StringBuilder builder = new StringBuilder("DROP AGGREGATE IF EXISTS "); return getSQL(builder, true).toString(); } @Override public String getCreateSQL() { StringBuilder builder = new StringBuilder("CREATE FORCE AGGREGATE "); getSQL(builder, true).append(" FOR "); Parser.quoteIdentifier(builder, className, true); return builder.toString(); } @Override public int getType() { return DbObject.AGGREGATE; } @Override public synchronized void removeChildrenAndResources(Session session) { database.removeMeta(session, getId()); className = null; javaClass = null; invalidate(); } @Override public void checkRename() { throw DbException.getUnsupportedException("AGGREGATE"); } public String getJavaClassName() { return this.className; }
Wrap AggregateFunction in order to behave as Aggregate
/** * Wrap {@link AggregateFunction} in order to behave as * {@link org.h2.api.Aggregate} **/
private static class AggregateWrapper implements Aggregate { private final AggregateFunction aggregateFunction; AggregateWrapper(AggregateFunction aggregateFunction) { this.aggregateFunction = aggregateFunction; } @Override public void init(Connection conn) throws SQLException { aggregateFunction.init(conn); } @Override public int getInternalType(int[] inputTypes) throws SQLException { int[] sqlTypes = new int[inputTypes.length]; for (int i = 0; i < inputTypes.length; i++) { sqlTypes[i] = DataType.convertTypeToSQLType(inputTypes[i]); } return DataType.convertSQLTypeToValueType(aggregateFunction.getType(sqlTypes)); } @Override public void add(Object value) throws SQLException { aggregateFunction.add(value); } @Override public Object getResult() throws SQLException { return aggregateFunction.getResult(); } } }