Really no luck with this. I figured out that I have to use PGobject. But using an UDT out parameter fails with an exception that cannot be correct. I suspect that there is a bug with either MyBatis or the PG driver. I am running out of time and can't pursue this further.
For types not supported by JDBC, PGobject serializes the types in field order, depth first. The example I used above would look like this: "(4,blah,5.55)".
The type-handler methods for the parameters should be like this (results are similar).
@Override
public void setNonNullParameter( PreparedStatement ps, int columnIndex, Object parameter, JdbcType jdbcType) throws SQLException {
MyJavaType param = (MyJavaType) parameter;
PGobject pgObj = new PGobject();
pgObj.setType( "my_sql_type");
pgObj.setValue( "(" + param.getAnInt() + "," + param.getAString() + "," + param.getANumber() + ")");
ps.setObject( columnIndex, pgObj);
}
@Override
public Object getNullableResult( CallableStatement cs, int columnIndex) throws SQLException {
PGobject pgObj = (PGobject) cs.getObject( columnIndex);
if (! "my_sql_type".equals( pgObj.getType())) throw new SQLException( "invalid object type; expected my_sql_type; got: " + pgObj.getType());
String[] values = pgObj.getValue().substring( 1, pgObj.getValue().length() - 1).split( ",");
param.setAnInt( Integer.valueOf( values[0]);
param.setAString( values[1]);
param.setANumber( Float.valueOf( values[2]);
return (Object) param;
}
Now the exception I get when using the user defined type (UDT) as an out parameter is:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.postgresql.util.PSQLException: A CallableStatement was executed with an invalid number of parameters
### The error may exist in mapper/_test_/FunctionsAndProceduresMapper.xml
### The error may involve com.brocade.dcm.domain.mapper._test_.FunctionsAndProceduresMapper.procWithUdtOut-Inline
### The error occurred while setting parameters
### SQL: { CALL dcmtest.proc_with_udt_out( ? ) }
### Cause: org.postgresql.util.PSQLException: A CallableStatement was executed with an invalid number of parameters
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.ibatis.session.SqlSessionManager$SqlSessionInterceptor.invoke(SqlSessionManager.java:357)
at com.sun.proxy.$Proxy2.selectOne(Unknown Source)
at org.apache.ibatis.session.SqlSessionManager.selectOne(SqlSessionManager.java:166)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:82)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy6.procWithUdtOut(Unknown Source)
at com.brocade.dcm.domain.AdHocDomainTest.testCallingFunctionsAndProcedures(AdHocDomainTest.java:383)
at com.brocade.dcm.domain.AdHocDomainTest.main(AdHocDomainTest.java:95)
Caused by: org.postgresql.util.PSQLException: A CallableStatement was executed with an invalid number of parameters
at org.postgresql.jdbc.PgCallableStatement.executeWithFlags(PgCallableStatement.java:103)
at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:158)
at org.apache.ibatis.executor.statement.CallableStatementHandler.query(CallableStatementHandler.java:67)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:83)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
... 14 more
But I am absolutely sure that everything I did was right.
So, use a UDT return value instead. That is simpler (does not require a type handler).
Roger