ARRAY data type and non-Object[] arrays in JDBC
H2 historically had an array data type without base data type. With recent changes H2 has optional base data type.
On the JDBC level ARRAY data type is mapped to Object[], that violates the JDBC specification. Table B-1 JDBC Types Mapped to Java Types in JDBC 4.3 requires the java.sql.Array.
Released versions of H2 was able to return custom arrays, such as Integer[] if this array was returned by user-defined function, for example. This logic was buggy, because H2 didn't preserve the data type and because H2 didn't generate the elements of the same data type in all cases (conversion to Value and back to Object may change the class), the ArrayStoreException was possible. This logic was removed. Note that JdbcArray.get() methods didn't have it, they returned an Object[] unconditionally and legally, they may return Object[] or custom array, it's implementation-defined.
H2 still able to accept such custom arrays, this issue is only about ResultSet.getObject() and Array.get() methods. Should we return custom arrays when data type is known?
Note that ARRAY literals don't have a base data type in the SQL Standard, only ARRAY data type has (columns, casts, etc.) Anyway, the literals must evaluate their base data type by combination of data types of all elements and cast all of them to it, H2 doesn't do that currently. H2 only can evaluate it when all elements are really have the same type (NULL values are possible too). For example, array literal with INT and BIGINT values is currently considered as array of mixed type.
For example, an empty array or array with only NULL values currently doesn't know its base data type.
It could be recovered from column's data type in the same way as enum data types are recovered, but it requires some additional code.
If we used to return an Object[], then I'm happy that we continue to do so
Yes, the Object[] was always returned when value was read from a persisted table, it was returned from built-in functions, but with direct invocation of user-defined Java function the data type was either the Object[] or a some other depending on the way to read the value from the result set.
When comparing 1.4.200 with 2.1.214 it seems that the JdbcArray#get once delegated to ValueArray#getObject which used
Object[] list = (Object[]) Array.newInstance(componentType, len);
But now JdbcArray#get uses ValueToObjectConverter#valueToDefaultArray which sadly does
Object[] list = new Object[len];
to construct the result. This breaks my MyBatis-Mapper.
java.sql.Array.getArray() implementations may return Object[] according to specification.
Actually you don't need to use java.sql.Array with H2, you can get regular Java array directly:
Connection connection = DriverManager.getConnection("jdbc:h2:mem:1");
Statement s = connection.createStatement();
s.execute("CREATE TABLE A(A INTEGER ARRAY) AS VALUES ARRAY[1, 2, 3]");
ResultSet rs = s.executeQuery("TABLE A");
rs.next();
Integer[] a = rs.getObject(1, Integer[].class);
System.out.println(Arrays.toString(a));
java.sql.Array.getArray() implementations may return Object[] according to specification.
That is correct, i just wanted to point out that h2 used to do it "better". I just thought it is weird that there is a typed array now but in the implementation the typing which was there with the untyped array is lost...