Skip to content

Commit 427fc4d

Browse files
schaudermp911de
authored andcommitted
SqlIdentifierParameterSource now sanitizes identifier names.
Closes #1405 See #1406 Original pull request #1415
1 parent b8e8c99 commit 427fc4d

File tree

6 files changed

+70
-6
lines changed

6 files changed

+70
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.data.jdbc.core.convert;
18+
19+
import java.util.regex.Pattern;
20+
21+
/**
22+
* Sanitizes the name of bind parameters, so they don't contain any illegal characters.
23+
*
24+
* @author Jens Schauder
25+
*
26+
* @since 3.0
27+
*/
28+
enum BindParameterNameSanitizer {
29+
INSTANCE;
30+
31+
private static final Pattern parameterPattern = Pattern.compile("\\W");
32+
33+
String sanitize(String rawName) {
34+
35+
return parameterPattern.matcher(rawName).replaceAll("");
36+
}
37+
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ class SqlGenerator {
6666
static final SqlIdentifier IDS_SQL_PARAMETER = SqlIdentifier.unquoted("ids");
6767
static final SqlIdentifier ROOT_ID_PARAMETER = SqlIdentifier.unquoted("rootId");
6868

69-
private static final Pattern parameterPattern = Pattern.compile("\\W");
7069
private final RelationalPersistentEntity<?> entity;
7170
private final MappingContext<RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
7271
private final RenderContext renderContext;
@@ -159,7 +158,7 @@ private Condition getSubselectCondition(PersistentPropertyPathExtension path,
159158
}
160159

161160
private BindMarker getBindMarker(SqlIdentifier columnName) {
162-
return SQL.bindMarker(":" + parameterPattern.matcher(renderReference(columnName)).replaceAll(""));
161+
return SQL.bindMarker(":" + BindParameterNameSanitizer.INSTANCE.sanitize(renderReference(columnName)));
163162
}
164163

165164
/**

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void addValue(SqlIdentifier name, Object value) {
6868
void addValue(SqlIdentifier identifier, Object value, int sqlType) {
6969

7070
identifiers.add(identifier);
71-
String name = identifier.getReference(identifierProcessing);
71+
String name = BindParameterNameSanitizer.INSTANCE.sanitize(identifier.getReference(identifierProcessing));
7272
namesToValues.put(name, value);
7373
registerSqlType(name, sqlType);
7474
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ <T> SqlIdentifierParameterSource forInsert(T instance, Class<T> domainType, Iden
9595
*/
9696
<T> SqlIdentifierParameterSource forUpdate(T instance, Class<T> domainType) {
9797

98-
return getParameterSource(instance, getRequiredPersistentEntity(domainType), "", RelationalPersistentProperty::isInsertOnly,
99-
dialect.getIdentifierProcessing());
98+
return getParameterSource(instance, getRequiredPersistentEntity(domainType), "",
99+
RelationalPersistentProperty::isInsertOnly, dialect.getIdentifierProcessing());
100100
}
101101

102102
/**

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

+26
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext;
3939
import org.springframework.data.relational.core.conversion.IdValueSource;
4040
import org.springframework.data.relational.core.dialect.AnsiDialect;
41+
import org.springframework.data.relational.core.mapping.Column;
4142
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
4243
import org.springframework.data.relational.core.sql.SqlIdentifier;
4344
import org.springframework.jdbc.core.JdbcOperations;
@@ -147,6 +148,21 @@ void considersConfiguredWriteConverterForIdValueObjects_onWrite() {
147148
assertThat(sqlParameterSource.getValue("value")).isEqualTo(value);
148149
}
149150

151+
@Test // GH-1405
152+
void parameterNamesGetSanitized() {
153+
154+
WithIllegalCharacters entity = new WithIllegalCharacters(23L,"aValue");
155+
156+
SqlIdentifierParameterSource sqlParameterSource = sqlParametersFactory.forInsert(entity, WithIllegalCharacters.class,
157+
Identifier.empty(), IdValueSource.PROVIDED);
158+
159+
assertThat(sqlParameterSource.getValue("id")).isEqualTo(23L);
160+
assertThat(sqlParameterSource.getValue("value")).isEqualTo("aValue");
161+
162+
assertThat(sqlParameterSource.getValue("i.d")).isNull();
163+
assertThat(sqlParameterSource.getValue("val&ue")).isNull();
164+
}
165+
150166
@WritingConverter
151167
enum IdValueToStringConverter implements Converter<IdValue, String> {
152168

@@ -212,6 +228,16 @@ private static class DummyEntity {
212228
@Id private final Long id;
213229
}
214230

231+
@AllArgsConstructor
232+
private static class WithIllegalCharacters {
233+
234+
@Column("i.d")
235+
@Id Long id;
236+
237+
@Column("val&ue")
238+
String value;
239+
}
240+
215241
private SqlParametersFactory createSqlParametersFactoryWithConverters(List<?> converters) {
216242

217243
BasicJdbcConverter converter = new BasicJdbcConverter(context, relationResolver,

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
* @author Chirag Tailor
105105
* @author Diego Krupitza
106106
* @author Christopher Klein
107+
* @author Mikhail Polivakha
107108
*/
108109
@Transactional
109110
@TestExecutionListeners(value = AssumeFeatureTestExecutionListener.class, mergeMode = MERGE_WITH_DEFAULTS)
@@ -1242,8 +1243,9 @@ void fetchByExampleFluentOnlyInstantOneValueAsSimple() {
12421243
assertThat(match.get().getName()).contains(two.getName());
12431244
}
12441245

1245-
@Test
1246+
@Test // GH-1405
12461247
void withDelimitedColumnTest() {
1248+
12471249
WithDelimitedColumn withDelimitedColumn = new WithDelimitedColumn();
12481250
withDelimitedColumn.setType("TYPICAL");
12491251
withDelimitedColumn.setIdentifier("UR-123");

0 commit comments

Comments
 (0)