1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.jdbc;
17
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.List;
23
24
25
26
27
28
29
30 public abstract class AbstractSQL<T> {
31
32 private static final String AND = ") \nAND (";
33 private static final String OR = ") \nOR (";
34
35 private final SQLStatement sql = new SQLStatement();
36
37 public abstract T getSelf();
38
39 public T UPDATE(String table) {
40 sql().statementType = SQLStatement.StatementType.UPDATE;
41 sql().tables.add(table);
42 return getSelf();
43 }
44
45 public T SET(String sets) {
46 sql().sets.add(sets);
47 return getSelf();
48 }
49
50
51
52
53
54
55
56
57
58 public T SET(String... sets) {
59 sql().sets.addAll(Arrays.asList(sets));
60 return getSelf();
61 }
62
63 public T INSERT_INTO(String tableName) {
64 sql().statementType = SQLStatement.StatementType.INSERT;
65 sql().tables.add(tableName);
66 return getSelf();
67 }
68
69 public T VALUES(String columns, String values) {
70 INTO_COLUMNS(columns);
71 INTO_VALUES(values);
72 return getSelf();
73 }
74
75
76
77
78
79
80
81
82
83 public T INTO_COLUMNS(String... columns) {
84 sql().columns.addAll(Arrays.asList(columns));
85 return getSelf();
86 }
87
88
89
90
91
92
93
94
95
96 public T INTO_VALUES(String... values) {
97 List<String> list = sql().valuesList.get(sql().valuesList.size() - 1);
98 Collections.addAll(list, values);
99 return getSelf();
100 }
101
102 public T SELECT(String columns) {
103 sql().statementType = SQLStatement.StatementType.SELECT;
104 sql().select.add(columns);
105 return getSelf();
106 }
107
108
109
110
111
112
113
114
115
116 public T SELECT(String... columns) {
117 sql().statementType = SQLStatement.StatementType.SELECT;
118 sql().select.addAll(Arrays.asList(columns));
119 return getSelf();
120 }
121
122 public T SELECT_DISTINCT(String columns) {
123 sql().distinct = true;
124 SELECT(columns);
125 return getSelf();
126 }
127
128
129
130
131
132
133
134
135
136 public T SELECT_DISTINCT(String... columns) {
137 sql().distinct = true;
138 SELECT(columns);
139 return getSelf();
140 }
141
142 public T DELETE_FROM(String table) {
143 sql().statementType = SQLStatement.StatementType.DELETE;
144 sql().tables.add(table);
145 return getSelf();
146 }
147
148 public T FROM(String table) {
149 sql().tables.add(table);
150 return getSelf();
151 }
152
153
154
155
156
157
158
159
160
161 public T FROM(String... tables) {
162 sql().tables.addAll(Arrays.asList(tables));
163 return getSelf();
164 }
165
166 public T JOIN(String join) {
167 sql().join.add(join);
168 return getSelf();
169 }
170
171
172
173
174
175
176
177
178
179 public T JOIN(String... joins) {
180 sql().join.addAll(Arrays.asList(joins));
181 return getSelf();
182 }
183
184 public T INNER_JOIN(String join) {
185 sql().innerJoin.add(join);
186 return getSelf();
187 }
188
189
190
191
192
193
194
195
196
197 public T INNER_JOIN(String... joins) {
198 sql().innerJoin.addAll(Arrays.asList(joins));
199 return getSelf();
200 }
201
202 public T LEFT_OUTER_JOIN(String join) {
203 sql().leftOuterJoin.add(join);
204 return getSelf();
205 }
206
207
208
209
210
211
212
213
214
215 public T LEFT_OUTER_JOIN(String... joins) {
216 sql().leftOuterJoin.addAll(Arrays.asList(joins));
217 return getSelf();
218 }
219
220 public T RIGHT_OUTER_JOIN(String join) {
221 sql().rightOuterJoin.add(join);
222 return getSelf();
223 }
224
225
226
227
228
229
230
231
232
233 public T RIGHT_OUTER_JOIN(String... joins) {
234 sql().rightOuterJoin.addAll(Arrays.asList(joins));
235 return getSelf();
236 }
237
238 public T OUTER_JOIN(String join) {
239 sql().outerJoin.add(join);
240 return getSelf();
241 }
242
243
244
245
246
247
248
249
250
251 public T OUTER_JOIN(String... joins) {
252 sql().outerJoin.addAll(Arrays.asList(joins));
253 return getSelf();
254 }
255
256 public T WHERE(String conditions) {
257 sql().where.add(conditions);
258 sql().lastList = sql().where;
259 return getSelf();
260 }
261
262
263
264
265
266
267
268
269
270 public T WHERE(String... conditions) {
271 sql().where.addAll(Arrays.asList(conditions));
272 sql().lastList = sql().where;
273 return getSelf();
274 }
275
276 public T OR() {
277 sql().lastList.add(OR);
278 return getSelf();
279 }
280
281 public T AND() {
282 sql().lastList.add(AND);
283 return getSelf();
284 }
285
286 public T GROUP_BY(String columns) {
287 sql().groupBy.add(columns);
288 return getSelf();
289 }
290
291
292
293
294
295
296
297
298
299 public T GROUP_BY(String... columns) {
300 sql().groupBy.addAll(Arrays.asList(columns));
301 return getSelf();
302 }
303
304 public T HAVING(String conditions) {
305 sql().having.add(conditions);
306 sql().lastList = sql().having;
307 return getSelf();
308 }
309
310
311
312
313
314
315
316
317
318 public T HAVING(String... conditions) {
319 sql().having.addAll(Arrays.asList(conditions));
320 sql().lastList = sql().having;
321 return getSelf();
322 }
323
324 public T ORDER_BY(String columns) {
325 sql().orderBy.add(columns);
326 return getSelf();
327 }
328
329
330
331
332
333
334
335
336
337 public T ORDER_BY(String... columns) {
338 sql().orderBy.addAll(Arrays.asList(columns));
339 return getSelf();
340 }
341
342
343
344
345
346
347
348
349
350 public T LIMIT(String variable) {
351 sql().limit = variable;
352 sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT;
353 return getSelf();
354 }
355
356
357
358
359
360
361
362
363
364 public T LIMIT(int value) {
365 return LIMIT(String.valueOf(value));
366 }
367
368
369
370
371
372
373
374
375
376 public T OFFSET(String variable) {
377 sql().offset = variable;
378 sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT;
379 return getSelf();
380 }
381
382
383
384
385
386
387
388
389
390 public T OFFSET(long value) {
391 return OFFSET(String.valueOf(value));
392 }
393
394
395
396
397
398
399
400
401
402 public T FETCH_FIRST_ROWS_ONLY(String variable) {
403 sql().limit = variable;
404 sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO;
405 return getSelf();
406 }
407
408
409
410
411
412
413
414
415
416 public T FETCH_FIRST_ROWS_ONLY(int value) {
417 return FETCH_FIRST_ROWS_ONLY(String.valueOf(value));
418 }
419
420
421
422
423
424
425
426
427
428 public T OFFSET_ROWS(String variable) {
429 sql().offset = variable;
430 sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO;
431 return getSelf();
432 }
433
434
435
436
437
438
439
440
441
442 public T OFFSET_ROWS(long value) {
443 return OFFSET_ROWS(String.valueOf(value));
444 }
445
446
447
448
449
450
451
452 public T ADD_ROW() {
453 sql().valuesList.add(new ArrayList<>());
454 return getSelf();
455 }
456
457 private SQLStatement sql() {
458 return sql;
459 }
460
461 public <A extends Appendable> A usingAppender(A a) {
462 sql().sql(a);
463 return a;
464 }
465
466 @Override
467 public String toString() {
468 StringBuilder sb = new StringBuilder();
469 sql().sql(sb);
470 return sb.toString();
471 }
472
473 private static class SafeAppendable {
474 private final Appendable appendable;
475 private boolean empty = true;
476
477 public SafeAppendable(Appendable a) {
478 super();
479 this.appendable = a;
480 }
481
482 public SafeAppendable append(CharSequence s) {
483 try {
484 if (empty && s.length() > 0) {
485 empty = false;
486 }
487 appendable.append(s);
488 } catch (IOException e) {
489 throw new RuntimeException(e);
490 }
491 return this;
492 }
493
494 public boolean isEmpty() {
495 return empty;
496 }
497
498 }
499
500 private static class SQLStatement {
501
502 public enum StatementType {
503 DELETE, INSERT, SELECT, UPDATE
504 }
505
506 private enum LimitingRowsStrategy {
507 NOP {
508 @Override
509 protected void appendClause(SafeAppendable builder, String offset, String limit) {
510
511 }
512 },
513 ISO {
514 @Override
515 protected void appendClause(SafeAppendable builder, String offset, String limit) {
516 if (offset != null) {
517 builder.append(" OFFSET ").append(offset).append(" ROWS");
518 }
519 if (limit != null) {
520 builder.append(" FETCH FIRST ").append(limit).append(" ROWS ONLY");
521 }
522 }
523 },
524 OFFSET_LIMIT {
525 @Override
526 protected void appendClause(SafeAppendable builder, String offset, String limit) {
527 if (limit != null) {
528 builder.append(" LIMIT ").append(limit);
529 }
530 if (offset != null) {
531 builder.append(" OFFSET ").append(offset);
532 }
533 }
534 };
535
536 protected abstract void appendClause(SafeAppendable builder, String offset, String limit);
537
538 }
539
540 StatementType statementType;
541 List<String> sets = new ArrayList<>();
542 List<String> select = new ArrayList<>();
543 List<String> tables = new ArrayList<>();
544 List<String> join = new ArrayList<>();
545 List<String> innerJoin = new ArrayList<>();
546 List<String> outerJoin = new ArrayList<>();
547 List<String> leftOuterJoin = new ArrayList<>();
548 List<String> rightOuterJoin = new ArrayList<>();
549 List<String> where = new ArrayList<>();
550 List<String> having = new ArrayList<>();
551 List<String> groupBy = new ArrayList<>();
552 List<String> orderBy = new ArrayList<>();
553 List<String> lastList = new ArrayList<>();
554 List<String> columns = new ArrayList<>();
555 List<List<String>> valuesList = new ArrayList<>();
556 boolean distinct;
557 String offset;
558 String limit;
559 LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP;
560
561 public SQLStatement() {
562
563 valuesList.add(new ArrayList<>());
564 }
565
566 private void sqlClause(SafeAppendable builder, String keyword, List<String> parts, String open, String close,
567 String conjunction) {
568 if (!parts.isEmpty()) {
569 if (!builder.isEmpty()) {
570 builder.append("\n");
571 }
572 builder.append(keyword);
573 builder.append(" ");
574 builder.append(open);
575 String last = "________";
576 for (int i = 0, n = parts.size(); i < n; i++) {
577 String part = parts.get(i);
578 if (i > 0 && !part.equals(AND) && !part.equals(OR) && !last.equals(AND) && !last.equals(OR)) {
579 builder.append(conjunction);
580 }
581 builder.append(part);
582 last = part;
583 }
584 builder.append(close);
585 }
586 }
587
588 private String selectSQL(SafeAppendable builder) {
589 if (distinct) {
590 sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");
591 } else {
592 sqlClause(builder, "SELECT", select, "", "", ", ");
593 }
594
595 sqlClause(builder, "FROM", tables, "", "", ", ");
596 joins(builder);
597 sqlClause(builder, "WHERE", where, "(", ")", " AND ");
598 sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
599 sqlClause(builder, "HAVING", having, "(", ")", " AND ");
600 sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
601 limitingRowsStrategy.appendClause(builder, offset, limit);
602 return builder.toString();
603 }
604
605 private void joins(SafeAppendable builder) {
606 sqlClause(builder, "JOIN", join, "", "", "\nJOIN ");
607 sqlClause(builder, "INNER JOIN", innerJoin, "", "", "\nINNER JOIN ");
608 sqlClause(builder, "OUTER JOIN", outerJoin, "", "", "\nOUTER JOIN ");
609 sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", "\nLEFT OUTER JOIN ");
610 sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", "\nRIGHT OUTER JOIN ");
611 }
612
613 private String insertSQL(SafeAppendable builder) {
614 sqlClause(builder, "INSERT INTO", tables, "", "", "");
615 sqlClause(builder, "", columns, "(", ")", ", ");
616 for (int i = 0; i < valuesList.size(); i++) {
617 sqlClause(builder, i > 0 ? "," : "VALUES", valuesList.get(i), "(", ")", ", ");
618 }
619 return builder.toString();
620 }
621
622 private String deleteSQL(SafeAppendable builder) {
623 sqlClause(builder, "DELETE FROM", tables, "", "", "");
624 sqlClause(builder, "WHERE", where, "(", ")", " AND ");
625 limitingRowsStrategy.appendClause(builder, null, limit);
626 return builder.toString();
627 }
628
629 private String updateSQL(SafeAppendable builder) {
630 sqlClause(builder, "UPDATE", tables, "", "", "");
631 joins(builder);
632 sqlClause(builder, "SET", sets, "", "", ", ");
633 sqlClause(builder, "WHERE", where, "(", ")", " AND ");
634 limitingRowsStrategy.appendClause(builder, null, limit);
635 return builder.toString();
636 }
637
638 public String sql(Appendable a) {
639 SafeAppendable builder = new SafeAppendable(a);
640 if (statementType == null) {
641 return null;
642 }
643
644 String answer;
645
646 switch (statementType) {
647 case DELETE:
648 answer = deleteSQL(builder);
649 break;
650
651 case INSERT:
652 answer = insertSQL(builder);
653 break;
654
655 case SELECT:
656 answer = selectSQL(builder);
657 break;
658
659 case UPDATE:
660 answer = updateSQL(builder);
661 break;
662
663 default:
664 answer = null;
665 }
666
667 return answer;
668 }
669 }
670 }