1 package com.github.davidmoten.rx.jdbc;
2
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.io.Reader;
8 import java.io.StringReader;
9 import java.io.Writer;
10 import java.lang.reflect.Constructor;
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 import java.math.BigDecimal;
14 import java.math.BigInteger;
15 import java.sql.Blob;
16 import java.sql.Clob;
17 import java.sql.Connection;
18 import java.sql.PreparedStatement;
19 import java.sql.ResultSet;
20 import java.sql.ResultSetMetaData;
21 import java.sql.SQLException;
22 import java.sql.Time;
23 import java.sql.Timestamp;
24 import java.sql.Types;
25 import java.util.ArrayList;
26 import java.util.Calendar;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.apache.commons.io.IOUtils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import rx.functions.Func1;
37
38 import com.github.davidmoten.rx.jdbc.QuerySelect.Builder;
39 import com.github.davidmoten.rx.jdbc.exceptions.SQLRuntimeException;
40
41
42
43
44 public final class Util {
45
46
47
48
49 private Util() {
50
51 }
52
53
54
55
56 private static final Logger log = LoggerFactory.getLogger(Util.class);
57
58
59
60
61
62
63
64
65 static int parametersCount(Query query) {
66 if (query.names().isEmpty())
67 return countQuestionMarkParameters(query.sql());
68 else
69 return query.names().size();
70 }
71
72
73 static int countQuestionMarkParameters(String sql) {
74
75
76 int count = 0;
77 int length = sql.length();
78 boolean inSingleQuote = false;
79 boolean inDoubleQuote = false;
80 for (int i = 0; i < length; i++) {
81 char c = sql.charAt(i);
82 if (inSingleQuote) {
83 if (c == '\'') {
84 inSingleQuote = false;
85 }
86 } else if (inDoubleQuote) {
87 if (c == '"') {
88 inDoubleQuote = false;
89 }
90 } else {
91 if (c == '\'') {
92 inSingleQuote = true;
93 } else if (c == '"') {
94 inDoubleQuote = true;
95 } else if (c == '?') {
96 count++;
97 }
98 }
99 }
100 return count;
101 }
102
103
104
105
106
107
108
109 static void closeQuietly(PreparedStatement ps) {
110 try {
111 boolean isClosed;
112 try {
113 if (ps != null)
114 isClosed = ps.isClosed();
115 else
116 isClosed = true;
117 } catch (SQLException e) {
118 log.debug(e.getMessage());
119 isClosed = true;
120 }
121 if (ps != null && !isClosed) {
122 try {
123 ps.cancel();
124 log.debug("cancelled {}", ps);
125 } catch (SQLException e) {
126 log.debug(e.getMessage());
127 }
128 ps.close();
129 log.debug("closed {}", ps);
130 }
131 } catch (SQLException e) {
132 log.debug(e.getMessage(), e);
133 } catch (RuntimeException e) {
134 log.debug(e.getMessage(), e);
135 }
136 }
137
138
139
140
141
142
143
144 static void closeQuietly(Connection connection) {
145 try {
146 if (connection != null && !connection.isClosed()) {
147 connection.close();
148 log.debug("closed {}", connection);
149 }
150 } catch (SQLException e) {
151 log.debug(e.getMessage(), e);
152 } catch (RuntimeException e) {
153 log.debug(e.getMessage(), e);
154 }
155 }
156
157
158
159
160
161
162
163 static boolean closeQuietlyIfAutoCommit(Connection connection) {
164 try {
165 if (connection != null && !connection.isClosed() && connection.getAutoCommit()) {
166 closeQuietly(connection);
167 return true;
168 } else
169 return false;
170 } catch (SQLException e) {
171 throw new SQLRuntimeException(e);
172 }
173 }
174
175
176
177
178
179
180 static void commit(Connection connection) {
181 if (connection != null)
182 try {
183 connection.commit();
184 log.debug("committed");
185 } catch (SQLException e) {
186 throw new SQLRuntimeException(e);
187 }
188 }
189
190
191
192
193
194
195 static void rollback(Connection connection) {
196 if (connection != null)
197 try {
198 connection.rollback();
199 log.debug("rolled back");
200 } catch (SQLException e) {
201 throw new SQLRuntimeException(e);
202 }
203 }
204
205
206
207
208
209
210 static void closeQuietly(ResultSet rs) {
211 try {
212 if (rs != null && !rs.isClosed()) {
213 rs.close();
214 log.debug("closed {}", rs);
215 }
216 } catch (SQLException e) {
217 log.debug(e.getMessage(), e);
218 } catch (RuntimeException e) {
219 log.debug(e.getMessage(), e);
220 }
221 }
222
223
224
225
226
227
228
229 static boolean isAutoCommit(Connection con) {
230 try {
231 return con.getAutoCommit();
232 } catch (SQLException e) {
233 throw new SQLRuntimeException(e);
234 }
235 }
236
237
238
239
240 static Func1<Integer, List<Parameter>> TO_EMPTY_PARAMETER_LIST = new Func1<Integer, List<Parameter>>() {
241 @Override
242 public List<Parameter> call(Integer n) {
243 return Collections.emptyList();
244 };
245 };
246
247
248
249
250
251
252
253
254
255
256 static <T> ResultSetMapper<T> autoMap(final Class<T> cls) {
257 return new ResultSetMapper<T>() {
258 @Override
259 public T call(ResultSet rs) {
260 return autoMap(rs, cls);
261 }
262 };
263 }
264
265
266
267
268
269
270
271
272
273
274
275 @SuppressWarnings("unchecked")
276 static <T> T autoMap(ResultSet rs, Class<T> cls) {
277 try {
278 if (cls.isInterface()) {
279 return autoMapInterface(rs, cls);
280 } else {
281 int n = rs.getMetaData().getColumnCount();
282 for (Constructor<?> c : cls.getDeclaredConstructors()) {
283 if (n == c.getParameterTypes().length) {
284 return autoMap(rs, (Constructor<T>) c);
285 }
286 }
287 throw new RuntimeException("constructor with number of parameters=" + n
288 + " not found in " + cls);
289 }
290 } catch (SQLException e) {
291 throw new SQLRuntimeException(e);
292 }
293 }
294
295 private static <T> T autoMapInterface(ResultSet rs, Class<T> cls) {
296 return ProxyService.newInstance(rs, cls);
297 }
298
299 static interface Col {
300 Class<?> returnType();
301 }
302
303 static class NamedCol implements Col {
304 final String name;
305 private final Class<?> returnType;
306
307 public NamedCol(String name, Class<?> returnType) {
308 this.name = name;
309 this.returnType = returnType;
310 }
311
312 @Override
313 public Class<?> returnType() {
314 return returnType;
315 }
316
317 @Override
318 public String toString() {
319 return "NamedCol [name=" + name + ", returnType=" + returnType + "]";
320 }
321
322 }
323
324 static class IndexedCol implements Col {
325 final int index;
326 private final Class<?> returnType;
327
328 public IndexedCol(int index, Class<?> returnType) {
329 this.index = index;
330 this.returnType = returnType;
331 }
332
333 @Override
334 public Class<?> returnType() {
335 return returnType;
336 }
337
338 @Override
339 public String toString() {
340 return "IndexedCol [index=" + index + ", returnType=" + returnType + "]";
341 }
342
343 }
344
345 private static class ProxyService<T> implements java.lang.reflect.InvocationHandler {
346
347 private final Map<String, Object> values = new HashMap<String, Object>();
348
349 ProxyService(ResultSet rs, Class<T> cls) {
350
351 if (Database.rsCache.get() == null || Database.rsCache.get().rs != rs)
352 Database.rsCache.set(new ResultSetCache(rs));
353 Map<String, Integer> colIndexes = Database.rsCache.get().colIndexes;
354
355
356 if (Database.autoMapCache.get() == null || Database.autoMapCache.get().cls != cls)
357 Database.autoMapCache.set(new AutoMapCache(cls));
358 Map<String, Col> methodCols = Database.autoMapCache.get().methodCols;
359
360
361
362 for (Method m : cls.getMethods()) {
363 String methodName = m.getName();
364 Col column = methodCols.get(methodName);
365 Integer index;
366 if (column instanceof NamedCol) {
367 String name = ((NamedCol) column).name;
368 index = colIndexes.get(name.toUpperCase());
369 if (index == null) {
370 throw new SQLRuntimeException("query column names do not include '" + name
371 + "'");
372 }
373 } else {
374 IndexedCol col = ((IndexedCol) column);
375 index = col.index;
376 }
377 Object value = autoMap(getObject(rs, column.returnType(), index),
378 column.returnType());
379 values.put(methodName, value);
380 }
381 }
382
383 @SuppressWarnings("unchecked")
384 public static <T> T newInstance(ResultSet rs, Class<T> cls) {
385
386 return (T) java.lang.reflect.Proxy.newProxyInstance(cls.getClassLoader(),
387 new Class[] { cls }, new ProxyService<T>(rs, cls));
388 }
389
390 @Override
391 public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
392 return values.get(m.getName());
393 }
394 }
395
396 static String camelCaseToUnderscore(String camelCased) {
397
398
399 final String regex = "([a-z])([A-Z]+)";
400 final String replacement = "$1_$2";
401 return camelCased.replaceAll(regex, replacement);
402 }
403
404 static String first(String[] value) {
405 if (value == null || value.length == 0)
406 return null;
407 else
408 return value[0];
409 }
410
411
412
413
414
415
416
417
418
419
420
421
422
423 private static <T> T autoMap(ResultSet rs, Constructor<T> c) {
424 Class<?>[] types = c.getParameterTypes();
425 List<Object> list = new ArrayList<Object>();
426 for (int i = 0; i < types.length; i++) {
427 list.add(autoMap(getObject(rs, types[i], i + 1), types[i]));
428 }
429 try {
430 return newInstance(c, list);
431 } catch (RuntimeException e) {
432 throw new RuntimeException("problem with parameters=" + getTypeInfo(list)
433 + ", rs types=" + getRowInfo(rs)
434 + ". Be sure not to use primitives in a constructor when calling autoMap().", e);
435 }
436 }
437
438 static <T> void setSqlFromQueryAnnotation(Class<T> cls, QueryBuilder builder) {
439 if (builder.sql() == null) {
440 com.github.davidmoten.rx.jdbc.annotations.Query query = cls
441 .getAnnotation(com.github.davidmoten.rx.jdbc.annotations.Query.class);
442 if (query != null && query.value() != null) {
443 String sql = query.value();
444 builder.setSql(sql);
445 } else
446 throw new RuntimeException(
447 "Class "
448 + cls
449 + " must be annotated with @Query(sql) or sql must be specified to the builder.select() call");
450 }
451 }
452
453
454
455
456
457
458
459 private static String getTypeInfo(List<Object> list) {
460
461 StringBuilder s = new StringBuilder();
462 for (Object o : list) {
463 if (s.length() > 0)
464 s.append(", ");
465 if (o == null)
466 s.append("null");
467 else {
468 s.append(o.getClass().getName());
469 s.append("=");
470 s.append(o);
471 }
472 }
473 return s.toString();
474 }
475
476 private static String getRowInfo(ResultSet rs) {
477 StringBuilder s = new StringBuilder();
478 try {
479 ResultSetMetaData md = rs.getMetaData();
480 for (int i = 1; i <= md.getColumnCount(); i++) {
481 String name = md.getColumnName(i);
482 String type = md.getColumnClassName(i);
483 if (s.length() > 0)
484 s.append(", ");
485 s.append(name);
486 s.append("=");
487 s.append(type);
488 }
489 } catch (SQLException e1) {
490 throw new SQLRuntimeException(e1);
491 }
492 return s.toString();
493 }
494
495
496
497
498
499
500
501
502
503 @SuppressWarnings("unchecked")
504 private static <T> T newInstance(Constructor<?> c, List<Object> parameters) {
505 try {
506 return (T) c.newInstance(parameters.toArray());
507 } catch (InstantiationException e) {
508 throw new RuntimeException(e);
509 } catch (IllegalAccessException e) {
510 throw new RuntimeException(e);
511 } catch (IllegalArgumentException e) {
512 throw new RuntimeException(e);
513 } catch (InvocationTargetException e) {
514 throw new RuntimeException(e);
515 }
516 }
517
518
519
520
521
522
523
524
525
526 public static Object autoMap(Object o, Class<?> cls) {
527 if (o == null)
528 return o;
529 else if (cls.isAssignableFrom(o.getClass())) {
530 return o;
531 } else {
532 if (o instanceof java.sql.Date) {
533 java.sql.Date d = (java.sql.Date) o;
534 if (cls.isAssignableFrom(Long.class))
535 return d.getTime();
536 else if (cls.isAssignableFrom(BigInteger.class))
537 return BigInteger.valueOf(d.getTime());
538 else
539 return o;
540 } else if (o instanceof java.sql.Timestamp) {
541 Timestamp t = (java.sql.Timestamp) o;
542 if (cls.isAssignableFrom(Long.class))
543 return t.getTime();
544 else if (cls.isAssignableFrom(BigInteger.class))
545 return BigInteger.valueOf(t.getTime());
546 else
547 return o;
548 } else if (o instanceof java.sql.Time) {
549 Time t = (java.sql.Time) o;
550 if (cls.isAssignableFrom(Long.class))
551 return t.getTime();
552 else if (cls.isAssignableFrom(BigInteger.class))
553 return BigInteger.valueOf(t.getTime());
554 else
555 return o;
556 } else if (o instanceof Blob && cls.isAssignableFrom(byte[].class)) {
557 return toBytes((Blob) o);
558 } else if (o instanceof Clob && cls.isAssignableFrom(String.class)) {
559 return toString((Clob) o);
560 } else if (o instanceof BigInteger && cls.isAssignableFrom(Long.class)) {
561 return ((BigInteger) o).longValue();
562 } else if (o instanceof BigInteger && cls.isAssignableFrom(Integer.class)) {
563 return ((BigInteger) o).intValue();
564 } else if (o instanceof BigInteger && cls.isAssignableFrom(Double.class)) {
565 return ((BigInteger) o).doubleValue();
566 } else if (o instanceof BigInteger && cls.isAssignableFrom(Float.class)) {
567 return ((BigInteger) o).floatValue();
568 } else if (o instanceof BigInteger && cls.isAssignableFrom(Short.class)) {
569 return ((BigInteger) o).shortValue();
570 } else if (o instanceof BigInteger && cls.isAssignableFrom(BigDecimal.class)) {
571 return new BigDecimal((BigInteger) o);
572 } else if (o instanceof BigDecimal && cls.isAssignableFrom(Double.class)) {
573 return ((BigDecimal) o).doubleValue();
574 } else if (o instanceof BigDecimal && cls.isAssignableFrom(Integer.class)) {
575 return ((BigDecimal) o).toBigInteger().intValue();
576 } else if (o instanceof BigDecimal && cls.isAssignableFrom(Float.class)) {
577 return ((BigDecimal) o).floatValue();
578 } else if (o instanceof BigDecimal && cls.isAssignableFrom(Short.class)) {
579 return ((BigDecimal) o).toBigInteger().shortValue();
580 } else if (o instanceof BigDecimal && cls.isAssignableFrom(Long.class)) {
581 return ((BigDecimal) o).toBigInteger().longValue();
582 } else if (o instanceof BigDecimal && cls.isAssignableFrom(BigInteger.class)) {
583 return ((BigDecimal) o).toBigInteger();
584 } else if ((o instanceof Short || o instanceof Integer || o instanceof Long)
585 && cls.isAssignableFrom(BigInteger.class)) {
586 return new BigInteger(o.toString());
587 } else if (o instanceof Number && cls.isAssignableFrom(BigDecimal.class)) {
588 return new BigDecimal(o.toString());
589 } else if (o instanceof Number && cls.isAssignableFrom(Short.class))
590 return ((Number) o).shortValue();
591 else if (o instanceof Number && cls.isAssignableFrom(Integer.class))
592 return ((Number) o).intValue();
593 else if (o instanceof Number && cls.isAssignableFrom(Integer.class))
594 return ((Number) o).intValue();
595 else if (o instanceof Number && cls.isAssignableFrom(Long.class))
596 return ((Number) o).longValue();
597 else if (o instanceof Number && cls.isAssignableFrom(Float.class))
598 return ((Number) o).floatValue();
599 else if (o instanceof Number && cls.isAssignableFrom(Double.class))
600 return ((Number) o).doubleValue();
601 else
602 return o;
603 }
604 }
605
606 public static <T> Object mapObject(final ResultSet rs, Class<T> cls, int i) {
607 return autoMap(getObject(rs, cls, i), cls);
608 }
609
610 private static <T> Object getObject(final ResultSet rs, Class<T> cls, int i) {
611 try {
612 if (rs.getObject(i) == null) {
613 return null;
614 }
615
616 final int type = rs.getMetaData().getColumnType(i);
617
618
619 if (type == Types.DATE)
620 return rs.getDate(i, Calendar.getInstance());
621 else if (type == Types.TIME)
622 return rs.getTime(i, Calendar.getInstance());
623 else if (type == Types.TIMESTAMP)
624 return rs.getTimestamp(i, Calendar.getInstance());
625 else if (type == Types.CLOB && cls.equals(String.class)) {
626 return toString(rs.getClob(i));
627 } else if (type == Types.CLOB && Reader.class.isAssignableFrom(cls)) {
628 Clob c = rs.getClob(i);
629 Reader r = c.getCharacterStream();
630 return createFreeOnCloseReader(c, r);
631 } else if (type == Types.BLOB && cls.equals(byte[].class)) {
632 return toBytes(rs.getBlob(i));
633 } else if (type == Types.BLOB && InputStream.class.isAssignableFrom(cls)) {
634 final Blob b = rs.getBlob(i);
635 final InputStream is = rs.getBlob(i).getBinaryStream();
636 return createFreeOnCloseInputStream(b, is);
637 } else
638 return rs.getObject(i);
639 } catch (SQLException e) {
640 throw new SQLRuntimeException(e);
641 }
642 }
643
644
645
646
647
648
649
650
651 private static byte[] toBytes(Blob b) {
652 try {
653 InputStream is = b.getBinaryStream();
654 byte[] result = IOUtils.toByteArray(is);
655 is.close();
656 b.free();
657 return result;
658 } catch (IOException e) {
659 throw new RuntimeException(e);
660 } catch (SQLException e) {
661 throw new SQLRuntimeException(e);
662 }
663
664 }
665
666
667
668
669
670
671
672 private static String toString(Clob c) {
673 try {
674 Reader reader = c.getCharacterStream();
675 String result = IOUtils.toString(reader);
676 reader.close();
677 c.free();
678 return result;
679 } catch (IOException e) {
680 throw new RuntimeException(e);
681 } catch (SQLException e) {
682 throw new SQLRuntimeException(e);
683 }
684 }
685
686
687
688
689
690
691
692
693
694 private static InputStream createFreeOnCloseInputStream(final Blob blob, final InputStream is) {
695 return new InputStream() {
696
697 @Override
698 public int read() throws IOException {
699 return is.read();
700 }
701
702 @Override
703 public void close() throws IOException {
704 try {
705 is.close();
706 } finally {
707 try {
708 blob.free();
709 } catch (SQLException e) {
710 log.debug(e.getMessage());
711 }
712 }
713 }
714 };
715 }
716
717
718
719
720
721
722
723
724
725 private static Reader createFreeOnCloseReader(final Clob clob, final Reader reader) {
726 return new Reader() {
727
728 @Override
729 public void close() throws IOException {
730 try {
731 reader.close();
732 } finally {
733 try {
734 clob.free();
735 } catch (SQLException e) {
736 log.debug(e.getMessage());
737 }
738 }
739 }
740
741 @Override
742 public int read(char[] cbuf, int off, int len) throws IOException {
743 return reader.read(cbuf, off, len);
744 }
745 };
746 }
747
748
749
750
751
752
753
754
755 static void setParameters(PreparedStatement ps, List<Parameter> params, boolean namesAllowed)
756 throws SQLException {
757 for (int i = 1; i <= params.size(); i++) {
758 if (params.get(i - 1).hasName() && !namesAllowed)
759 throw new SQLException("named parameter found but sql does not contain names");
760 Object o = params.get(i - 1).value();
761 try {
762 if (o == null)
763 ps.setObject(i, null);
764 else if (o == Database.NULL_CLOB)
765 ps.setNull(i, Types.CLOB);
766 else if (o == Database.NULL_BLOB)
767 ps.setNull(i, Types.BLOB);
768 else {
769 Class<?> cls = o.getClass();
770 if (Clob.class.isAssignableFrom(cls)) {
771 setClob(ps, i, o, cls);
772 } else if (Blob.class.isAssignableFrom(cls)) {
773 setBlob(ps, i, o, cls);
774 } else if (Calendar.class.isAssignableFrom(cls)) {
775 Calendar cal = (Calendar) o;
776 Timestamp t = new java.sql.Timestamp(cal.getTimeInMillis());
777 ps.setTimestamp(i, t, cal);
778 } else if (Time.class.isAssignableFrom(cls)) {
779 Calendar cal = Calendar.getInstance();
780 ps.setTime(i, (Time) o, cal);
781 } else if (Timestamp.class.isAssignableFrom(cls)) {
782 Calendar cal = Calendar.getInstance();
783 ps.setTimestamp(i, (Timestamp) o, cal);
784 } else if (java.sql.Date.class.isAssignableFrom(cls)) {
785 Calendar cal = Calendar.getInstance();
786 ps.setDate(i, (java.sql.Date) o, cal);
787 } else if (java.util.Date.class.isAssignableFrom(cls)) {
788 Calendar cal = Calendar.getInstance();
789 java.util.Date date = (java.util.Date) o;
790 ps.setTimestamp(i, new java.sql.Timestamp(date.getTime()), cal);
791 } else
792 ps.setObject(i, o);
793 }
794 } catch (SQLException e) {
795 log.debug("{} when setting ps.setObject({},{})", e.getMessage(), i, o);
796 throw e;
797 }
798 }
799 }
800
801
802
803
804
805
806
807
808
809
810 private static void setBlob(PreparedStatement ps, int i, Object o, Class<?> cls)
811 throws SQLException {
812 final InputStream is;
813 if (o instanceof byte[]) {
814 is = new ByteArrayInputStream((byte[]) o);
815 } else if (o instanceof InputStream)
816 is = (InputStream) o;
817 else
818 throw new RuntimeException("cannot insert parameter of type " + cls
819 + " into blob column " + i);
820 Blob c = ps.getConnection().createBlob();
821 OutputStream os = c.setBinaryStream(1);
822 copy(is, os);
823 ps.setBlob(i, c);
824 }
825
826
827
828
829
830
831
832
833
834
835 private static void setClob(PreparedStatement ps, int i, Object o, Class<?> cls)
836 throws SQLException {
837 final Reader r;
838 if (o instanceof String)
839 r = new StringReader((String) o);
840 else if (o instanceof Reader)
841 r = (Reader) o;
842 else
843 throw new RuntimeException("cannot insert parameter of type " + cls
844 + " into clob column " + i);
845 Clob c = ps.getConnection().createClob();
846 Writer w = c.setCharacterStream(1);
847 copy(r, w);
848 ps.setClob(i, c);
849 }
850
851
852
853
854
855
856
857
858 private static int copy(Reader input, Writer output) {
859 try {
860 return IOUtils.copy(input, output);
861 } catch (IOException e) {
862 throw new RuntimeException(e);
863 }
864 }
865
866
867
868
869
870
871
872
873 private static int copy(InputStream input, OutputStream output) {
874 try {
875 return IOUtils.copy(input, output);
876 } catch (IOException e) {
877 throw new RuntimeException(e);
878 }
879 }
880
881
882
883
884 public static final Func1<Reader, String> READER_TO_STRING = new Func1<Reader, String>() {
885 @Override
886 public String call(Reader r) {
887 try {
888 return IOUtils.toString(r);
889 } catch (IOException e) {
890 throw new RuntimeException(e);
891 }
892 }
893 };
894
895
896 private static final class ResultSetMapperToOne {
897 static final ResultSetMapper<Integer> INSTANCE = new ResultSetMapper<Integer>() {
898 @Override
899 public Integer call(ResultSet rs) {
900 return 1;
901 }
902 };
903 }
904
905 static ResultSetMapper<Integer> toOne() {
906 return ResultSetMapperToOne.INSTANCE;
907 }
908
909 public static void setNamedParameters(PreparedStatement ps, List<Parameter> parameters,
910 List<String> names) throws SQLException {
911 Map<String, Parameter> map = new HashMap<String, Parameter>();
912 for (Parameter p : parameters) {
913 if (p.hasName()) {
914 map.put(p.name(), p);
915 } else {
916 throw new SQLException(
917 "named parameters were expected but this parameter did not have a name: "
918 + p);
919 }
920 }
921 List<Parameter> list = new ArrayList<Parameter>();
922 for (String name : names) {
923 if (!map.containsKey(name))
924 throw new SQLException("named parameter is missing for '" + name + "'");
925 Parameter p = map.get(name);
926 list.add(p);
927 }
928 Util.setParameters(ps, list, true);
929 }
930
931 static void setParameters(PreparedStatement ps, List<Parameter> parameters, List<String> names)
932 throws SQLException {
933 if (names.isEmpty()) {
934 Util.setParameters(ps, parameters, false);
935 } else {
936 Util.setNamedParameters(ps, parameters, names);
937 }
938 }
939 }