1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.dynamic.sql;
17
18 import static org.assertj.core.api.Assertions.assertThat;
19 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
20 import static org.mybatis.dynamic.sql.SqlBuilder.*;
21
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.MissingResourceException;
25 import java.util.Optional;
26
27 import org.jspecify.annotations.Nullable;
28 import org.junit.jupiter.api.Test;
29 import org.mybatis.dynamic.sql.common.OrderByModel;
30 import org.mybatis.dynamic.sql.configuration.StatementConfiguration;
31 import org.mybatis.dynamic.sql.exception.InvalidSqlException;
32 import org.mybatis.dynamic.sql.insert.BatchInsertModel;
33 import org.mybatis.dynamic.sql.insert.GeneralInsertModel;
34 import org.mybatis.dynamic.sql.insert.InsertColumnListModel;
35 import org.mybatis.dynamic.sql.insert.InsertModel;
36 import org.mybatis.dynamic.sql.insert.MultiRowInsertModel;
37 import org.mybatis.dynamic.sql.render.RenderingContext;
38 import org.mybatis.dynamic.sql.render.RenderingStrategies;
39 import org.mybatis.dynamic.sql.select.GroupByModel;
40 import org.mybatis.dynamic.sql.select.PagingModel;
41 import org.mybatis.dynamic.sql.select.QueryExpressionModel;
42 import org.mybatis.dynamic.sql.select.SelectModel;
43 import org.mybatis.dynamic.sql.select.join.JoinModel;
44 import org.mybatis.dynamic.sql.select.join.JoinSpecification;
45 import org.mybatis.dynamic.sql.select.join.JoinType;
46 import org.mybatis.dynamic.sql.select.render.FetchFirstPagingModelRenderer;
47 import org.mybatis.dynamic.sql.update.UpdateModel;
48 import org.mybatis.dynamic.sql.util.InternalError;
49 import org.mybatis.dynamic.sql.util.Messages;
50
51 class InvalidSQLTest {
52
53 private static final SqlTable person = new SqlTable("person");
54 private static final SqlColumn<Integer> id = person.column("id");
55
56 @Test
57 void testInvalidGeneralInsertStatement() {
58 GeneralInsertModel.Builder builder = new GeneralInsertModel.Builder()
59 .withTable(person);
60
61 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
62 .withMessage(Messages.getString("ERROR.6"));
63 }
64
65 @Test
66 void testInvalidGeneralInsertStatementWhenAllOptionalsAreDropped() {
67 GeneralInsertModel model = insertInto(person)
68 .set(id).toValueWhenPresent((Integer) null)
69 .build();
70
71 assertThatExceptionOfType(InvalidSqlException.class)
72 .isThrownBy(() -> model.render(RenderingStrategies.SPRING_NAMED_PARAMETER))
73 .withMessage(Messages.getString("ERROR.9"));
74 }
75
76 @Test
77 void testInvalidInsertStatement() {
78 InsertModel.Builder<TestRow> builder = new InsertModel.Builder<TestRow>()
79 .withTable(person)
80 .withRow(new TestRow());
81
82 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
83 .withMessage(Messages.getString("ERROR.7"));
84 }
85
86 @Test
87 void testInvalidInsertStatementWhenAllOptionalsAreDropped() {
88 TestRow testRow = new TestRow();
89
90 InsertModel<TestRow> model = insert(testRow)
91 .into(person)
92 .map(id).toPropertyWhenPresent("id", testRow::getId)
93 .build();
94
95 assertThatExceptionOfType(InvalidSqlException.class)
96 .isThrownBy(() -> model.render(RenderingStrategies.SPRING_NAMED_PARAMETER))
97 .withMessage(Messages.getString("ERROR.10"));
98 }
99
100 @Test
101 void testInvalidMultipleInsertStatementNoRecords() {
102 MultiRowInsertModel.Builder<TestRow> builder = new MultiRowInsertModel.Builder<TestRow>()
103 .withTable(person);
104
105 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
106 .withMessage(Messages.getString("ERROR.20"));
107 }
108
109 @Test
110 void testInvalidMultipleInsertStatementNoMappings() {
111 List<TestRow> records = List.of(new TestRow());
112
113 MultiRowInsertModel.Builder<TestRow> builder = new MultiRowInsertModel.Builder<TestRow>()
114 .withRecords(records)
115 .withTable(person);
116
117 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
118 .withMessage(Messages.getString("ERROR.8"));
119 }
120
121 @Test
122 void testInvalidBatchInsertStatementNoRecords() {
123 BatchInsertModel.Builder<TestRow> builder = new BatchInsertModel.Builder<TestRow>()
124 .withTable(person);
125
126 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
127 .withMessage(Messages.getString("ERROR.19"));
128 }
129
130 @Test
131 void testInvalidBatchInsertStatementNoMappings() {
132 List<TestRow> records = List.of(new TestRow());
133
134 BatchInsertModel.Builder<TestRow> builder = new BatchInsertModel.Builder<TestRow>()
135 .withRecords(records)
136 .withTable(person);
137
138 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
139 .withMessage(Messages.getString("ERROR.5"));
140 }
141
142 @Test
143 void testInvalidEmptyInsertColumnList() {
144 List<SqlColumn<?>> list = Collections.emptyList();
145 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> InsertColumnListModel.of(list))
146 .withMessage(Messages.getString("ERROR.4"));
147 }
148
149 @Test
150 void testInvalidNullInsertColumnList() {
151 assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> InsertColumnListModel.of(null));
152 }
153
154 @Test
155 void testInvalidSelectStatementWithoutQueryExpressions() {
156 SelectModel.Builder builder =
157 new SelectModel.Builder().withStatementConfiguration(new StatementConfiguration());
158
159 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
160 .withMessage(Messages.getString("ERROR.14"));
161 }
162
163 @Test
164 void testInvalidSelectStatementWithoutColumnList() {
165 QueryExpressionModel.Builder builder = new QueryExpressionModel.Builder()
166 .withTable(person);
167
168 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
169 .withMessage(Messages.getString("ERROR.13"));
170 }
171
172 @Test
173 void testInvalidSelectStatementEmptyJoinModel() {
174 List<JoinSpecification> list = Collections.emptyList();
175 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> JoinModel.of(list))
176 .withMessage(Messages.getString("ERROR.15"));
177 }
178
179 @Test
180 void testInvalidSelectStatementNullJoinModel() {
181 assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> JoinModel.of(null));
182 }
183
184 @Test
185 void testInvalidSelectStatementJoinSpecification() {
186 JoinSpecification.Builder builder = new JoinSpecification.Builder()
187 .withJoinTable(person)
188 .withJoinType(JoinType.LEFT);
189
190 assertThatExceptionOfType(NullPointerException.class).isThrownBy(builder::build);
191 }
192 @Test
193 void testInvalidSelectStatementWithEmptyOrderByList() {
194 List<SortSpecification> list = Collections.emptyList();
195 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> OrderByModel.of(list))
196 .withMessage(Messages.getString("ERROR.12"));
197 }
198
199 @Test
200 void testInvalidSelectStatementWithEmptyGroupByList() {
201 List<BasicColumn> list = Collections.emptyList();
202 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(() -> GroupByModel.of(list))
203 .withMessage(Messages.getString("ERROR.11"));
204 }
205
206 @Test
207 void testInvalidUpdateStatement() {
208 UpdateModel.Builder builder = new UpdateModel.Builder()
209 .withTable(person);
210
211 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(builder::build)
212 .withMessage(Messages.getString("ERROR.17"));
213 }
214
215 @Test
216 void testInvalidUpdateStatementWhenAllOptionalsAreDropped() {
217 UpdateModel model = update(person)
218 .set(id).equalToWhenPresent((Integer) null)
219 .build();
220
221 assertThatExceptionOfType(InvalidSqlException.class)
222 .isThrownBy(() -> model.render(RenderingStrategies.SPRING_NAMED_PARAMETER))
223 .withMessage(Messages.getString("ERROR.18"));
224 }
225
226 @Test
227 void testMissingMessage() {
228 assertThatExceptionOfType(MissingResourceException.class)
229 .isThrownBy(() -> Messages.getString("MISSING_MESSAGE"));
230 }
231
232 @Test
233 void testInvalidPagingModel() {
234 Optional<PagingModel> pagingModel = new PagingModel.Builder().withLimit(22L).build();
235
236 RenderingContext renderingContext = RenderingContext
237 .withRenderingStrategy(RenderingStrategies.MYBATIS3)
238 .withStatementConfiguration(new StatementConfiguration())
239 .build();
240
241 assertThat(pagingModel).hasValueSatisfying(pm -> {
242 FetchFirstPagingModelRenderer renderer = new FetchFirstPagingModelRenderer(renderingContext, pm);
243
244 assertThatExceptionOfType(InvalidSqlException.class)
245 .isThrownBy(renderer::render)
246 .withMessage(Messages.getInternalErrorString(InternalError.INTERNAL_ERROR_13));
247 });
248 }
249
250 @Test
251 void testInvalidValueAlias() {
252 BoundValue<Integer> foo = value(1);
253
254 assertThat(foo.alias()).isEmpty();
255 assertThatExceptionOfType(InvalidSqlException.class)
256 .isThrownBy(() -> foo.as("foo"))
257 .withMessage(Messages.getString("ERROR.38"));
258 }
259
260 @Test
261 void testInvalidDoubleForUpdate() {
262 var dsl = select(id).from(person).limit(2).forUpdate();
263 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::forUpdate)
264 .withMessage(Messages.getString("ERROR.48"));
265 }
266
267 @Test
268 void testInvalidDoubleForShare() {
269 var dsl = select(id).from(person).offset(2).forShare();
270 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::forShare)
271 .withMessage(Messages.getString("ERROR.48"));
272 }
273
274 @Test
275 void testInvalidDoubleForKeyShare() {
276 var dsl = select(id).from(person).forKeyShare();
277 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::forKeyShare)
278 .withMessage(Messages.getString("ERROR.48"));
279 }
280
281 @Test
282 void testInvalidDoubleForNoKeyUpdate() {
283 var dsl = select(id).from(person).where(id, isEqualTo(1)).forNoKeyUpdate();
284 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::forNoKeyUpdate)
285 .withMessage(Messages.getString("ERROR.48"));
286 }
287
288 @Test
289 void testInvalidDoubleForNoKeyUpdateAfterJoin() {
290 var dsl = select(id).from(person).join(person).on(id, isEqualTo(id)).skipLocked();
291 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::skipLocked)
292 .withMessage(Messages.getString("ERROR.49"));
293 }
294
295 @Test
296 void testInvalidDoubleForNoKeyUpdateAfterGroupBy() {
297 var dsl = select(id).from(person).groupBy(id).nowait();
298 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::nowait)
299 .withMessage(Messages.getString("ERROR.49"));
300 }
301
302 @Test
303 void testInvalidDoubleForNoKeyUpdateAfterHaving() {
304 var dsl = select(id).from(person).groupBy(id).having(id, isEqualTo(2)).nowait();
305 assertThatExceptionOfType(InvalidSqlException.class).isThrownBy(dsl::nowait)
306 .withMessage(Messages.getString("ERROR.49"));
307 }
308
309 static class TestRow {
310 private @Nullable Integer id;
311
312 public @Nullable Integer getId() {
313 return id;
314 }
315
316 public void setId(Integer id) {
317 this.id = id;
318 }
319 }
320 }