1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.engine; |
7 | |
8 | import java.sql.Connection; |
9 | import java.sql.SQLException; |
10 | |
11 | import org.h2.api.Aggregate; |
12 | import org.h2.api.AggregateFunction; |
13 | import org.h2.command.Parser; |
14 | import org.h2.message.DbException; |
15 | import org.h2.message.Trace; |
16 | import org.h2.table.Table; |
17 | import org.h2.util.JdbcUtils; |
18 | import org.h2.value.DataType; |
19 | |
20 | /** |
21 | * Represents a user-defined aggregate function. |
22 | */ |
23 | public class UserAggregate extends DbObjectBase { |
24 | |
25 | private String className; |
26 | private Class<?> javaClass; |
27 | |
28 | public UserAggregate(Database db, int id, String name, String className, |
29 | boolean force) { |
30 | initDbObjectBase(db, id, name, Trace.FUNCTION); |
31 | this.className = className; |
32 | if (!force) { |
33 | getInstance(); |
34 | } |
35 | } |
36 | |
37 | public Aggregate getInstance() { |
38 | if (javaClass == null) { |
39 | javaClass = JdbcUtils.loadUserClass(className); |
40 | } |
41 | Object obj; |
42 | try { |
43 | obj = javaClass.newInstance(); |
44 | Aggregate agg; |
45 | if (obj instanceof Aggregate) { |
46 | agg = (Aggregate) obj; |
47 | } else { |
48 | agg = new AggregateWrapper((AggregateFunction) obj); |
49 | } |
50 | return agg; |
51 | } catch (Exception e) { |
52 | throw DbException.convert(e); |
53 | } |
54 | } |
55 | |
56 | @Override |
57 | public String getCreateSQLForCopy(Table table, String quotedName) { |
58 | throw DbException.throwInternalError(); |
59 | } |
60 | |
61 | @Override |
62 | public String getDropSQL() { |
63 | return "DROP AGGREGATE IF EXISTS " + getSQL(); |
64 | } |
65 | |
66 | @Override |
67 | public String getCreateSQL() { |
68 | return "CREATE FORCE AGGREGATE " + getSQL() + |
69 | " FOR " + Parser.quoteIdentifier(className); |
70 | } |
71 | |
72 | @Override |
73 | public int getType() { |
74 | return DbObject.AGGREGATE; |
75 | } |
76 | |
77 | @Override |
78 | public synchronized void removeChildrenAndResources(Session session) { |
79 | database.removeMeta(session, getId()); |
80 | className = null; |
81 | javaClass = null; |
82 | invalidate(); |
83 | } |
84 | |
85 | @Override |
86 | public void checkRename() { |
87 | throw DbException.getUnsupportedException("AGGREGATE"); |
88 | } |
89 | |
90 | public String getJavaClassName() { |
91 | return this.className; |
92 | } |
93 | |
94 | /** |
95 | * Wrap {@link AggregateFunction} in order to behave as |
96 | * {@link org.h2.api.Aggregate} |
97 | **/ |
98 | private static class AggregateWrapper implements Aggregate { |
99 | private final AggregateFunction aggregateFunction; |
100 | |
101 | AggregateWrapper(AggregateFunction aggregateFunction) { |
102 | this.aggregateFunction = aggregateFunction; |
103 | } |
104 | |
105 | @Override |
106 | public void init(Connection conn) throws SQLException { |
107 | aggregateFunction.init(conn); |
108 | } |
109 | |
110 | @Override |
111 | public int getInternalType(int[] inputTypes) throws SQLException { |
112 | int[] sqlTypes = new int[inputTypes.length]; |
113 | for (int i = 0; i < inputTypes.length; i++) { |
114 | sqlTypes[i] = DataType.convertTypeToSQLType(inputTypes[i]); |
115 | } |
116 | return DataType.convertSQLTypeToValueType(aggregateFunction.getType(sqlTypes)); |
117 | } |
118 | |
119 | @Override |
120 | public void add(Object value) throws SQLException { |
121 | aggregateFunction.add(value); |
122 | } |
123 | |
124 | @Override |
125 | public Object getResult() throws SQLException { |
126 | return aggregateFunction.getResult(); |
127 | } |
128 | } |
129 | |
130 | } |