Browse Source

`SqlIdentifierParameterSource` now sanitizes identifier names.

Closes #1405
See #1406
Original pull request #1415
pull/1486/head
Jens Schauder 3 years ago committed by Mark Paluch
parent
commit
eff0c72126
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 37
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BindParameterNameSanitizer.java
  2. 3
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java
  3. 2
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java
  4. 4
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlParametersFactory.java
  5. 26
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlParametersFactoryTest.java
  6. 4
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryIntegrationTests.java

37
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BindParameterNameSanitizer.java

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
/*
* Copyright 2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jdbc.core.convert;
import java.util.regex.Pattern;
/**
* Sanitizes the name of bind parameters, so they don't contain any illegal characters.
*
* @author Jens Schauder
*
* @since 3.0
*/
enum BindParameterNameSanitizer {
INSTANCE;
private static final Pattern parameterPattern = Pattern.compile("\\W");
String sanitize(String rawName) {
return parameterPattern.matcher(rawName).replaceAll("");
}
}

3
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java

@ -65,7 +65,6 @@ class SqlGenerator { @@ -65,7 +65,6 @@ class SqlGenerator {
static final SqlIdentifier IDS_SQL_PARAMETER = SqlIdentifier.unquoted("ids");
static final SqlIdentifier ROOT_ID_PARAMETER = SqlIdentifier.unquoted("rootId");
private static final Pattern parameterPattern = Pattern.compile("\\W");
private final RelationalPersistentEntity<?> entity;
private final MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
private final RenderContext renderContext;
@ -158,7 +157,7 @@ class SqlGenerator { @@ -158,7 +157,7 @@ class SqlGenerator {
}
private BindMarker getBindMarker(SqlIdentifier columnName) {
return SQL.bindMarker(":" + parameterPattern.matcher(renderReference(columnName)).replaceAll(""));
return SQL.bindMarker(":" + BindParameterNameSanitizer.INSTANCE.sanitize(renderReference(columnName)));
}
/**

2
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlIdentifierParameterSource.java

@ -68,7 +68,7 @@ class SqlIdentifierParameterSource extends AbstractSqlParameterSource { @@ -68,7 +68,7 @@ class SqlIdentifierParameterSource extends AbstractSqlParameterSource {
void addValue(SqlIdentifier identifier, Object value, int sqlType) {
identifiers.add(identifier);
String name = identifier.getReference(identifierProcessing);
String name = BindParameterNameSanitizer.INSTANCE.sanitize(identifier.getReference(identifierProcessing));
namesToValues.put(name, value);
registerSqlType(name, sqlType);
}

4
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlParametersFactory.java

@ -95,8 +95,8 @@ public class SqlParametersFactory { @@ -95,8 +95,8 @@ public class SqlParametersFactory {
*/
<T> SqlIdentifierParameterSource forUpdate(T instance, Class<T> domainType) {
return getParameterSource(instance, getRequiredPersistentEntity(domainType), "", RelationalPersistentProperty::isInsertOnly,
dialect.getIdentifierProcessing());
return getParameterSource(instance, getRequiredPersistentEntity(domainType), "",
RelationalPersistentProperty::isInsertOnly, dialect.getIdentifierProcessing());
}
/**

26
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/convert/SqlParametersFactoryTest.java

@ -38,6 +38,7 @@ import org.springframework.data.convert.WritingConverter; @@ -38,6 +38,7 @@ import org.springframework.data.convert.WritingConverter;
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
import org.springframework.data.relational.core.conversion.IdValueSource;
import org.springframework.data.relational.core.dialect.AnsiDialect;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.jdbc.core.JdbcOperations;
@ -147,6 +148,21 @@ class SqlParametersFactoryTest { @@ -147,6 +148,21 @@ class SqlParametersFactoryTest {
assertThat(sqlParameterSource.getValue("value")).isEqualTo(value);
}
@Test // GH-1405
void parameterNamesGetSanitized() {
WithIllegalCharacters entity = new WithIllegalCharacters(23L,"aValue");
SqlIdentifierParameterSource sqlParameterSource = sqlParametersFactory.forInsert(entity, WithIllegalCharacters.class,
Identifier.empty(), IdValueSource.PROVIDED);
assertThat(sqlParameterSource.getValue("id")).isEqualTo(23L);
assertThat(sqlParameterSource.getValue("value")).isEqualTo("aValue");
assertThat(sqlParameterSource.getValue("i.d")).isNull();
assertThat(sqlParameterSource.getValue("val&ue")).isNull();
}
@WritingConverter
enum IdValueToStringConverter implements Converter<IdValue, String> {
@ -212,6 +228,16 @@ class SqlParametersFactoryTest { @@ -212,6 +228,16 @@ class SqlParametersFactoryTest {
@Id private final Long id;
}
@AllArgsConstructor
private static class WithIllegalCharacters {
@Column("i.d")
@Id Long id;
@Column("val&ue")
String value;
}
private SqlParametersFactory createSqlParametersFactoryWithConverters(List<?> converters) {
BasicJdbcConverter converter = new BasicJdbcConverter(context, relationResolver,

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

@ -104,6 +104,7 @@ import lombok.Data; @@ -104,6 +104,7 @@ import lombok.Data;
* @author Chirag Tailor
* @author Diego Krupitza
* @author Christopher Klein
* @author Mikhail Polivakha
*/
@Transactional
@TestExecutionListeners(value = AssumeFeatureTestExecutionListener.class, mergeMode = MERGE_WITH_DEFAULTS)
@ -1242,8 +1243,9 @@ public class JdbcRepositoryIntegrationTests { @@ -1242,8 +1243,9 @@ public class JdbcRepositoryIntegrationTests {
assertThat(match.get().getName()).contains(two.getName());
}
@Test
@Test // GH-1405
void withDelimitedColumnTest() {
WithDelimitedColumn withDelimitedColumn = new WithDelimitedColumn();
withDelimitedColumn.setType("TYPICAL");
withDelimitedColumn.setIdentifier("UR-123");

Loading…
Cancel
Save