Browse Source

Polishing.

Correctly assign SQL type for tuples.

See #1323
Original pull request: #1838
pull/1840/head
Mark Paluch 1 year ago
parent
commit
4978b4c0e3
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 21
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java
  2. 9
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/JdbcUtil.java
  3. 18
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java
  4. 3
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java
  5. 5
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestDatabaseFeatures.java

21
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQuery.java

@ -19,7 +19,6 @@ import static org.springframework.data.jdbc.repository.query.JdbcQueryExecution.
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.sql.JDBCType;
import java.sql.SQLType; import java.sql.SQLType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -31,8 +30,10 @@ import java.util.function.Supplier;
import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.data.jdbc.core.convert.JdbcColumnTypes;
import org.springframework.data.jdbc.core.convert.JdbcConverter; import org.springframework.data.jdbc.core.convert.JdbcConverter;
import org.springframework.data.jdbc.core.mapping.JdbcValue; import org.springframework.data.jdbc.core.mapping.JdbcValue;
import org.springframework.data.jdbc.support.JdbcUtil;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.repository.query.RelationalParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor; import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor;
@ -223,7 +224,7 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
if (actualType != null && actualType.getType().isArray()) { if (actualType != null && actualType.getType().isArray()) {
TypeInformation<?> nestedElementType = actualType.getRequiredActualType(); TypeInformation<?> nestedElementType = actualType.getRequiredActualType();
return writeCollection(collection, JDBCType.OTHER, return writeCollection(collection, parameter.getActualSqlType(),
array -> writeArrayValue(parameter, array, nestedElementType)); array -> writeArrayValue(parameter, array, nestedElementType));
} }
@ -265,21 +266,29 @@ public class StringBasedJdbcQuery extends AbstractJdbcQuery {
return jdbcValue; return jdbcValue;
} }
private Object[] writeArrayValue(JdbcParameters.JdbcParameter parameter, Object array, private JdbcValue writeArrayValue(JdbcParameters.JdbcParameter parameter, Object array,
TypeInformation<?> nestedElementType) { TypeInformation<?> nestedElementType) {
int length = Array.getLength(array); int length = Array.getLength(array);
Object[] mappedArray = new Object[length]; Object[] mappedArray = new Object[length];
SQLType sqlType = null;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Object element = Array.get(array, i); Object element = Array.get(array, i);
JdbcValue elementJdbcValue = converter.writeJdbcValue(element, nestedElementType, parameter.getActualSqlType()); JdbcValue converted = converter.writeJdbcValue(element, nestedElementType, parameter.getActualSqlType());
mappedArray[i] = elementJdbcValue.getValue(); if (sqlType == null && converted.getJdbcType() != null) {
sqlType = converted.getJdbcType();
}
mappedArray[i] = converted.getValue();
}
if (sqlType == null) {
sqlType = JdbcUtil.targetSqlTypeFor(JdbcColumnTypes.INSTANCE.resolvePrimitiveType(nestedElementType.getType()));
} }
return mappedArray; return JdbcValue.of(mappedArray, sqlType);
} }
RowMapper<Object> determineRowMapper(ResultProcessor resultProcessor, boolean hasDynamicProjection) { RowMapper<Object> determineRowMapper(ResultProcessor resultProcessor, boolean hasDynamicProjection) {

9
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/support/JdbcUtil.java

@ -22,13 +22,11 @@ import java.sql.JDBCType;
import java.sql.SQLType; import java.sql.SQLType;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.sql.Types;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -54,7 +52,12 @@ public final class JdbcUtil {
public Integer getVendorTypeNumber() { public Integer getVendorTypeNumber() {
return JdbcUtils.TYPE_UNKNOWN; return JdbcUtils.TYPE_UNKNOWN;
} }
} ;
@Override
public String toString() {
return getName();
}
};
private static final Map<Class<?>, SQLType> sqlTypeMappings = new HashMap<>(); private static final Map<Class<?>, SQLType> sqlTypeMappings = new HashMap<>();
static { static {

18
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java

@ -41,6 +41,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
@ -66,6 +67,7 @@ import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory; import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.jdbc.testing.ConditionalOnDatabase; import org.springframework.data.jdbc.testing.ConditionalOnDatabase;
import org.springframework.data.jdbc.testing.DatabaseType; import org.springframework.data.jdbc.testing.DatabaseType;
import org.springframework.data.jdbc.testing.EnabledOnDatabase;
import org.springframework.data.jdbc.testing.EnabledOnFeature; import org.springframework.data.jdbc.testing.EnabledOnFeature;
import org.springframework.data.jdbc.testing.IntegrationTest; import org.springframework.data.jdbc.testing.IntegrationTest;
import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.jdbc.testing.TestConfiguration;
@ -107,6 +109,7 @@ import org.springframework.test.jdbc.JdbcTestUtils;
* @author Paul Jones * @author Paul Jones
*/ */
@IntegrationTest @IntegrationTest
@EnabledOnDatabase(DatabaseType.MARIADB)
public class JdbcRepositoryIntegrationTests { public class JdbcRepositoryIntegrationTests {
@Autowired NamedParameterJdbcTemplate template; @Autowired NamedParameterJdbcTemplate template;
@ -1339,15 +1342,15 @@ public class JdbcRepositoryIntegrationTests {
} }
@Test // GH-1323 @Test // GH-1323
@EnabledOnFeature(TestDatabaseFeatures.Feature.WHERE_IN_TUPLE)
void queryWithTupleIn() { void queryWithTupleIn() {
DummyEntity one = repository.save(createDummyEntity("one")); DummyEntity one = repository.save(createDummyEntity("one"));
DummyEntity two = repository.save(createDummyEntity( "two")); DummyEntity two = repository.save(createDummyEntity("two"));
DummyEntity three = repository.save(createDummyEntity( "three")); DummyEntity three = repository.save(createDummyEntity("three"));
List<Object[]> tuples = List.of( List<Object[]> tuples = List.of(new Object[] { two.idProp, "two" }, // matches "two"
new Object[]{two.idProp, "two"}, // matches "two" new Object[] { three.idProp, "two" } // matches nothing
new Object[]{three.idProp, "two"} // matches nothing
); );
List<DummyEntity> result = repository.findByListInTuple(tuples); List<DummyEntity> result = repository.findByListInTuple(tuples);
@ -1887,6 +1890,11 @@ public class JdbcRepositoryIntegrationTests {
public int hashCode() { public int hashCode() {
return Objects.hash(name, pointInTime, offsetDateTime, idProp, flag, ref, direction); return Objects.hash(name, pointInTime, offsetDateTime, idProp, flag, ref, direction);
} }
@Override
public String toString() {
return "DummyEntity{" + "name='" + name + '\'' + ", idProp=" + idProp + '}';
}
} }
enum Direction { enum Direction {

3
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/query/StringBasedJdbcQueryUnitTests.java

@ -49,6 +49,7 @@ import org.springframework.data.jdbc.core.convert.JdbcTypeFactory;
import org.springframework.data.jdbc.core.convert.MappingJdbcConverter; import org.springframework.data.jdbc.core.convert.MappingJdbcConverter;
import org.springframework.data.jdbc.core.convert.RelationResolver; import org.springframework.data.jdbc.core.convert.RelationResolver;
import org.springframework.data.jdbc.core.mapping.JdbcValue; import org.springframework.data.jdbc.core.mapping.JdbcValue;
import org.springframework.data.jdbc.support.JdbcUtil;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.relational.core.mapping.RelationalMappingContext; import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
@ -338,6 +339,8 @@ class StringBasedJdbcQueryUnitTests {
assertThat(parameterSource.getValue("tuples")) assertThat(parameterSource.getValue("tuples"))
.asInstanceOf(LIST) .asInstanceOf(LIST)
.containsExactly(tuples); .containsExactly(tuples);
assertThat(parameterSource.getSqlType("tuples")).isEqualTo(JdbcUtil.TYPE_UNKNOWN.getVendorTypeNumber());
} }
@Test // GH-1323 @Test // GH-1323

5
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/testing/TestDatabaseFeatures.java

@ -79,6 +79,10 @@ public class TestDatabaseFeatures {
assumeThat(database).isNotIn(Database.MySql, Database.MariaDb, Database.SqlServer); assumeThat(database).isNotIn(Database.MySql, Database.MariaDb, Database.SqlServer);
} }
private void supportsWhereInTuples() {
assumeThat(database).isIn(Database.MySql, Database.PostgreSql);
}
public void databaseIs(Database database) { public void databaseIs(Database database) {
assumeThat(this.database).isEqualTo(database); assumeThat(this.database).isEqualTo(database);
} }
@ -112,6 +116,7 @@ public class TestDatabaseFeatures {
SUPPORTS_NANOSECOND_PRECISION(TestDatabaseFeatures::supportsNanosecondPrecision), // SUPPORTS_NANOSECOND_PRECISION(TestDatabaseFeatures::supportsNanosecondPrecision), //
SUPPORTS_NULL_PRECEDENCE(TestDatabaseFeatures::supportsNullPrecedence), SUPPORTS_NULL_PRECEDENCE(TestDatabaseFeatures::supportsNullPrecedence),
IS_POSTGRES(f -> f.databaseIs(Database.PostgreSql)), // IS_POSTGRES(f -> f.databaseIs(Database.PostgreSql)), //
WHERE_IN_TUPLE(TestDatabaseFeatures::supportsWhereInTuples), //
IS_HSQL(f -> f.databaseIs(Database.Hsql)); IS_HSQL(f -> f.databaseIs(Database.Hsql));
private final Consumer<TestDatabaseFeatures> featureMethod; private final Consumer<TestDatabaseFeatures> featureMethod;

Loading…
Cancel
Save