Skip to content

Commit 7f06887

Browse files
committed
Use force-quoting in R2dbcMappingContext by default
1 parent 3ef1f86 commit 7f06887

20 files changed

+157
-91
lines changed

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/convert/MappingR2dbcConverter.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
4545
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
4646
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
47+
import org.springframework.data.relational.core.sql.SqlIdentifier;
4748
import org.springframework.data.relational.domain.RowDocument;
4849
import org.springframework.data.util.TypeInformation;
4950
import org.springframework.lang.Nullable;
@@ -225,7 +226,10 @@ private void writeSimpleInternal(OutboundRow sink, Object value, boolean isNew,
225226

226227
Object result = getPotentiallyConvertedSimpleWrite(value);
227228

228-
sink.put(property.getColumnName(),
229+
SqlIdentifier columnName = property.getColumnName();
230+
231+
sink.put(SqlIdentifier.unquoted(columnName.getReference()),
232+
// sink.put(property.getColumnName(),
229233
Parameter.fromOrEmpty(result, getPotentiallyConvertedSimpleNullType(property.getType())));
230234
}
231235

@@ -244,7 +248,10 @@ private void writePropertyInternal(OutboundRow sink, Object value, boolean isNew
244248
}
245249

246250
List<Object> collectionInternal = createCollection(asCollection(value), property);
247-
sink.put(property.getColumnName(), Parameter.from(collectionInternal));
251+
// sink.put(property.getColumnName(), Parameter.from(collectionInternal));
252+
SqlIdentifier columnName = property.getColumnName();
253+
//
254+
sink.put(SqlIdentifier.unquoted(columnName.getReference()), Parameter.from(collectionInternal));
248255
return;
249256
}
250257

@@ -301,7 +308,7 @@ private List<Object> writeCollectionInternal(Collection<?> source, @Nullable Typ
301308

302309
private void writeNullInternal(OutboundRow sink, RelationalPersistentProperty property) {
303310

304-
sink.put(property.getColumnName(), Parameter.empty(getPotentiallyConvertedSimpleNullType(property.getType())));
311+
sink.put(property.getColumnName().getReference(), Parameter.empty(getPotentiallyConvertedSimpleNullType(property.getType())));
305312
}
306313

307314
private Class<?> getPotentiallyConvertedSimpleNullType(Class<?> type) {

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/core/DefaultReactiveDataAccessStrategy.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,11 @@ public OutboundRow getOutboundRow(Object object) {
181181

182182
for (RelationalPersistentProperty property : entity) {
183183

184-
Parameter value = row.get(property.getColumnName());
184+
Parameter value = row.get(property.getColumnName().getReference());
185185
if (value != null && shouldConvertArrayValue(property, value)) {
186186

187187
Parameter writeValue = getArrayValue(value, property);
188-
row.put(property.getColumnName(), writeValue);
188+
row.put(property.getColumnName().getReference(), writeValue);
189189
}
190190
}
191191

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/core/DefaultStatementMapper.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
import java.util.ArrayList;
1919
import java.util.List;
2020

21+
import org.jetbrains.annotations.NotNull;
2122
import org.springframework.data.mapping.context.MappingContext;
2223
import org.springframework.data.r2dbc.convert.R2dbcConverter;
2324
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
2425
import org.springframework.data.r2dbc.query.BoundAssignments;
2526
import org.springframework.data.r2dbc.query.BoundCondition;
2627
import org.springframework.data.r2dbc.query.UpdateMapper;
2728
import org.springframework.data.relational.core.dialect.RenderContextFactory;
29+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2830
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2931
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3032
import org.springframework.data.relational.core.query.CriteriaDefinition;
@@ -53,7 +55,7 @@ class DefaultStatementMapper implements StatementMapper {
5355
private final RenderContext renderContext;
5456
private final UpdateMapper updateMapper;
5557
private final MappingContext<? extends RelationalPersistentEntity<?>, ? extends RelationalPersistentProperty> mappingContext;
56-
58+
private boolean forceQuote;
5759
DefaultStatementMapper(R2dbcDialect dialect, R2dbcConverter converter) {
5860

5961
RenderContextFactory factory = new RenderContextFactory(dialect);
@@ -62,6 +64,9 @@ class DefaultStatementMapper implements StatementMapper {
6264
this.renderContext = factory.createRenderContext();
6365
this.updateMapper = new UpdateMapper(dialect, converter);
6466
this.mappingContext = converter.getMappingContext();
67+
if(mappingContext instanceof RelationalMappingContext relationalMappingContext){
68+
forceQuote = relationalMappingContext.isForceQuote();
69+
}
6570
}
6671

6772
DefaultStatementMapper(R2dbcDialect dialect, RenderContext renderContext, UpdateMapper updateMapper,
@@ -70,6 +75,9 @@ class DefaultStatementMapper implements StatementMapper {
7075
this.renderContext = renderContext;
7176
this.updateMapper = updateMapper;
7277
this.mappingContext = mappingContext;
78+
if(mappingContext instanceof RelationalMappingContext relationalMappingContext){
79+
forceQuote = relationalMappingContext.isForceQuote();
80+
}
7381
}
7482

7583
@Override
@@ -90,7 +98,8 @@ public PreparedOperation<?> getMappedObject(SelectSpec selectSpec) {
9098
private PreparedOperation<Select> getMappedObject(SelectSpec selectSpec,
9199
@Nullable RelationalPersistentEntity<?> entity) {
92100

93-
Table table = selectSpec.getTable();
101+
String tableName = selectSpec.getTable().getName().getReference();
102+
Table table = getTable(tableName);
94103
SelectBuilder.SelectAndFrom selectAndFrom = StatementBuilder.select(getSelectList(selectSpec, entity));
95104

96105
if (selectSpec.isDistinct()) {
@@ -158,7 +167,7 @@ private PreparedOperation<Insert> getMappedObject(InsertSpec insertSpec,
158167
@Nullable RelationalPersistentEntity<?> entity) {
159168

160169
BindMarkers bindMarkers = this.dialect.getBindMarkersFactory().create();
161-
Table table = Table.create(toSql(insertSpec.getTable()));
170+
Table table = getTable(insertSpec.getTable().getReference());
162171

163172
BoundAssignments boundAssignments = this.updateMapper.getMappedObject(bindMarkers, insertSpec.getAssignments(),
164173
table, entity);
@@ -191,7 +200,7 @@ private PreparedOperation<Update> getMappedObject(UpdateSpec updateSpec,
191200
@Nullable RelationalPersistentEntity<?> entity) {
192201

193202
BindMarkers bindMarkers = this.dialect.getBindMarkersFactory().create();
194-
Table table = Table.create(toSql(updateSpec.getTable()));
203+
Table table = getTable(updateSpec.getTable().getReference());
195204

196205
if (updateSpec.getUpdate() == null || updateSpec.getUpdate().getAssignments().isEmpty()) {
197206
throw new IllegalArgumentException("UPDATE contains no assignments");
@@ -210,7 +219,6 @@ private PreparedOperation<Update> getMappedObject(UpdateSpec updateSpec,
210219

211220
CriteriaDefinition criteria = updateSpec.getCriteria();
212221
if (criteria != null && !criteria.isEmpty()) {
213-
214222
BoundCondition boundCondition = this.updateMapper.getMappedObject(bindMarkers, criteria, table, entity);
215223

216224
bindings = bindings.and(boundCondition.getBindings());
@@ -222,6 +230,10 @@ private PreparedOperation<Update> getMappedObject(UpdateSpec updateSpec,
222230
return new DefaultPreparedOperation<>(update, this.renderContext, bindings);
223231
}
224232

233+
private Table getTable(String tableName) {
234+
return forceQuote ? Table.create(SqlIdentifier.quoted(tableName)) : Table.create(SqlIdentifier.unquoted(tableName));
235+
}
236+
225237
@Override
226238
public PreparedOperation<Delete> getMappedObject(DeleteSpec deleteSpec) {
227239
return getMappedObject(deleteSpec, null);
@@ -236,7 +248,7 @@ private PreparedOperation<Delete> getMappedObject(DeleteSpec deleteSpec,
236248
@Nullable RelationalPersistentEntity<?> entity) {
237249

238250
BindMarkers bindMarkers = this.dialect.getBindMarkersFactory().create();
239-
Table table = Table.create(toSql(deleteSpec.getTable()));
251+
Table table = getTable(deleteSpec.getTable().getReference());
240252

241253
DeleteBuilder.DeleteWhere deleteBuilder = StatementBuilder.delete(table);
242254

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplate.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import io.r2dbc.spi.Row;
2020
import io.r2dbc.spi.RowMetadata;
2121
import io.r2dbc.spi.Statement;
22+
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
23+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2224
import reactor.core.publisher.Flux;
2325
import reactor.core.publisher.Mono;
2426

@@ -354,6 +356,11 @@ private <T> RowsFetchSpec<T> doSelect(Query query, Class<?> entityType, SqlIdent
354356
Class<T> returnType, Function<? super Statement, ? extends Statement> filterFunction) {
355357

356358
StatementMapper statementMapper = dataAccessStrategy.getStatementMapper().forType(entityType);
359+
boolean forceQuote = false;
360+
if(this.mappingContext instanceof RelationalMappingContext relationalMappingContext){
361+
forceQuote = relationalMappingContext.isForceQuote();
362+
}
363+
tableName = forceQuote ? SqlIdentifier.quoted(tableName.getReference()): SqlIdentifier.unquoted(tableName.getReference());
357364

358365
StatementMapper.SelectSpec selectSpec = statementMapper //
359366
.createSelect(tableName) //
@@ -548,9 +555,16 @@ private <T> Mono<T> doInsert(T entity, SqlIdentifier tableName, OutboundRow outb
548555
StatementMapper.InsertSpec insert = mapper.createInsert(tableName);
549556

550557
for (SqlIdentifier column : outboundRow.keySet()) {
558+
551559
Parameter settableValue = outboundRow.get(column);
552560
if (settableValue.hasValue()) {
553-
insert = insert.withColumn(column, settableValue);
561+
boolean forceQuote = false;
562+
if(this.mappingContext instanceof R2dbcMappingContext r2dbcMappingContext){
563+
forceQuote = r2dbcMappingContext.isForceQuote();
564+
}
565+
566+
567+
insert = insert.withColumn(forceQuote? SqlIdentifier.quoted(column.getReference()): column, settableValue);
554568
}
555569
}
556570

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/core/StatementMapper.java

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.function.Supplier;
2727
import java.util.stream.Collectors;
2828

29+
import org.jetbrains.annotations.TestOnly;
2930
import org.springframework.data.domain.Pageable;
3031
import org.springframework.data.domain.Sort;
3132
import org.springframework.data.r2dbc.convert.R2dbcConverter;
@@ -128,6 +129,7 @@ interface TypedStatementMapper<T> extends StatementMapper {}
128129
* @param table
129130
* @return the {@link SelectSpec}.
130131
*/
132+
@TestOnly
131133
default SelectSpec createSelect(String table) {
132134
return SelectSpec.create(table);
133135
}
@@ -250,6 +252,7 @@ protected SelectSpec(Table table, List<String> projectedFields, List<Expression>
250252
* @param table
251253
* @return the {@link SelectSpec}.
252254
*/
255+
@TestOnly
253256
public static SelectSpec create(String table) {
254257
return create(SqlIdentifier.unquoted(table));
255258
}

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/mapping/R2dbcMappingContext.java

-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ public class R2dbcMappingContext extends RelationalMappingContext {
3232
* Create a new {@link R2dbcMappingContext}.
3333
*/
3434
public R2dbcMappingContext() {
35-
setForceQuote(false);
3635
}
3736

3837
/**
@@ -42,7 +41,6 @@ public R2dbcMappingContext() {
4241
*/
4342
public R2dbcMappingContext(NamingStrategy namingStrategy) {
4443
super(namingStrategy);
45-
setForceQuote(false);
4644
}
4745

4846
@Override

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/query/QueryMapper.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.Map;
2323
import java.util.regex.Pattern;
2424

25+
import org.jetbrains.annotations.NotNull;
2526
import org.springframework.data.domain.Sort;
2627
import org.springframework.data.mapping.MappingException;
2728
import org.springframework.data.mapping.PersistentPropertyPath;
@@ -31,6 +32,7 @@
3132
import org.springframework.data.r2dbc.convert.R2dbcConverter;
3233
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
3334
import org.springframework.data.relational.core.dialect.Escaper;
35+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
3436
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
3537
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3638
import org.springframework.data.relational.core.query.CriteriaDefinition;
@@ -64,6 +66,7 @@ public class QueryMapper {
6466
private final R2dbcConverter converter;
6567
private final R2dbcDialect dialect;
6668
private final MappingContext<? extends RelationalPersistentEntity<?>, RelationalPersistentProperty> mappingContext;
69+
private final boolean forceQuote;
6770

6871
/**
6972
* Creates a new {@link QueryMapper} with the given {@link R2dbcConverter}.
@@ -80,6 +83,11 @@ public QueryMapper(R2dbcDialect dialect, R2dbcConverter converter) {
8083
this.converter = converter;
8184
this.dialect = dialect;
8285
this.mappingContext = (MappingContext) converter.getMappingContext();
86+
if(mappingContext instanceof RelationalMappingContext relationalMappingContext){
87+
forceQuote = relationalMappingContext.isForceQuote();
88+
}else {
89+
forceQuote= false;
90+
}
8391
}
8492

8593
/**
@@ -107,7 +115,7 @@ public String toSql(SqlIdentifier identifier) {
107115
public List<OrderByField> getMappedSort(Table table, Sort sort, @Nullable RelationalPersistentEntity<?> entity) {
108116

109117
List<OrderByField> mappedOrder = new ArrayList<>();
110-
118+
table = getTable(table);
111119
for (Sort.Order order : sort) {
112120

113121
SqlSort.validate(order);
@@ -120,13 +128,23 @@ public List<OrderByField> getMappedSort(Table table, Sort sort, @Nullable Relati
120128
return mappedOrder;
121129
}
122130

131+
Table getTable(Table table) {
132+
String tableName = table.getName().getReference();
133+
table = Table.create(forceQuote? SqlIdentifier.quoted(tableName):SqlIdentifier.unquoted(tableName));
134+
return table;
135+
}
136+
123137
private OrderByField createSimpleOrderByField(Table table, RelationalPersistentEntity<?> entity, Sort.Order order) {
124138

125139
if (order instanceof SqlSort.SqlOrder sqlOrder && sqlOrder.isUnsafe()) {
126140
return OrderByField.from(Expressions.just(sqlOrder.getProperty()));
127141
}
142+
boolean forceQuote = false;
143+
if(this.mappingContext instanceof RelationalMappingContext relationalMappingContext){
144+
forceQuote = relationalMappingContext.isForceQuote();
145+
}
128146

129-
Field field = createPropertyField(entity, SqlIdentifier.unquoted(order.getProperty()), this.mappingContext);
147+
Field field = createPropertyField(entity, forceQuote ? SqlIdentifier.quoted(order.getProperty()) : SqlIdentifier.unquoted(order.getProperty()), this.mappingContext);
130148
return OrderByField.from(table.column(field.getMappedColumnName()));
131149
}
132150

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/query/UpdateMapper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public BoundAssignments getMappedObject(BindMarkers markers, Map<SqlIdentifier,
9494
List<Assignment> result = new ArrayList<>();
9595

9696
assignments.forEach((column, value) -> {
97-
Assignment assignment = getAssignment(column, value, bindings, table, entity);
97+
Assignment assignment = getAssignment(column, value, bindings, getTable(table), entity);
9898
result.add(assignment);
9999
});
100100

spring-data-r2dbc/src/main/java/org/springframework/data/r2dbc/repository/query/R2dbcQueryCreator.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.data.domain.Sort;
2626
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
2727
import org.springframework.data.r2dbc.core.StatementMapper;
28+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2829
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
2930
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3031
import org.springframework.data.relational.core.query.Criteria;
@@ -163,9 +164,18 @@ private Expression[] getSelectProjection() {
163164
for (String projectedProperty : projectedProperties) {
164165

165166
RelationalPersistentProperty property = entity.getPersistentProperty(projectedProperty);
166-
Column column = table.column(property != null //
167-
? property.getColumnName() //
168-
: SqlIdentifier.unquoted(projectedProperty));
167+
Column column;
168+
if (property != null) {
169+
column = table.column(property.getColumnName());
170+
} else {
171+
boolean forceQuote = false;
172+
if (this.dataAccessStrategy.getConverter().getMappingContext() instanceof RelationalMappingContext relationalMappingContext) {
173+
forceQuote = relationalMappingContext.isForceQuote();
174+
}
175+
column = table.column(forceQuote
176+
? SqlIdentifier.quoted(projectedProperty)
177+
: SqlIdentifier.unquoted(projectedProperty));
178+
}
169179
expressions.add(column);
170180
}
171181

spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/R2dbcEntityTemplateUnitTests.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ void before() {
9595
R2dbcCustomConversions conversions = R2dbcCustomConversions.of(PostgresDialect.INSTANCE, new MoneyConverter(),
9696
new RowConverter(), new RowDocumentConverter(), new PkConverter());
9797

98+
R2dbcMappingContext context = new R2dbcMappingContext();
99+
context.setForceQuote(false);
98100
entityTemplate = new R2dbcEntityTemplate(client, PostgresDialect.INSTANCE,
99-
new MappingR2dbcConverter(new R2dbcMappingContext(), conversions));
101+
new MappingR2dbcConverter(context, conversions));
100102
}
101103

102104
@Test // GH-220

spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.junit.jupiter.api.Test;
3939
import org.springframework.data.annotation.ReadOnlyProperty;
4040
import org.springframework.data.r2dbc.dialect.R2dbcDialect;
41+
import org.springframework.data.r2dbc.mapping.OutboundRow;
4142
import org.springframework.data.relational.core.sql.SqlIdentifier;
4243
import org.springframework.r2dbc.core.Parameter;
4344

spring-data-r2dbc/src/test/java/org/springframework/data/r2dbc/core/ReactiveDeleteOperationUnitTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void shouldDelete() {
6767

6868
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("DELETE"));
6969

70-
assertThat(statement.getSql()).isEqualTo("DELETE FROM person");
70+
assertThat(statement.getSql()).isEqualTo("DELETE FROM \"person\"");
7171
}
7272

7373
@Test // gh-410
@@ -104,7 +104,7 @@ void shouldDeleteWithQuery() {
104104

105105
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("DELETE"));
106106

107-
assertThat(statement.getSql()).isEqualTo("DELETE FROM person WHERE person.THE_NAME = $1");
107+
assertThat(statement.getSql()).isEqualTo("DELETE FROM \"person\" WHERE \"person\".\"THE_NAME\" = $1");
108108
assertThat(statement.getBindings()).hasSize(1).containsEntry(0, Parameter.from("Walter"));
109109
}
110110

@@ -125,7 +125,7 @@ void shouldDeleteInTable() {
125125

126126
StatementRecorder.RecordedStatement statement = recorder.getCreatedStatement(s -> s.startsWith("DELETE"));
127127

128-
assertThat(statement.getSql()).isEqualTo("DELETE FROM other_table WHERE other_table.THE_NAME = $1");
128+
assertThat(statement.getSql()).isEqualTo("DELETE FROM other_table WHERE other_table.\"THE_NAME\" = $1");
129129
}
130130

131131
static class Person {

0 commit comments

Comments
 (0)