diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java index f5674e43d3..9503940d61 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/ColumnMapRowMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,13 +52,12 @@ public class ColumnMapRowMapper implements RowMapper> { public Map mapRow(ResultSet rs, int rowNum) throws SQLException { ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); - Map mapOfColValues = createColumnMap(columnCount); + Map mapOfColumnValues = createColumnMap(columnCount); for (int i = 1; i <= columnCount; i++) { - String key = getColumnKey(JdbcUtils.lookupColumnName(rsmd, i)); - Object obj = getColumnValue(rs, i); - mapOfColValues.put(key, obj); + String column = JdbcUtils.lookupColumnName(rsmd, i); + mapOfColumnValues.putIfAbsent(getColumnKey(column), getColumnValue(rs, i)); } - return mapOfColValues; + return mapOfColumnValues; } /** diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java index 1a26ff5d86..213063271d 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/TableMetaDataContext.java @@ -253,7 +253,7 @@ public class TableMetaDataContext { for (Map.Entry entry : inParameters.entrySet()) { if (column.equalsIgnoreCase(entry.getKey())) { value = entry.getValue(); - // TODO: break; + break; } } } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java index 9490c7653e..936793861d 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java @@ -22,12 +22,14 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -704,10 +706,10 @@ public class JdbcTemplateTests { @Test public void testBatchUpdateWithListOfObjectArrays() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final List ids = new ArrayList<>(); + final List ids = new ArrayList<>(2); ids.add(new Object[] {100}); ids.add(new Object[] {200}); - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); @@ -730,11 +732,11 @@ public class JdbcTemplateTests { @Test public void testBatchUpdateWithListOfObjectArraysPlusTypeInfo() throws Exception { final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?"; - final List ids = new ArrayList<>(); + final List ids = new ArrayList<>(2); ids.add(new Object[] {100}); ids.add(new Object[] {200}); final int[] sqlTypes = new int[] {Types.NUMERIC}; - final int[] rowsAffected = new int[] { 1, 2 }; + final int[] rowsAffected = new int[] {1, 2}; given(this.preparedStatement.executeBatch()).willReturn(rowsAffected); mockDatabaseMetaData(true); @@ -1070,14 +1072,13 @@ public class JdbcTemplateTests { given(this.callableStatement.execute()).willReturn(true); given(this.callableStatement.getUpdateCount()).willReturn(-1); - List params = new ArrayList<>(); - params.add(new SqlReturnResultSet("", (RowCallbackHandler) rs -> { + SqlParameter param = new SqlReturnResultSet("", (RowCallbackHandler) rs -> { throw new InvalidDataAccessApiUsageException(""); - })); + }); this.thrown.expect(InvalidDataAccessApiUsageException.class); try { - this.template.call(conn -> conn.prepareCall("my query"), params); + this.template.call(conn -> conn.prepareCall("my query"), Collections.singletonList(param)); } finally { verify(this.resultSet).close(); @@ -1099,10 +1100,8 @@ public class JdbcTemplateTests { assertTrue("now it should have been set to case insensitive", this.template.isResultsMapCaseInsensitive()); - List params = new ArrayList<>(); - params.add(new SqlOutParameter("a", 12)); - - Map out = this.template.call(conn -> conn.prepareCall("my query"), params); + Map out = this.template.call( + conn -> conn.prepareCall("my query"), Collections.singletonList(new SqlOutParameter("a", 12))); assertThat(out, instanceOf(LinkedCaseInsensitiveMap.class)); assertNotNull("we should have gotten the result with upper case", out.get("A")); @@ -1111,6 +1110,25 @@ public class JdbcTemplateTests { verify(this.connection).close(); } + @Test // SPR-16578 + public void testEquallyNamedColumn() throws SQLException { + given(this.connection.createStatement()).willReturn(this.statement); + + ResultSetMetaData metaData = mock(ResultSetMetaData.class); + given(metaData.getColumnCount()).willReturn(2); + given(metaData.getColumnLabel(1)).willReturn("x"); + given(metaData.getColumnLabel(2)).willReturn("X"); + given(this.resultSet.getMetaData()).willReturn(metaData); + + given(this.resultSet.next()).willReturn(true, false); + given(this.resultSet.getObject(1)).willReturn("first value"); + given(this.resultSet.getObject(2)).willReturn("second value"); + + Map map = this.template.queryForMap("my query"); + assertEquals(1, map.size()); + assertEquals("first value", map.get("x")); + } + private void mockDatabaseMetaData(boolean supportsBatchUpdates) throws SQLException { DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);