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.jdbc; |
7 | |
8 | import java.sql.Array; |
9 | import java.sql.ResultSet; |
10 | import java.sql.SQLException; |
11 | import java.sql.Types; |
12 | import java.util.Map; |
13 | |
14 | import org.h2.api.ErrorCode; |
15 | import org.h2.message.DbException; |
16 | import org.h2.message.TraceObject; |
17 | import org.h2.tools.SimpleResultSet; |
18 | import org.h2.value.Value; |
19 | |
20 | /** |
21 | * Represents an ARRAY value. |
22 | */ |
23 | public class JdbcArray extends TraceObject implements Array { |
24 | |
25 | private Value value; |
26 | private final JdbcConnection conn; |
27 | |
28 | /** |
29 | * INTERNAL |
30 | */ |
31 | JdbcArray(JdbcConnection conn, Value value, int id) { |
32 | setTrace(conn.getSession().getTrace(), TraceObject.ARRAY, id); |
33 | this.conn = conn; |
34 | this.value = value; |
35 | } |
36 | |
37 | /** |
38 | * Returns the value as a Java array. |
39 | * This method always returns an Object[]. |
40 | * |
41 | * @return the Object array |
42 | */ |
43 | @Override |
44 | public Object getArray() throws SQLException { |
45 | try { |
46 | debugCodeCall("getArray"); |
47 | checkClosed(); |
48 | return get(); |
49 | } catch (Exception e) { |
50 | throw logAndConvert(e); |
51 | } |
52 | } |
53 | |
54 | /** |
55 | * Returns the value as a Java array. |
56 | * This method always returns an Object[]. |
57 | * |
58 | * @param map is ignored. Only empty or null maps are supported |
59 | * @return the Object array |
60 | */ |
61 | @Override |
62 | public Object getArray(Map<String, Class<?>> map) throws SQLException { |
63 | try { |
64 | debugCode("getArray("+quoteMap(map)+");"); |
65 | JdbcConnection.checkMap(map); |
66 | checkClosed(); |
67 | return get(); |
68 | } catch (Exception e) { |
69 | throw logAndConvert(e); |
70 | } |
71 | } |
72 | |
73 | /** |
74 | * Returns the value as a Java array. A subset of the array is returned, |
75 | * starting from the index (1 meaning the first element) and up to the given |
76 | * object count. This method always returns an Object[]. |
77 | * |
78 | * @param index the start index of the subset (starting with 1) |
79 | * @param count the maximum number of values |
80 | * @return the Object array |
81 | */ |
82 | @Override |
83 | public Object getArray(long index, int count) throws SQLException { |
84 | try { |
85 | debugCode("getArray(" + index + ", " + count + ");"); |
86 | checkClosed(); |
87 | return get(index, count); |
88 | } catch (Exception e) { |
89 | throw logAndConvert(e); |
90 | } |
91 | } |
92 | |
93 | /** |
94 | * Returns the value as a Java array. A subset of the array is returned, |
95 | * starting from the index (1 meaning the first element) and up to the given |
96 | * object count. This method always returns an Object[]. |
97 | * |
98 | * @param index the start index of the subset (starting with 1) |
99 | * @param count the maximum number of values |
100 | * @param map is ignored. Only empty or null maps are supported |
101 | * @return the Object array |
102 | */ |
103 | @Override |
104 | public Object getArray(long index, int count, Map<String, Class<?>> map) |
105 | throws SQLException { |
106 | try { |
107 | debugCode("getArray(" + index + ", " + count + ", " + quoteMap(map)+");"); |
108 | checkClosed(); |
109 | JdbcConnection.checkMap(map); |
110 | return get(index, count); |
111 | } catch (Exception e) { |
112 | throw logAndConvert(e); |
113 | } |
114 | } |
115 | |
116 | /** |
117 | * Returns the base type of the array. This database does support mixed type |
118 | * arrays and therefore there is no base type. |
119 | * |
120 | * @return Types.NULL |
121 | */ |
122 | @Override |
123 | public int getBaseType() throws SQLException { |
124 | try { |
125 | debugCodeCall("getBaseType"); |
126 | checkClosed(); |
127 | return Types.NULL; |
128 | } catch (Exception e) { |
129 | throw logAndConvert(e); |
130 | } |
131 | } |
132 | |
133 | /** |
134 | * Returns the base type name of the array. This database does support mixed |
135 | * type arrays and therefore there is no base type. |
136 | * |
137 | * @return "NULL" |
138 | */ |
139 | @Override |
140 | public String getBaseTypeName() throws SQLException { |
141 | try { |
142 | debugCodeCall("getBaseTypeName"); |
143 | checkClosed(); |
144 | return "NULL"; |
145 | } catch (Exception e) { |
146 | throw logAndConvert(e); |
147 | } |
148 | } |
149 | |
150 | /** |
151 | * Returns the value as a result set. |
152 | * The first column contains the index |
153 | * (starting with 1) and the second column the value. |
154 | * |
155 | * @return the result set |
156 | */ |
157 | @Override |
158 | public ResultSet getResultSet() throws SQLException { |
159 | try { |
160 | debugCodeCall("getResultSet"); |
161 | checkClosed(); |
162 | return getResultSet(get(), 0); |
163 | } catch (Exception e) { |
164 | throw logAndConvert(e); |
165 | } |
166 | } |
167 | |
168 | /** |
169 | * Returns the value as a result set. The first column contains the index |
170 | * (starting with 1) and the second column the value. |
171 | * |
172 | * @param map is ignored. Only empty or null maps are supported |
173 | * @return the result set |
174 | */ |
175 | @Override |
176 | public ResultSet getResultSet(Map<String, Class<?>> map) throws SQLException { |
177 | try { |
178 | debugCode("getResultSet("+quoteMap(map)+");"); |
179 | checkClosed(); |
180 | JdbcConnection.checkMap(map); |
181 | return getResultSet(get(), 0); |
182 | } catch (Exception e) { |
183 | throw logAndConvert(e); |
184 | } |
185 | } |
186 | |
187 | /** |
188 | * Returns the value as a result set. The first column contains the index |
189 | * (starting with 1) and the second column the value. A subset of the array |
190 | * is returned, starting from the index (1 meaning the first element) and |
191 | * up to the given object count. |
192 | * |
193 | * @param index the start index of the subset (starting with 1) |
194 | * @param count the maximum number of values |
195 | * @return the result set |
196 | */ |
197 | @Override |
198 | public ResultSet getResultSet(long index, int count) throws SQLException { |
199 | try { |
200 | debugCode("getResultSet("+index+", " + count+");"); |
201 | checkClosed(); |
202 | return getResultSet(get(index, count), index - 1); |
203 | } catch (Exception e) { |
204 | throw logAndConvert(e); |
205 | } |
206 | } |
207 | |
208 | /** |
209 | * Returns the value as a result set. |
210 | * The first column contains the index |
211 | * (starting with 1) and the second column the value. |
212 | * A subset of the array is returned, starting from the index |
213 | * (1 meaning the first element) and up to the given object count. |
214 | * |
215 | * @param index the start index of the subset (starting with 1) |
216 | * @param count the maximum number of values |
217 | * @param map is ignored. Only empty or null maps are supported |
218 | * @return the result set |
219 | */ |
220 | @Override |
221 | public ResultSet getResultSet(long index, int count, |
222 | Map<String, Class<?>> map) throws SQLException { |
223 | try { |
224 | debugCode("getResultSet("+index+", " + count+", " + quoteMap(map)+");"); |
225 | checkClosed(); |
226 | JdbcConnection.checkMap(map); |
227 | return getResultSet(get(index, count), index - 1); |
228 | } catch (Exception e) { |
229 | throw logAndConvert(e); |
230 | } |
231 | } |
232 | |
233 | /** |
234 | * Release all resources of this object. |
235 | */ |
236 | @Override |
237 | public void free() { |
238 | debugCodeCall("free"); |
239 | value = null; |
240 | } |
241 | |
242 | private static ResultSet getResultSet(Object[] array, long offset) { |
243 | SimpleResultSet rs = new SimpleResultSet(); |
244 | rs.addColumn("INDEX", Types.BIGINT, 0, 0); |
245 | // TODO array result set: there are multiple data types possible |
246 | rs.addColumn("VALUE", Types.NULL, 0, 0); |
247 | for (int i = 0; i < array.length; i++) { |
248 | rs.addRow(Long.valueOf(offset + i + 1), array[i]); |
249 | } |
250 | return rs; |
251 | } |
252 | |
253 | private void checkClosed() { |
254 | conn.checkClosed(); |
255 | if (value == null) { |
256 | throw DbException.get(ErrorCode.OBJECT_CLOSED); |
257 | } |
258 | } |
259 | |
260 | private Object[] get() { |
261 | return (Object[]) value.convertTo(Value.ARRAY).getObject(); |
262 | } |
263 | |
264 | private Object[] get(long index, int count) { |
265 | Object[] array = get(); |
266 | if (count < 0 || count > array.length) { |
267 | throw DbException.getInvalidValueException("count (1.." |
268 | + array.length + ")", count); |
269 | } |
270 | if (index < 1 || index > array.length) { |
271 | throw DbException.getInvalidValueException("index (1.." |
272 | + array.length + ")", index); |
273 | } |
274 | Object[] subset = new Object[count]; |
275 | System.arraycopy(array, (int) (index - 1), subset, 0, count); |
276 | return subset; |
277 | } |
278 | |
279 | /** |
280 | * INTERNAL |
281 | */ |
282 | @Override |
283 | public String toString() { |
284 | return value == null ? "null" : |
285 | (getTraceObjectName() + ": " + value.getTraceSQL()); |
286 | } |
287 | } |