Skip to content

Commit 5029c2b

Browse files
committed
Checks for invalid SQL during the render phase
1 parent 47d66a4 commit 5029c2b

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

src/main/java/org/mybatis/dynamic/sql/insert/render/GeneralInsertRenderer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2020 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import java.util.Optional;
2525
import java.util.stream.Collectors;
2626

27+
import org.mybatis.dynamic.sql.exception.InvalidSqlException;
2728
import org.mybatis.dynamic.sql.insert.GeneralInsertModel;
2829
import org.mybatis.dynamic.sql.render.RenderingStrategy;
2930

@@ -42,6 +43,11 @@ public GeneralInsertStatementProvider render() {
4243
List<Optional<FieldAndValueAndParameters>> fieldsAndValues = model.mapColumnMappings(m -> m.accept(visitor))
4344
.collect(Collectors.toList());
4445

46+
if(fieldsAndValues.stream().noneMatch(Optional::isPresent)) {
47+
throw new InvalidSqlException(
48+
"All optional set phrases were dropped when rendering the general insert statement");
49+
}
50+
4551
return DefaultGeneralInsertStatementProvider.withInsertStatement(calculateInsertStatement(fieldsAndValues))
4652
.withParameters(calculateParameters(fieldsAndValues))
4753
.build();

src/main/java/org/mybatis/dynamic/sql/insert/render/InsertRenderer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2021 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222
import java.util.Optional;
2323
import java.util.stream.Collectors;
2424

25+
import org.mybatis.dynamic.sql.exception.InvalidSqlException;
2526
import org.mybatis.dynamic.sql.insert.InsertModel;
2627
import org.mybatis.dynamic.sql.render.RenderingStrategy;
2728

@@ -41,6 +42,11 @@ public InsertStatementProvider<T> render() {
4142
List<Optional<FieldAndValue>> fieldsAndValues = model.mapColumnMappings(m -> m.accept(visitor))
4243
.collect(Collectors.toList());
4344

45+
if (fieldsAndValues.stream().noneMatch(Optional::isPresent)) {
46+
throw new InvalidSqlException(
47+
"All optional column mappings were dropped when rendering the insert statement");
48+
}
49+
4450
return DefaultInsertStatementProvider.withRow(model.row())
4551
.withInsertStatement(calculateInsertStatement(fieldsAndValues))
4652
.build();

src/main/java/org/mybatis/dynamic/sql/update/render/UpdateRenderer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.stream.Collectors;
2727

2828
import org.mybatis.dynamic.sql.SqlTable;
29+
import org.mybatis.dynamic.sql.exception.InvalidSqlException;
2930
import org.mybatis.dynamic.sql.render.ExplicitTableAliasCalculator;
3031
import org.mybatis.dynamic.sql.render.RenderingStrategy;
3132
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
@@ -56,6 +57,10 @@ public UpdateStatementProvider render() {
5657
updateModel.mapColumnMappings(m -> m.accept(visitor))
5758
.collect(Collectors.toList());
5859

60+
if (fragmentsAndParameters.stream().noneMatch(Optional::isPresent)) {
61+
throw new InvalidSqlException("All optional set phrases were dropped when rendering the update statement");
62+
}
63+
5964
return updateModel.whereModel()
6065
.flatMap(this::renderWhereClause)
6166
.map(wc -> renderWithWhereClause(fragmentsAndParameters, wc))

src/test/java/org/mybatis/dynamic/sql/InvalidSQLTest.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
package org.mybatis.dynamic.sql;
1717

1818
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
19+
import static org.mybatis.dynamic.sql.SqlBuilder.insert;
20+
import static org.mybatis.dynamic.sql.SqlBuilder.insertInto;
21+
import static org.mybatis.dynamic.sql.SqlBuilder.update;
1922

2023
import java.util.ArrayList;
2124
import java.util.Collections;
@@ -28,6 +31,7 @@
2831
import org.mybatis.dynamic.sql.insert.InsertColumnListModel;
2932
import org.mybatis.dynamic.sql.insert.InsertModel;
3033
import org.mybatis.dynamic.sql.insert.MultiRowInsertModel;
34+
import org.mybatis.dynamic.sql.render.RenderingStrategies;
3135
import org.mybatis.dynamic.sql.select.GroupByModel;
3236
import org.mybatis.dynamic.sql.select.OrderByModel;
3337
import org.mybatis.dynamic.sql.select.QueryExpressionModel;
@@ -40,6 +44,7 @@
4044
class InvalidSQLTest {
4145

4246
private static final SqlTable person = new SqlTable("person");
47+
private static final SqlColumn<Integer> id = person.column("id");
4348

4449
@Test
4550
void testInvalidGeneralInsertStatement() {
@@ -50,6 +55,17 @@ void testInvalidGeneralInsertStatement() {
5055
.withMessage("General insert statements must have at least one column mapping");
5156
}
5257

58+
@Test
59+
void testInvalidGeneralInsertStatementWhenAllOptionalsAreDropped() {
60+
GeneralInsertModel model = insertInto(person)
61+
.set(id).toValueWhenPresent((Integer) null)
62+
.build();
63+
64+
assertThatExceptionOfType(InvalidSqlException.class)
65+
.isThrownBy(() -> model.render(RenderingStrategies.SPRING_NAMED_PARAMETER))
66+
.withMessage("All optional set phrases were dropped when rendering the general insert statement");
67+
}
68+
5369
@Test
5470
void testInvalidInsertStatement() {
5571
InsertModel.Builder<String> builder = new InsertModel.Builder<String>()
@@ -60,6 +76,20 @@ void testInvalidInsertStatement() {
6076
.withMessage("Insert statements must have at least one column mapping");
6177
}
6278

79+
@Test
80+
void testInvalidInsertStatementWhenAllOptionalsAreDropped() {
81+
TestRow testRow = new TestRow();
82+
83+
InsertModel<TestRow> model = insert(testRow)
84+
.into(person)
85+
.map(id).toPropertyWhenPresent("id", testRow::getId)
86+
.build();
87+
88+
assertThatExceptionOfType(InvalidSqlException.class)
89+
.isThrownBy(() -> model.render(RenderingStrategies.SPRING_NAMED_PARAMETER))
90+
.withMessage("All optional column mappings were dropped when rendering the insert statement");
91+
}
92+
6393
@Test
6494
void testInvalidMultipleInsertStatementNoRecords() {
6595
MultiRowInsertModel.Builder<String> builder = new MultiRowInsertModel.Builder<String>()
@@ -176,4 +206,27 @@ void testInvalidUpdateStatement() {
176206
assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
177207
.withMessage("Update statements must have at least one set phrase");
178208
}
209+
210+
@Test
211+
void testInvalidUpdateStatementWhenAllOptionalsAreDropped() {
212+
UpdateModel model = update(person)
213+
.set(id).equalToWhenPresent((Integer) null)
214+
.build();
215+
216+
assertThatExceptionOfType(InvalidSqlException.class)
217+
.isThrownBy(() -> model.render(RenderingStrategies.SPRING_NAMED_PARAMETER))
218+
.withMessage("All optional set phrases were dropped when rendering the update statement");
219+
}
220+
221+
static class TestRow {
222+
private Integer id;
223+
224+
public Integer getId() {
225+
return id;
226+
}
227+
228+
public void setId(Integer id) {
229+
this.id = id;
230+
}
231+
}
179232
}

0 commit comments

Comments
 (0)