提交 0381d824 authored 作者: Thomas Mueller's avatar Thomas Mueller

Java functions: array component types are now preserved, so that a…

Java functions: array component types are now preserved, so that a ResultSet.getObject() will return Integer[] if the Java functions returns Integer[]. Thanks to Noel Grandin for the patch.
上级 7501daeb
......@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>Recover tool: the script generated by the recover tool didn't work
<ul><li>Java functions: array component types are now preserved, so that a ResultSet.getObject()
will return Integer[] if the Java functions returns Integer[]. Thanks to Noel Grandin for the patch.
</li><li>Recover tool: the script generated by the recover tool didn't work
if fulltext search was used, because the triggers were created before the primary keys.
</li><li>Issue 321: the database does not expect XA rollback without XA prepare
(an exception was unnecessarily written into the .trace.db file).
......
......@@ -30,6 +30,7 @@ import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueNull;
/**
......@@ -352,6 +353,14 @@ public class FunctionAlias extends SchemaObjectBase {
Object o;
if (Value.class.isAssignableFrom(paramClass)) {
o = v;
} else if (v.getType() == Value.ARRAY && paramClass.isArray() && paramClass.getComponentType() != Object.class) {
Value[] array = ((ValueArray) v).getList();
Object[] objArray = (Object[]) Array.newInstance(paramClass.getComponentType(), array.length);
int componentType = DataType.getTypeFromClass(paramClass.getComponentType());
for (int i = 0; i < objArray.length; i++) {
objArray[i] = array[i].convertTo(componentType).getObject();
}
o = objArray;
} else {
v = v.convertTo(type);
o = v.getObject();
......
......@@ -917,7 +917,7 @@ public class DataType {
for (int i = 0; i < len; i++) {
v[i] = convertToValue(session, o[i], type);
}
return ValueArray.get(v);
return ValueArray.get(x.getClass().getComponentType(), v);
} else if (x instanceof Character) {
return ValueStringFixed.get(((Character) x).toString());
} else {
......
......@@ -6,6 +6,7 @@
*/
package org.h2.value;
import java.lang.reflect.Array;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import org.h2.engine.Constants;
......@@ -18,13 +19,19 @@ import org.h2.util.StatementBuilder;
*/
public class ValueArray extends Value {
private final Class<?> componentType;
private final Value[] values;
private int hash;
private ValueArray(Value[] list) {
private ValueArray(Class<?> componentType, Value[] list) {
this.componentType = componentType;
this.values = list;
}
private ValueArray(Value[] list) {
this(Object.class, list);
}
/**
* Get or create a array value for the given value array.
* Do not clone the data.
......@@ -36,6 +43,17 @@ public class ValueArray extends Value {
return new ValueArray(list);
}
/**
* Get or create a array value for the given value array.
* Do not clone the data.
*
* @param list the value array
* @return the value
*/
public static ValueArray get(Class<?> componentType, Value[] list) {
return new ValueArray(componentType, list);
}
public int hashCode() {
if (hash != 0) {
return hash;
......@@ -56,6 +74,10 @@ public class ValueArray extends Value {
return Value.ARRAY;
}
public Class<?> getComponentType() {
return componentType;
}
public long getPrecision() {
long p = 0;
for (Value v : values) {
......@@ -94,7 +116,7 @@ public class ValueArray extends Value {
public Object getObject() {
int len = values.length;
Object[] list = new Object[len];
Object[] list = (Object[]) Array.newInstance(componentType, len);
for (int i = 0; i < len; i++) {
list[i] = values[i].getObject();
}
......
......@@ -578,6 +578,30 @@ public abstract class TestBase {
}
}
/**
* Check if two values are equal, and if not throw an exception.
*
* @param expected the expected value
* @param actual the actual value
* @throws AssertionError if the values are not equal
*/
public void assertEquals(Object[] expected, Object[] actual) {
if (expected == null || actual == null) {
assertTrue(expected == actual);
return;
}
assertEquals(expected.length, actual.length);
for (int i = 0; i < expected.length; i++) {
if (expected[i] == null || actual[i] == null) {
if (expected[i] != actual[i]) {
fail("[" + i + "]: expected: " + expected[i] + " actual: " + actual[i]);
}
} else if (!expected[i].equals(actual[i])) {
fail("[" + i + "]: expected: " + expected[i] + " actual: " + actual[i]);
}
}
}
/**
* Check if two readers are equal, and if not throw an exception.
*
......
......@@ -13,6 +13,7 @@ import java.io.OutputStream;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
......@@ -50,6 +51,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
public void test() throws Exception {
deleteDb("functions");
testArrayParameters();
testDefaultConnection();
testFunctionInSchema();
testGreatest();
......@@ -731,6 +733,33 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close();
}
private void testArrayParameters() throws SQLException {
deleteDb("functions");
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
ResultSet rs;
stat.execute("create alias array_test AS "
+ "$$ Integer[] array_test(Integer[] in_array) "
+ "{ return in_array; } $$;");
PreparedStatement stmt = conn.prepareStatement("select array_test(?) from dual");
stmt.setObject(1, new Integer[] { 1, 2 });
rs = stmt.executeQuery();
rs.next();
assertEquals(Integer[].class.getName(), rs.getObject(1).getClass().getName());
CallableStatement call = conn.prepareCall("{ ? = call array_test(?) }");
call.setObject(2, new Integer[] { 2, 1 });
call.registerOutParameter(1, Types.ARRAY);
call.execute();
assertEquals(Integer[].class.getName(), call.getArray(1).getArray().getClass().getName());
assertEquals(new Integer[] { 2, 1 }, (Integer[]) call.getObject(1));
stat.execute("drop alias array_test");
conn.close();
}
private void assertCallResult(String expected, Statement stat, String sql) throws SQLException {
ResultSet rs = stat.executeQuery("CALL " + sql);
rs.next();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论