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