Skip to content

Commit c84f858

Browse files
committed
fixes #1523 Better error message when too many keys are generated
1 parent f73e5d3 commit c84f858

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

src/main/java/org/apache/ibatis/executor/keygen/Jdbc3KeyGenerator.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public class Jdbc3KeyGenerator implements KeyGenerator {
5454
*/
5555
public static final Jdbc3KeyGenerator INSTANCE = new Jdbc3KeyGenerator();
5656

57+
private static final String MSG_TOO_MANY_KEYS = "Too many keys are generated. There are only %d target objects. "
58+
+ "You either specified a wrong 'keyProperty' or encountered a driver bug like #1523.";
59+
5760
@Override
5861
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
5962
// do nothing
@@ -110,6 +113,9 @@ private void assignKeysToParam(Configuration configuration, ResultSet rs, Result
110113
}
111114
Iterator<?> iterator = params.iterator();
112115
while (rs.next()) {
116+
if (!iterator.hasNext()) {
117+
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, params.size()));
118+
}
113119
Object param = iterator.next();
114120
assignerList.forEach(x -> x.assign(rs, param));
115121
}
@@ -119,7 +125,11 @@ private void assignKeysToParamMapList(Configuration configuration, ResultSet rs,
119125
String[] keyProperties, ArrayList<ParamMap<?>> paramMapList) throws SQLException {
120126
Iterator<ParamMap<?>> iterator = paramMapList.iterator();
121127
List<KeyAssigner> assignerList = new ArrayList<>();
128+
long counter = 0;
122129
while (rs.next()) {
130+
if (!iterator.hasNext()) {
131+
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
132+
}
123133
ParamMap<?> paramMap = iterator.next();
124134
if (assignerList.isEmpty()) {
125135
for (int i = 0; i < keyProperties.length; i++) {
@@ -129,6 +139,7 @@ private void assignKeysToParamMapList(Configuration configuration, ResultSet rs,
129139
}
130140
}
131141
assignerList.forEach(x -> x.assign(rs, paramMap));
142+
counter++;
132143
}
133144
}
134145

@@ -145,11 +156,16 @@ private void assignKeysToParamMap(Configuration configuration, ResultSet rs, Res
145156
k -> entry(collectionize(paramMap.get(k)).iterator(), new ArrayList<>()));
146157
iteratorPair.getValue().add(entry.getValue());
147158
}
159+
long counter = 0;
148160
while (rs.next()) {
149161
for (Entry<Iterator<?>, List<KeyAssigner>> pair : assignerMap.values()) {
162+
if (!pair.getKey().hasNext()) {
163+
throw new ExecutorException(String.format(MSG_TOO_MANY_KEYS, counter));
164+
}
150165
Object param = pair.getKey().next();
151166
pair.getValue().forEach(x -> x.assign(rs, param));
152167
}
168+
counter++;
153169
}
154170
}
155171

src/test/java/org/apache/ibatis/submitted/keygen/CountryMapper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,13 @@ int insertMultiParams_keyPropertyWithWrongParamName(@Param("country") Country co
9191
@Options(useGeneratedKeys = true, keyProperty = "planet.id,map.code")
9292
@Insert({ "insert into planet (name) values (#{planet.name})" })
9393
int insertAssignKeysToTwoParams(@Param("planet") Planet planet, @Param("map") Map<String, Object> map);
94+
95+
96+
@Options(useGeneratedKeys = true, keyProperty = "id")
97+
@Insert({ "insert into country (countryname,countrycode) values ('a','A'), ('b', 'B')" })
98+
int tooManyGeneratedKeys(Country country);
99+
100+
@Options(useGeneratedKeys = true, keyProperty = "country.id")
101+
@Insert({ "insert into country (countryname,countrycode) values ('a','A'), ('b', 'B')" })
102+
int tooManyGeneratedKeysParamMap(@Param("country") Country country, @Param("someId") Integer someId);
94103
}

src/test/java/org/apache/ibatis/submitted/keygen/Jdbc3KeyGeneratorTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,4 +512,48 @@ void shouldErrorUndefineProperty() {
512512
}
513513
}
514514
}
515+
516+
@Test
517+
void shouldFailIfTooManyGeneratedKeys() {
518+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
519+
try {
520+
CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
521+
when(mapper).tooManyGeneratedKeys(new Country());
522+
then(caughtException()).isInstanceOf(PersistenceException.class).hasMessageContaining(
523+
"Too many keys are generated. There are only 1 target objects.");
524+
} finally {
525+
sqlSession.rollback();
526+
}
527+
}
528+
}
529+
530+
@Test
531+
void shouldFailIfTooManyGeneratedKeys_ParamMap() {
532+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
533+
try {
534+
CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
535+
when(mapper).tooManyGeneratedKeysParamMap(new Country(), 1);
536+
then(caughtException()).isInstanceOf(PersistenceException.class).hasMessageContaining(
537+
"Too many keys are generated. There are only 1 target objects.");
538+
} finally {
539+
sqlSession.rollback();
540+
}
541+
}
542+
}
543+
544+
@Test
545+
void shouldFailIfTooManyGeneratedKeys_Batch() {
546+
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
547+
try {
548+
CountryMapper mapper = sqlSession.getMapper(CountryMapper.class);
549+
mapper.tooManyGeneratedKeysParamMap(new Country(), 1);
550+
mapper.tooManyGeneratedKeysParamMap(new Country(), 1);
551+
when(sqlSession).flushStatements();
552+
then(caughtException()).isInstanceOf(PersistenceException.class).hasMessageContaining(
553+
"Too many keys are generated. There are only 2 target objects.");
554+
} finally {
555+
sqlSession.rollback();
556+
}
557+
}
558+
}
515559
}

0 commit comments

Comments
 (0)