1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.skife.jdbi.v2;
18
19 import org.skife.jdbi.v2.exceptions.ResultSetException;
20 import org.skife.jdbi.v2.exceptions.UnableToCreateStatementException;
21 import org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException;
22 import org.skife.jdbi.v2.tweak.Argument;
23 import org.skife.jdbi.v2.tweak.RewrittenStatement;
24 import org.skife.jdbi.v2.tweak.SQLLog;
25 import org.skife.jdbi.v2.tweak.StatementBuilder;
26 import org.skife.jdbi.v2.tweak.StatementCustomizer;
27 import org.skife.jdbi.v2.tweak.StatementLocator;
28 import org.skife.jdbi.v2.tweak.StatementRewriter;
29
30 import java.io.InputStream;
31 import java.io.Reader;
32 import java.math.BigDecimal;
33 import java.net.URL;
34 import java.sql.Blob;
35 import java.sql.Clob;
36 import java.sql.Connection;
37 import java.sql.PreparedStatement;
38 import java.sql.ResultSet;
39 import java.sql.SQLException;
40 import java.sql.Time;
41 import java.sql.Timestamp;
42 import java.sql.Types;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.Map;
46
47
48
49
50
51
52 public abstract class SQLStatement<SelfType extends SQLStatement<SelfType>>
53 {
54 private final Binding params;
55 private final Connection connection;
56 private final String sql;
57 private final StatementRewriter rewriter;
58 private final StatementBuilder statementBuilder;
59 private final StatementLocator locator;
60 private final Collection<StatementCustomizer> customizers = new ArrayList<StatementCustomizer>();
61 private final StatementContext context;
62
63
64
65
66 private RewrittenStatement rewritten;
67 private PreparedStatement stmt;
68 private final SQLLog log;
69 private final TimingCollector timingCollector;
70
71 SQLStatement(Binding params,
72 StatementLocator locator,
73 StatementRewriter rewriter,
74 Connection conn,
75 StatementBuilder preparedStatementCache,
76 String sql,
77 StatementContext ctx,
78 SQLLog log,
79 TimingCollector timingCollector,
80 Collection<StatementCustomizer> statementCustomizers)
81 {
82 this.log = log;
83 assert (verifyOurNastyDowncastIsOkay());
84 this.context = ctx;
85 this.statementBuilder = preparedStatementCache;
86 this.rewriter = rewriter;
87 this.connection = conn;
88 this.sql = sql;
89 this.timingCollector = timingCollector;
90 this.params = params;
91 this.locator = locator;
92 this.customizers.addAll(statementCustomizers);
93
94 ctx.setConnection(conn);
95 ctx.setRawSql(sql);
96 ctx.setBinding(params);
97 }
98
99 protected Collection<StatementCustomizer> getStatementCustomizers()
100 {
101 return this.customizers;
102 }
103
104
105
106
107
108
109
110
111 @SuppressWarnings("unchecked")
112 public SelfType define(String key, Object value)
113 {
114 getContext().setAttribute(key, value);
115 return (SelfType)this;
116 }
117
118
119
120
121 public StatementContext getContext() {
122 return context;
123 }
124
125
126
127
128
129
130
131
132
133 @SuppressWarnings("unchecked")
134 public SelfType addStatementCustomizer(StatementCustomizer customizer)
135 {
136 this.customizers.add(customizer);
137 return (SelfType) this;
138 }
139
140 private boolean verifyOurNastyDowncastIsOkay()
141 {
142 if (this.getClass().getTypeParameters().length == 0) {
143 return true;
144 }
145 else {
146 Class<?> parameterized_type = this.getClass().getTypeParameters()[0].getGenericDeclaration();
147 return parameterized_type.isAssignableFrom(this.getClass());
148 }
149 }
150
151 protected StatementBuilder getStatementBuilder()
152 {
153 return statementBuilder;
154 }
155
156 protected StatementLocator getStatementLocator()
157 {
158 return this.locator;
159 }
160
161 protected StatementRewriter getRewriter()
162 {
163 return rewriter;
164 }
165
166 protected Binding getParams()
167 {
168 return params;
169 }
170
171 protected Connection getConnection()
172 {
173 return connection;
174 }
175
176
177
178
179
180 protected String getSql()
181 {
182 return sql;
183 }
184
185 protected Binding getParameters()
186 {
187 return params;
188 }
189
190
191
192
193
194
195
196
197
198 @SuppressWarnings("unchecked")
199 public SelfType bind(int position, Argument argument)
200 {
201 params.addPositional(position, argument);
202 return (SelfType) this;
203 }
204
205
206
207
208
209
210
211
212
213 @SuppressWarnings("unchecked")
214 public SelfType bind(String name, Argument argument)
215 {
216 params.addNamed(name, argument);
217 return (SelfType) this;
218 }
219
220
221
222
223
224
225
226
227 @SuppressWarnings("unchecked")
228 public SelfType bindFromProperties(Object o)
229 {
230 params.addLazyNamedArguments(new BeanPropertyArguments(o, context));
231 return (SelfType) this;
232 }
233
234
235
236
237
238
239
240
241 @SuppressWarnings("unchecked")
242 public SelfType bindFromMap(Map<String, ? extends Object> args)
243 {
244 params.addLazyNamedArguments(new MapArguments(args));
245 return (SelfType) this;
246 }
247
248
249
250
251
252
253
254
255
256 public final SelfType bind(int position, Character value)
257 {
258 if (value != null) {
259 return bind(position, new CharacterArgument(value));
260 }
261 else {
262 return bind(position, new NullArgument(Types.VARCHAR));
263 }
264 }
265
266
267
268
269
270
271
272
273
274 public final SelfType bind(String name, Character value)
275 {
276 if (value != null) {
277 return bind(name, new CharacterArgument(value));
278 }
279 else {
280 return bind(name, new NullArgument(Types.VARCHAR));
281 }
282 }
283
284
285
286
287
288
289
290
291
292 public final SelfType bind(int position, String value)
293 {
294 return bind(position, new StringArgument(value));
295 }
296
297
298
299
300
301
302
303
304
305 public final SelfType bind(String name, String value)
306 {
307 return bind(name, new StringArgument(value));
308 }
309
310
311
312
313
314
315
316
317
318 public final SelfType bind(int position, int value)
319 {
320 return bind(position, new IntegerArgument(value));
321 }
322
323
324
325
326
327
328
329
330
331 public final SelfType bind(int position, Integer value)
332 {
333 if (value != null) {
334 return bind(position, new IntegerArgument(value));
335 }
336 else {
337 return bind(position, new NullArgument(Types.INTEGER));
338 }
339 }
340
341
342
343
344
345
346
347
348
349 public final SelfType bind(String name, int value)
350 {
351 return bind(name, new IntegerArgument(value));
352 }
353
354
355
356
357
358
359
360
361
362 public final SelfType bind(String name, Integer value)
363 {
364 if (value != null) {
365 return bind(name, new IntegerArgument(value));
366 }
367 else {
368 return bind(name, new NullArgument(Types.INTEGER));
369 }
370 }
371
372
373
374
375
376
377
378
379
380 public final SelfType bind(int position, char value)
381 {
382 return bind(position, new CharacterArgument(value));
383 }
384
385
386
387
388
389
390
391
392
393 public final SelfType bind(String name, char value)
394 {
395 return bind(name, new CharacterArgument(value));
396 }
397
398
399
400
401
402
403
404
405
406
407 public final SelfType bindASCIIStream(int position, InputStream value, int length)
408 {
409 return bind(position, new InputStreamArgument(value, length, true));
410 }
411
412
413
414
415
416
417
418
419
420
421 public final SelfType bindASCIIStream(String name, InputStream value, int length)
422 {
423 return bind(name, new InputStreamArgument(value, length, true));
424 }
425
426
427
428
429
430
431
432
433
434 public final SelfType bind(int position, BigDecimal value)
435 {
436 return bind(position, new BigDecimalArgument(value));
437 }
438
439
440
441
442
443
444
445
446
447 public final SelfType bind(String name, BigDecimal value)
448 {
449 return bind(name, new BigDecimalArgument(value));
450 }
451
452
453
454
455
456
457
458
459
460 public final SelfType bindBinaryStream(int position, InputStream value, int length)
461 {
462 return bind(position, new InputStreamArgument(value, length, false));
463 }
464
465
466
467
468
469
470
471
472
473
474 public final SelfType bindBinaryStream(String name, InputStream value, int length)
475 {
476 return bind(name, new InputStreamArgument(value, length, false));
477 }
478
479
480
481
482
483
484
485
486
487 public final SelfType bind(int position, Blob value)
488 {
489 return bind(position, new BlobArgument(value));
490 }
491
492
493
494
495
496
497
498
499
500 public final SelfType bind(String name, Blob value)
501 {
502 return bind(name, new BlobArgument(value));
503 }
504
505
506
507
508
509
510
511
512
513 public final SelfType bind(int position, boolean value)
514 {
515 return bind(position, new BooleanArgument(value));
516 }
517
518
519
520
521
522
523
524
525
526 public final SelfType bind(int position, Boolean value)
527 {
528 if (value != null) {
529 return bind(position, new BooleanArgument(value));
530 }
531 else {
532 return bind(position, new NullArgument(Types.BOOLEAN));
533 }
534 }
535
536
537
538
539
540
541
542
543
544 public final SelfType bind(String name, boolean value)
545 {
546 return bind(name, new BooleanArgument(value));
547 }
548
549
550
551
552
553
554
555
556
557 public final SelfType bind(String name, Boolean value)
558 {
559 if (value != null) {
560 return bind(name, new BooleanArgument(value));
561 }
562 else {
563 return bind(name, new NullArgument(Types.BOOLEAN));
564 }
565 }
566
567
568
569
570
571
572
573
574
575 public final SelfType bindAsInt(int position, boolean value)
576 {
577 return bind(position, new BooleanIntegerArgument(value));
578 }
579
580
581
582
583
584
585
586
587
588 public final SelfType bindAsInt(int position, Boolean value)
589 {
590 if (value != null) {
591 return bind(position, new BooleanIntegerArgument(value));
592 }
593 else {
594 return bind(position, new NullArgument(Types.INTEGER));
595 }
596 }
597
598
599
600
601
602
603
604
605
606 public final SelfType bindAsInt(String name, boolean value)
607 {
608 return bind(name, new BooleanIntegerArgument(value));
609 }
610
611
612
613
614
615
616
617
618
619 public final SelfType bindAsInt(String name, Boolean value)
620 {
621 if (value != null) {
622 return bind(name, new BooleanIntegerArgument(value));
623 }
624 else {
625 return bind(name, new NullArgument(Types.INTEGER));
626 }
627 }
628
629
630
631
632
633
634
635
636
637 public final SelfType bind(int position, byte value)
638 {
639 return bind(position, new ByteArgument(value));
640 }
641
642
643
644
645
646
647
648
649
650 public final SelfType bind(int position, Byte value)
651 {
652 if (value != null) {
653 return bind(position, new ByteArgument(value));
654 }
655 else {
656 return bind(position, new NullArgument(Types.TINYINT));
657 }
658 }
659
660
661
662
663
664
665
666
667
668 public final SelfType bind(String name, byte value)
669 {
670 return bind(name, new ByteArgument(value));
671 }
672
673
674
675
676
677
678
679
680
681 public final SelfType bind(String name, Byte value)
682 {
683 if (value != null) {
684 return bind(name, new ByteArgument(value));
685 }
686 else {
687 return bind(name, new NullArgument(Types.TINYINT));
688 }
689 }
690
691
692
693
694
695
696
697
698
699 public final SelfType bind(int position, byte[] value)
700 {
701 return bind(position, new ByteArrayArgument(value));
702 }
703
704
705
706
707
708
709
710
711
712 public final SelfType bind(String name, byte[] value)
713 {
714 return bind(name, new ByteArrayArgument(value));
715 }
716
717
718
719
720
721
722
723
724
725
726 public final SelfType bind(int position, Reader value, int length)
727 {
728 return bind(position, new CharacterStreamArgument(value, length));
729 }
730
731
732
733
734
735
736
737
738
739
740 public final SelfType bind(String name, Reader value, int length)
741 {
742 return bind(name, new CharacterStreamArgument(value, length));
743 }
744
745
746
747
748
749
750
751
752
753 public final SelfType bind(int position, Clob value)
754 {
755 return bind(position, new ClobArgument(value));
756 }
757
758
759
760
761
762
763
764
765
766 public final SelfType bind(String name, Clob value)
767 {
768 return bind(name, new ClobArgument(value));
769 }
770
771
772
773
774
775
776
777
778
779 public final SelfType bind(int position, java.sql.Date value)
780 {
781 return bind(position, new SqlDateArgument(value));
782 }
783
784
785
786
787
788
789
790
791
792 public final SelfType bind(String name, java.sql.Date value)
793 {
794 return bind(name, new SqlDateArgument(value));
795 }
796
797
798
799
800
801
802
803
804
805 public final SelfType bind(int position, java.util.Date value)
806 {
807 return bind(position, new JavaDateArgument(value));
808 }
809
810
811
812
813
814
815
816
817
818 public final SelfType bind(String name, java.util.Date value)
819 {
820 return bind(name, new JavaDateArgument(value));
821 }
822
823
824
825
826
827
828
829
830
831 public final SelfType bind(int position, double value)
832 {
833 return bind(position, new DoubleArgument(value));
834 }
835
836
837
838
839
840
841
842
843
844 public final SelfType bind(int position, Double value)
845 {
846 if (value != null) {
847 return bind(position, new DoubleArgument(value));
848 }
849 else {
850 return bind(position, new NullArgument(Types.DOUBLE));
851 }
852 }
853
854
855
856
857
858
859
860
861
862 public final SelfType bind(String name, double value)
863 {
864 return bind(name, new DoubleArgument(value));
865 }
866
867
868
869
870
871
872
873
874
875 public final SelfType bind(String name, Double value)
876 {
877 if (value != null) {
878 return bind(name, new DoubleArgument(value));
879 }
880 else {
881 return bind(name, new NullArgument(Types.DOUBLE));
882 }
883 }
884
885
886
887
888
889
890
891
892
893 public final SelfType bind(int position, float value)
894 {
895 return bind(position, new FloatArgument(value));
896 }
897
898
899
900
901
902
903
904
905
906 public final SelfType bind(int position, Float value)
907 {
908 if (value != null) {
909 return bind(position, new FloatArgument(value));
910 }
911 else {
912 return bind(position, new NullArgument(Types.FLOAT));
913 }
914 }
915
916
917
918
919
920
921
922
923
924 public final SelfType bind(String name, float value)
925 {
926 return bind(name, new FloatArgument(value));
927 }
928
929
930
931
932
933
934
935
936
937 public final SelfType bind(String name, Float value)
938 {
939 if (value != null) {
940 return bind(name, new FloatArgument(value));
941 }
942 else {
943 return bind(name, new NullArgument(Types.FLOAT));
944 }
945 }
946
947
948
949
950
951
952
953
954
955 public final SelfType bind(int position, long value)
956 {
957 return bind(position, new LongArgument(value));
958 }
959
960
961
962
963
964
965
966
967
968 public final SelfType bind(int position, Long value)
969 {
970 if (value != null) {
971 return bind(position, new LongArgument(value));
972 }
973 else {
974 return bind(position, new NullArgument(Types.BIGINT));
975 }
976 }
977
978
979
980
981
982
983
984
985
986 public final SelfType bind(String name, long value)
987 {
988 return bind(name, new LongArgument(value));
989 }
990
991
992
993
994
995
996
997
998
999 public final SelfType bind(String name, Long value)
1000 {
1001 if (value != null) {
1002 return bind(name, new LongArgument(value));
1003 }
1004 else {
1005 return bind(name, new NullArgument(Types.BIGINT));
1006 }
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 public final SelfType bind(int position, Short value)
1018 {
1019 if (value != null) {
1020 return bind(position, new ShortArgument(value));
1021 }
1022 else {
1023 return bind(position, new NullArgument(Types.SMALLINT));
1024 }
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035 public final SelfType bind(int position, short value)
1036 {
1037 return bind(position, new ShortArgument(value));
1038 }
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 public final SelfType bind(String name, short value)
1049 {
1050 return bind(name, new ShortArgument(value));
1051 }
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061 public final SelfType bind(String name, Short value)
1062 {
1063 if (value != null) {
1064 return bind(name, new ShortArgument(value));
1065 }
1066 else {
1067 return bind(name, new NullArgument(Types.SMALLINT));
1068 }
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079 public final SelfType bind(int position, Object value)
1080 {
1081 return bind(position, new ObjectArgument(value));
1082 }
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092 public final SelfType bind(String name, Object value)
1093 {
1094 return bind(name, new ObjectArgument(value));
1095 }
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105 public final SelfType bind(int position, Time value)
1106 {
1107 return bind(position, new TimeArgument(value));
1108 }
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 public final SelfType bind(String name, Time value)
1119 {
1120 return bind(name, new TimeArgument(value));
1121 }
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131 public final SelfType bind(int position, Timestamp value)
1132 {
1133 return bind(position, new TimestampArgument(value));
1134 }
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144 public final SelfType bind(String name, Timestamp value)
1145 {
1146 return bind(name, new TimestampArgument(value));
1147 }
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 public final SelfType bind(int position, URL value)
1158 {
1159 return bind(position, new URLArgument(value));
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170 public final SelfType bind(String name, URL value)
1171 {
1172 return bind(name, new URLArgument(value));
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182 public final SelfType bindNull(String name, int sqlType) {
1183 return bind(name, new NullArgument(sqlType));
1184 }
1185
1186
1187
1188
1189
1190
1191
1192
1193 public final SelfType bindNull(int position, int sqlType) {
1194 return bind(position, new NullArgument(sqlType));
1195 }
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206 public final SelfType bindBySqlType(String name, Object value, int sqlType) {
1207 return bind(name, new SqlTypeArgument(value, sqlType));
1208 }
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219 public final SelfType bindBySqlType(int position, Object value, int sqlType) {
1220 return bind(position, new SqlTypeArgument(value, sqlType));
1221 }
1222
1223 private String wrapLookup(String sql)
1224 {
1225 try {
1226 return locator.locate(sql, this.getContext());
1227 }
1228 catch (Exception e) {
1229 throw new UnableToCreateStatementException("Exception thrown while looking for statement", e, context);
1230 }
1231 }
1232
1233 protected <Result> Result internalExecute(final QueryPreperator prep,
1234 final QueryResultMunger<Result> munger,
1235 final QueryPostMungeCleanup cleanup)
1236 {
1237 final String located_sql = wrapLookup(sql);
1238 this.context.setLocatedSql(located_sql);
1239 rewritten = rewriter.rewrite(located_sql, getParameters(), this.context);
1240 this.context.setRewrittenSql(rewritten.getSql());
1241 ResultSet rs = null;
1242 try {
1243 try {
1244 if (getClass().isAssignableFrom(Call.class)) {
1245 stmt = statementBuilder.createCall(this.getConnection(), rewritten.getSql(), context);
1246 }
1247 else {
1248 stmt = statementBuilder.create(this.getConnection(), rewritten.getSql(), context);
1249 }
1250 }
1251 catch (SQLException e) {
1252 throw new UnableToCreateStatementException(e,context);
1253 }
1254
1255 this.context.setStatement(stmt);
1256 try {
1257 rewritten.bind(getParameters(), stmt);
1258 }
1259 catch (SQLException e) {
1260 throw new UnableToExecuteStatementException("Unable to bind parameters to query", e, context);
1261 }
1262
1263 try {
1264 prep.prepare(stmt);
1265 }
1266 catch (SQLException e) {
1267 throw new UnableToExecuteStatementException("Unable to prepare JDBC statement", e, context);
1268 }
1269
1270 for (StatementCustomizer customizer : customizers) {
1271 try {
1272 customizer.beforeExecution(stmt, context);
1273 }
1274 catch (SQLException e) {
1275 throw new UnableToExecuteStatementException("Exception thrown in statement customization", e, context);
1276 }
1277 }
1278
1279 try {
1280 final long start = System.nanoTime();
1281 stmt.execute();
1282 final long elapsedTime = System.nanoTime() - start;
1283 log.logSQL(elapsedTime / 1000000L, rewritten.getSql());
1284 timingCollector.collect(elapsedTime, context);
1285 }
1286 catch (SQLException e) {
1287 throw new UnableToExecuteStatementException(e, context);
1288 }
1289
1290 for (StatementCustomizer customizer : customizers) {
1291 try {
1292 customizer.afterExecution(stmt, context);
1293 }
1294 catch (SQLException e) {
1295 throw new UnableToExecuteStatementException("Exception thrown in statement customization", e, context);
1296 }
1297 }
1298
1299 try {
1300 rs = stmt.getResultSet();
1301 return munger.munge(stmt);
1302 }
1303 catch (SQLException e) {
1304 throw new ResultSetException("Exception thrown while attempting to traverse the result set", e, context);
1305 }
1306 }
1307 finally {
1308 cleanup.cleanup(this, null, rs);
1309 }
1310 }
1311
1312 void close() throws SQLException
1313 {
1314 this.statementBuilder.close(getConnection(), rewritten.getSql(), stmt);
1315 }
1316
1317 protected SQLLog getLog()
1318 {
1319 return log;
1320 }
1321
1322 protected TimingCollector getTimingCollector()
1323 {
1324 return timingCollector;
1325 }
1326 }