Skip to content

Commit 9e19efc

Browse files
committed
Closes #22. Lost rows when handling an unordered join with a RowHandler
1 parent b503776 commit 9e19efc

File tree

4 files changed

+73
-14
lines changed

4 files changed

+73
-14
lines changed

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

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

1818
import java.sql.ResultSet;
1919
import java.sql.SQLException;
20+
import java.util.ArrayList;
2021
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.Locale;
@@ -44,6 +45,7 @@ public class NestedResultSetHandler extends FastResultSetHandler {
4445

4546
private final Map<CacheKey, Object> objectCache = new HashMap<CacheKey, Object>();
4647
private final Map<CacheKey, Object> ancestorCache = new HashMap<CacheKey, Object>();
48+
private final List<Object> unsortedRowHandlerElements = new ArrayList<Object>();
4749

4850
public NestedResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql, RowBounds rowBounds) {
4951
super(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
@@ -67,6 +69,7 @@ private void ensureNoRowBounds(RowBounds rowBounds) {
6769
protected void cleanUpAfterHandlingResultSet() {
6870
super.cleanUpAfterHandlingResultSet();
6971
objectCache.clear();
72+
unsortedRowHandlerElements.clear();
7073
}
7174

7275
//
@@ -82,13 +85,26 @@ protected void handleRowValues(ResultSet rs, ResultMap resultMap, ResultHandler
8285
final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rs, resultMap, null);
8386
final CacheKey rowKey = createRowKey(discriminatedResultMap, rs, null, resultColumnCache);
8487
Object partialObject = objectCache.get(rowKey);
85-
if (partialObject == null && rowValue != null) { // issue #542 delay calling ResultHandler until object ends
86-
if (mappedStatement.isResultOrdered()) objectCache.clear(); // issue #577 clear memory if ordered
87-
callResultHandler(resultHandler, resultContext, rowValue);
88-
}
89-
rowValue = getRowValue(rs, discriminatedResultMap, rowKey, rowKey, null, resultColumnCache, partialObject);
88+
if (mappedStatement.isResultOrdered()) { // issue #577
89+
if (partialObject == null && rowValue != null) {
90+
objectCache.clear();
91+
callResultHandler(resultHandler, resultContext, rowValue);
92+
}
93+
rowValue = getRowValue(rs, discriminatedResultMap, rowKey, rowKey, null, resultColumnCache, partialObject);
94+
} else {
95+
rowValue = getRowValue(rs, discriminatedResultMap, rowKey, rowKey, null, resultColumnCache, partialObject);
96+
if (partialObject == null) {
97+
unsortedRowHandlerElements.add(rowValue); // issue #542
98+
}
99+
}
100+
}
101+
if (mappedStatement.isResultOrdered()) {
102+
if (rowValue != null) callResultHandler(resultHandler, resultContext, rowValue);
103+
} else {
104+
for (Object o : unsortedRowHandlerElements) {
105+
callResultHandler(resultHandler, resultContext, o);
106+
}
90107
}
91-
if (rowValue != null) callResultHandler(resultHandler, resultContext, rowValue);
92108
}
93109

94110
//

src/test/java/org/apache/ibatis/submitted/nestedresulthandler/Mapper.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@
1919

2020
public interface Mapper {
2121
List<Person> getPersons();
22+
List<Person> getPersonsWithItemsOrdered();
2223
}

src/test/java/org/apache/ibatis/submitted/nestedresulthandler/Mapper.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,15 @@
2929
</resultMap>
3030

3131
<select id="getPersons" resultMap="personResult">
32-
select p.id as person_id, p.name as person_name, i.id as item_id, i.name as item_name
33-
from persons p, items i
32+
select p.id as person_id, p.name as person_name, i.id as item_id, i.name as item_name
33+
from persons p, items i
3434
where p.id = i.owner
3535
</select>
36-
</mapper>
36+
37+
<select id="getPersonsWithItemsOrdered" resultMap="personResult">
38+
select p.id as person_id, p.name as person_name, i.id as item_id, i.name as item_name
39+
from persons p, items i
40+
where p.id = i.owner
41+
order by i.name
42+
</select>
43+
</mapper>

src/test/java/org/apache/ibatis/submitted/nestedresulthandler/NestedResultHandlerTest.java

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public void testGetPerson() {
5858
Mapper mapper = sqlSession.getMapper(Mapper.class);
5959

6060
List<Person> persons = mapper.getPersons();
61-
61+
6262
Person person = persons.get(0);
6363
Assert.assertEquals("grandma", person.getName());
6464
Assert.assertTrue(person.owns("book"));
@@ -79,8 +79,9 @@ public void testGetPerson() {
7979
sqlSession.close();
8080
}
8181
}
82-
83-
@Test // issue #542
82+
83+
@Test
84+
// issue #542
8485
public void testGetPersonWithHandler() {
8586
SqlSession sqlSession = sqlSessionFactory.openSession();
8687
try {
@@ -91,10 +92,44 @@ public void handleResult(ResultContext context) {
9192
Assert.assertEquals(2, person.getItems().size());
9293
}
9394
}
94-
});
95+
});
9596
} finally {
9697
sqlSession.close();
9798
}
9899
}
99-
100+
101+
/**
102+
* Fix bug caused by issue #542, see new issue #22 on github If we order by a
103+
* nested result map attribute we can miss some records and end up with
104+
* duplicates instead.
105+
*/
106+
@Test
107+
public void testGetPersonOrderedByItem() {
108+
SqlSession sqlSession = sqlSessionFactory.openSession();
109+
try {
110+
Mapper mapper = sqlSession.getMapper(Mapper.class);
111+
112+
List<Person> persons = mapper.getPersonsWithItemsOrdered();
113+
114+
Person person = persons.get(0);
115+
Assert.assertEquals("grandma", person.getName());
116+
Assert.assertTrue(person.owns("book"));
117+
Assert.assertTrue(person.owns("tv"));
118+
Assert.assertEquals(2, person.getItems().size());
119+
120+
person = persons.get(1);
121+
Assert.assertEquals("brother", person.getName());
122+
Assert.assertTrue(person.owns("car"));
123+
Assert.assertEquals(1, person.getItems().size());
124+
125+
person = persons.get(2);
126+
Assert.assertEquals("sister", person.getName());
127+
Assert.assertTrue(person.owns("phone"));
128+
Assert.assertTrue(person.owns("shoes"));
129+
Assert.assertEquals(2, person.getItems().size());
130+
} finally {
131+
sqlSession.close();
132+
}
133+
}
134+
100135
}

0 commit comments

Comments
 (0)