Skip to content

Commit 7bce750

Browse files
committed
JdbcTemplate consistently exposes first value of equally named columns
Issue: SPR-16578
1 parent b790bd1 commit 7bce750

File tree

3 files changed

+36
-19
lines changed

3 files changed

+36
-19
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -52,13 +52,12 @@ public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {
5252
public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
5353
ResultSetMetaData rsmd = rs.getMetaData();
5454
int columnCount = rsmd.getColumnCount();
55-
Map<String, Object> mapOfColValues = createColumnMap(columnCount);
55+
Map<String, Object> mapOfColumnValues = createColumnMap(columnCount);
5656
for (int i = 1; i <= columnCount; i++) {
57-
String key = getColumnKey(JdbcUtils.lookupColumnName(rsmd, i));
58-
Object obj = getColumnValue(rs, i);
59-
mapOfColValues.put(key, obj);
57+
String column = JdbcUtils.lookupColumnName(rsmd, i);
58+
mapOfColumnValues.putIfAbsent(getColumnKey(column), getColumnValue(rs, i));
6059
}
61-
return mapOfColValues;
60+
return mapOfColumnValues;
6261
}
6362

6463
/**

spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ public List<Object> matchInParameterValuesWithInsertColumns(Map<String, ?> inPar
253253
for (Map.Entry<String, ?> entry : inParameters.entrySet()) {
254254
if (column.equalsIgnoreCase(entry.getKey())) {
255255
value = entry.getValue();
256-
// TODO: break;
256+
break;
257257
}
258258
}
259259
}

spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
import java.sql.DatabaseMetaData;
2323
import java.sql.PreparedStatement;
2424
import java.sql.ResultSet;
25+
import java.sql.ResultSetMetaData;
2526
import java.sql.SQLException;
2627
import java.sql.SQLWarning;
2728
import java.sql.Statement;
2829
import java.sql.Types;
2930
import java.util.ArrayList;
3031
import java.util.Arrays;
32+
import java.util.Collections;
3133
import java.util.LinkedList;
3234
import java.util.List;
3335
import java.util.Map;
@@ -704,10 +706,10 @@ public int getBatchSize() {
704706
@Test
705707
public void testBatchUpdateWithListOfObjectArrays() throws Exception {
706708
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
707-
final List<Object[]> ids = new ArrayList<>();
709+
final List<Object[]> ids = new ArrayList<>(2);
708710
ids.add(new Object[] {100});
709711
ids.add(new Object[] {200});
710-
final int[] rowsAffected = new int[] { 1, 2 };
712+
final int[] rowsAffected = new int[] {1, 2};
711713

712714
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
713715
mockDatabaseMetaData(true);
@@ -730,11 +732,11 @@ public void testBatchUpdateWithListOfObjectArrays() throws Exception {
730732
@Test
731733
public void testBatchUpdateWithListOfObjectArraysPlusTypeInfo() throws Exception {
732734
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
733-
final List<Object[]> ids = new ArrayList<>();
735+
final List<Object[]> ids = new ArrayList<>(2);
734736
ids.add(new Object[] {100});
735737
ids.add(new Object[] {200});
736738
final int[] sqlTypes = new int[] {Types.NUMERIC};
737-
final int[] rowsAffected = new int[] { 1, 2 };
739+
final int[] rowsAffected = new int[] {1, 2};
738740

739741
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
740742
mockDatabaseMetaData(true);
@@ -1070,14 +1072,13 @@ public void testExecuteClosed() throws Exception {
10701072
given(this.callableStatement.execute()).willReturn(true);
10711073
given(this.callableStatement.getUpdateCount()).willReturn(-1);
10721074

1073-
List<SqlParameter> params = new ArrayList<>();
1074-
params.add(new SqlReturnResultSet("", (RowCallbackHandler) rs -> {
1075+
SqlParameter param = new SqlReturnResultSet("", (RowCallbackHandler) rs -> {
10751076
throw new InvalidDataAccessApiUsageException("");
1076-
}));
1077+
});
10771078

10781079
this.thrown.expect(InvalidDataAccessApiUsageException.class);
10791080
try {
1080-
this.template.call(conn -> conn.prepareCall("my query"), params);
1081+
this.template.call(conn -> conn.prepareCall("my query"), Collections.singletonList(param));
10811082
}
10821083
finally {
10831084
verify(this.resultSet).close();
@@ -1099,10 +1100,8 @@ public void testCaseInsensitiveResultsMap() throws Exception {
10991100
assertTrue("now it should have been set to case insensitive",
11001101
this.template.isResultsMapCaseInsensitive());
11011102

1102-
List<SqlParameter> params = new ArrayList<>();
1103-
params.add(new SqlOutParameter("a", 12));
1104-
1105-
Map<String, Object> out = this.template.call(conn -> conn.prepareCall("my query"), params);
1103+
Map<String, Object> out = this.template.call(
1104+
conn -> conn.prepareCall("my query"), Collections.singletonList(new SqlOutParameter("a", 12)));
11061105

11071106
assertThat(out, instanceOf(LinkedCaseInsensitiveMap.class));
11081107
assertNotNull("we should have gotten the result with upper case", out.get("A"));
@@ -1111,6 +1110,25 @@ public void testCaseInsensitiveResultsMap() throws Exception {
11111110
verify(this.connection).close();
11121111
}
11131112

1113+
@Test // SPR-16578
1114+
public void testEquallyNamedColumn() throws SQLException {
1115+
given(this.connection.createStatement()).willReturn(this.statement);
1116+
1117+
ResultSetMetaData metaData = mock(ResultSetMetaData.class);
1118+
given(metaData.getColumnCount()).willReturn(2);
1119+
given(metaData.getColumnLabel(1)).willReturn("x");
1120+
given(metaData.getColumnLabel(2)).willReturn("X");
1121+
given(this.resultSet.getMetaData()).willReturn(metaData);
1122+
1123+
given(this.resultSet.next()).willReturn(true, false);
1124+
given(this.resultSet.getObject(1)).willReturn("first value");
1125+
given(this.resultSet.getObject(2)).willReturn("second value");
1126+
1127+
Map<String, Object> map = this.template.queryForMap("my query");
1128+
assertEquals(1, map.size());
1129+
assertEquals("first value", map.get("x"));
1130+
}
1131+
11141132

11151133
private void mockDatabaseMetaData(boolean supportsBatchUpdates) throws SQLException {
11161134
DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);

0 commit comments

Comments
 (0)