> I wanted to define a function that takes a variable number of object
> arguments
The database thinks you try pass a serialized object, so it tries to
convert the value to a byte array, and then deserialize it into a
java.lang.Object (data type 'OTHER' - see also
http://www.h2database.com/html/datatypes.html#othertype ).
What you want in your case is to _not_ convert the value. This is
currently not supported, and I wonder if it can be supported when
using static methods (and no hacks). Also, the return type is Object.
I guess that means the returned data type is unknown until the method
is called? One workaround is to pass an Object array and return an
Object array. Example:
private void testDynamicArgumentAndReturn() throws SQLException {
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
ResultSet rs;
stat.execute("create alias dynamic deterministic for
\""+getClass().getName()+".dynamic\"");
setCount(0);
rs = stat.executeQuery("call dynamic(('a', 1))[0]");
rs.next();
String a = rs.getString(1);
assertEquals("a1", a);
stat.execute("drop alias dynamic");
conn.close();
}
public static Object[] dynamic(Object[] args) {
StringBuilder buff = new StringBuilder();
for (Object a : args) {
buff.append(a);
}
return new Object[] { buff.toString() };
}
Could you explain what the method does?
> there is not enough information
> so certain sql signatures are not possible.
That's true.
> It seems to me that for functions to be defineable in a completely general way then it
> needs to be possible to define them, as well as by the current method of
> using a static function, by implementing an interface - much like the way
> that aggregate functions are defined.
Yes, that may be a solution. How do you suggest should the Function
interface look like?
Regards,
Thomas
Hi,
> I wanted to define a function that takes a variable number of object
> arguments
What you want in your case is to _not_ convert the value. This is
currently not supported, and I wonder if it can be supported when
using static methods (and no hacks). Also, the return type is Object.
I guess that means the returned data type is unknown until the method
is called? One workaround is to pass an Object array and return an
Object array. Example:
private void testDynamicArgumentAndReturn() throws SQLException {
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
ResultSet rs;
stat.execute("create alias dynamic deterministic for
\""+getClass().getName()+".dynamic\"");
setCount(0);
rs = stat.executeQuery("call dynamic(('a', 1))[0]");
rs.next();
String a = rs.getString(1);
assertEquals("a1", a);
stat.execute("drop alias dynamic");
conn.close();
}
public static Object[] dynamic(Object[] args) {
StringBuilder buff = new StringBuilder();
for (Object a : args) {
buff.append(a);
}
return new Object[] { buff.toString() };
}
> there is not enough information
> so certain sql signatures are not possible.
> I've run into some confusions as well about type handling in user-
> defined functions, and from this post and others, I'm probably not the
> only one.
> Would it be possible to add more to the documentation on the subject
> about user-defined functions?
Yes, what about if I add the following here:
http://www.h2database.com/html/features.html#user_defined_functions
"SQL types are mapped to Java classes and vice-versa as in the JDBC
API. For details, see <a href="datatypes.html">Data Types</a>. There
are two special cases: java.lang.Object is mapped to OTHER (a
serialized object). Therefore, Object can not be used to match all SQL
types. The second special case is Object[]: Arrays of any class are
mapped to ARRAY."
I will expand the data type documentation to include mappings to Java
types, such as:
DECIMAL: Mapped to java.math.BigDecimal.
BINARY: Mapped to byte[].
OTHER: Mapped to java.lang.Object (or any subclass).
BLOB: Mapped to java.sql.Blob (java.io.InputStream is also supported).
ARRAY: Mapped to java.lang.Object[] (arrays of any non-primitive type
are also supported).
> a few more words on user
> ResultSets
This is already documented at
http://www.h2database.com/html/features.html#user_defined_functions -
"Functions returning a Result Set".
> Can/should I pass java.sql.Blob or byte[] or input streams to
> something expecting a BLOB or BINARY type?
java.sql.Blob for BLOB, byte[] for BINARY.
> What about functions needing to take BLOB as input?
I don't understand the question.
> Which objects can be used with functions expecting TIME/DATE/TIMESTAMP
> objects (besides the java.sql.TimeStamp, etc)?
See above.
> Which of the java.lang.* and java.sql.* Objects will be implicitly
> converted to something besides OTHER if possible?
See above.
> How can I build & return a more full-featured or disk-paged ResultSet
> from a procedure, for accumulating large results from a stored
> procedure operating on tables, which may not fit in RAM?
SimpleResultSet supports streaming, unfortunately the constructor
SimpleResultSet(SimpleRowSource source) is not documented curently at
http://www.h2database.com/javadoc/org/h2/tools/SimpleResultSet.html -
I will fix that.
Regards,
Thomas
> I know it
> excludes the string parsing
> conversions (I've seen a couple) and implicit type conversions
> applied within SQL-only
> statements.
The best place to document this is probably the CAST(..) function. I
will extend the documentation of CAST:
"Converts a value to another data type. When converting a text to a
number, the default Java conversion
rules are used (prefixes 0x or # for hexadecimal numbers, prefix 0 for
octal numbers)."
That's a start, but much more is required.
> I'm kind of surprised that BLOBs can't accept byte[]
It can (data is converted automatically).
Regards,
Thomas