Skip to content

Commit 6576938

Browse files
committed
fixes #493 Apply ResultHandler on REFCURSOR OUT parameters.
1 parent 4abf21f commit 6576938

File tree

6 files changed

+81
-10
lines changed

6 files changed

+81
-10
lines changed

src/main/java/org/apache/ibatis/binding/MapperMethod.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.ibatis.cursor.Cursor;
2121
import org.apache.ibatis.mapping.MappedStatement;
2222
import org.apache.ibatis.mapping.SqlCommandType;
23+
import org.apache.ibatis.mapping.StatementType;
2324
import org.apache.ibatis.reflection.MetaObject;
2425
import org.apache.ibatis.reflection.ParamNameResolver;
2526
import org.apache.ibatis.reflection.TypeParameterResolver;
@@ -113,9 +114,10 @@ private Object rowCountResult(int rowCount) {
113114

114115
private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
115116
MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
116-
if (void.class.equals(ms.getResultMaps().get(0).getType())) {
117-
throw new BindingException("method " + command.getName()
118-
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
117+
if (!StatementType.CALLABLE.equals(ms.getStatementType())
118+
&& void.class.equals(ms.getResultMaps().get(0).getType())) {
119+
throw new BindingException("method " + command.getName()
120+
+ " needs either a @ResultMap annotation, a @ResultType annotation,"
119121
+ " or a resultType attribute in XML so a ResultHandler can be used as a parameter.");
120122
}
121123
Object param = method.convertArgsToSqlCommandParam(args);

src/main/java/org/apache/ibatis/executor/resultset/DefaultResultSetHandler.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,14 @@ private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping param
162162
try {
163163
final String resultMapId = parameterMapping.getResultMapId();
164164
final ResultMap resultMap = configuration.getResultMap(resultMapId);
165-
final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
166165
final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
167-
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
168-
metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
166+
if (this.resultHandler == null) {
167+
final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
168+
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
169+
metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
170+
} else {
171+
handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
172+
}
169173
} finally {
170174
// issue #228 (close resultsets)
171175
closeResultSet(rs);

src/test/java/org/apache/ibatis/submitted/usesjava8/refcursor/CreateDB.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ $BODY$
7878
LANGUAGE plpgsql VOLATILE
7979
COST 100 |
8080

81+
82+
CREATE OR REPLACE FUNCTION mbtest.get_order_out_params(
83+
order_number integer,
84+
detail_count out integer,
85+
header_curs out refcursor
86+
) AS $BODY$
87+
BEGIN
88+
open header_curs for select * from mbtest.order_header where order_id = ORDER_NUMBER;
89+
select count(*) into detail_count from mbtest.order_detail where order_id = ORDER_NUMBER;
90+
END;
91+
$BODY$
92+
LANGUAGE plpgsql VOLATILE
93+
COST 100 |
94+
8195
-- @DELIMITER ;
8296

8397
ALTER FUNCTION mbtest.get_order(integer) OWNER TO postgres;

src/test/java/org/apache/ibatis/submitted/usesjava8/refcursor/OrdersMapper.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717

1818
import java.util.Map;
1919

20+
import org.apache.ibatis.session.ResultHandler;
21+
2022
public interface OrdersMapper {
21-
void getOrder1(Map<String, Object> parameter);
22-
void getOrder2(Map<String, Object> parameter);
23+
void getOrder1(Map<String, Object> parameter);
24+
25+
void getOrder2(Map<String, Object> parameter);
26+
27+
void getOrder3(Map<String, Object> parameter, ResultHandler<Order> resultHandler);
2328
}

src/test/java/org/apache/ibatis/submitted/usesjava8/refcursor/OrdersMapper.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,18 @@
4040
{ #{order,jdbcType=OTHER,mode=OUT,resultMap=org.apache.ibatis.submitted.usesjava8.refcursor.OrdersMapper.OrderResult,javaType=java.sql.ResultSet} =
4141
call mbtest.get_order(#{orderId,jdbcType=INTEGER,mode=IN}) }
4242
</update>
43+
44+
<resultMap id="OrderHeaderResult" type="org.apache.ibatis.submitted.usesjava8.refcursor.Order">
45+
<id property="orderId" column="ORDER_ID"/>
46+
<result property="customerName" column="CUST_NAME" />
47+
</resultMap>
48+
49+
<select id="getOrder3" statementType="CALLABLE">
50+
{ call mbtest.get_order_out_params(
51+
#{orderId,jdbcType=INTEGER,mode=IN},
52+
#{detailCount,jdbcType=INTEGER,mode=OUT,javaType=int},
53+
#{order,jdbcType=OTHER,mode=OUT,resultMap=OrderHeaderResult,javaType=java.sql.ResultSet}
54+
) }
55+
</select>
56+
4357
</mapper>

src/test/java/org/apache/ibatis/submitted/usesjava8/refcursor/RefCursorTest.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
*/
1616
package org.apache.ibatis.submitted.usesjava8.refcursor;
1717

18-
import static org.junit.Assert.assertEquals;
19-
import static org.junit.Assert.assertNotNull;
18+
import static org.junit.Assert.*;
2019

2120
import java.io.IOException;
2221
import java.io.Reader;
2322
import java.nio.file.Paths;
2423
import java.sql.Connection;
24+
import java.util.ArrayList;
2525
import java.util.Collections;
2626
import java.util.HashMap;
2727
import java.util.List;
@@ -32,6 +32,8 @@
3232
import org.apache.ibatis.jdbc.ScriptRunner;
3333
import org.apache.ibatis.mapping.Environment;
3434
import org.apache.ibatis.session.Configuration;
35+
import org.apache.ibatis.session.ResultContext;
36+
import org.apache.ibatis.session.ResultHandler;
3537
import org.apache.ibatis.session.SqlSession;
3638
import org.apache.ibatis.session.SqlSessionFactory;
3739
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
@@ -114,4 +116,34 @@ public void testRefCursor2() throws IOException {
114116
assertEquals(3, order.getDetailLines().size());
115117
}
116118
}
119+
120+
@Test
121+
public void shouldUseResultHandlerOnOutputParam() throws IOException {
122+
class OrderResultHandler implements ResultHandler<Order> {
123+
private List<Order> orders = new ArrayList<Order>();
124+
125+
@Override
126+
public void handleResult(ResultContext<? extends Order> resultContext) {
127+
Order order = resultContext.getResultObject();
128+
order.setCustomerName("Anonymous");
129+
orders.add(order);
130+
}
131+
132+
List<Order> getResult() {
133+
return orders;
134+
}
135+
}
136+
137+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
138+
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
139+
OrderResultHandler handler = new OrderResultHandler();
140+
Map<String, Object> parameter = new HashMap<String, Object>();
141+
parameter.put("orderId", 1);
142+
mapper.getOrder3(parameter, handler);
143+
144+
assertNull(parameter.get("order"));
145+
assertEquals(Integer.valueOf(3), parameter.get("detailCount"));
146+
assertEquals("Anonymous", handler.getResult().get(0).getCustomerName());
147+
}
148+
}
117149
}

0 commit comments

Comments
 (0)