comparison src/main/java/nl/cwi/monetdb/jdbc/MonetPreparedStatement.java @ 0:a5a898f6886c

Copy of MonetDB java directory changeset e6e32756ad31.
author Sjoerd Mullender <sjoerd@acm.org>
date Wed, 21 Sep 2016 09:34:48 +0200 (2016-09-21)
parents
children a0e8adf10d41
comparison
equal deleted inserted replaced
-1:000000000000 0:a5a898f6886c
1 /*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V.
7 */
8
9 package nl.cwi.monetdb.jdbc;
10
11 import java.sql.*;
12 import java.util.*;
13 import java.net.URL;
14 import java.io.*;
15 import java.nio.*;
16 import java.math.*; // BigDecimal, etc.
17 import java.text.SimpleDateFormat;
18
19 /**
20 * A {@link PreparedStatement} suitable for the MonetDB database.
21 *
22 * This implementation of the PreparedStatement interface uses the
23 * capabilities of the MonetDB/SQL backend to prepare and execute
24 * queries. The backend takes care of finding the '?'s in the input and
25 * returns the types it expects for them.
26 *
27 * An example of a server response on a prepare query is:
28 * <pre>
29 * % prepare select name from tables where id &gt; ? and id &lt; ?;
30 * &amp;5 0 2 3 2
31 * # prepare, prepare, prepare # table_name
32 * # type, digits, scale # name
33 * # varchar, int, int # type
34 * # 0, 0, 0 # length
35 * [ "int", 9, 0 ]
36 * [ "int", 9, 0 ]
37 * </pre>
38 *
39 * @author Fabian Groffen
40 * @version 0.3
41 */
42 public class MonetPreparedStatement
43 extends MonetStatement
44 implements PreparedStatement
45 {
46 private final String[] monetdbType;
47 private final int[] javaType;
48 private final int[] digits;
49 private final int[] scale;
50 private final String[] schema;
51 private final String[] table;
52 private final String[] column;
53 private final int id;
54 private final int size;
55 private final int rscolcnt;
56
57 private final String[] values;
58
59 private final MonetConnection connection;
60
61 /* only parse the date patterns once, use multiple times */
62 /** Format of a timestamp with RFC822 time zone */
63 final SimpleDateFormat mTimestampZ =
64 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
65 /** Format of a timestamp */
66 final SimpleDateFormat mTimestamp =
67 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
68 /** Format of a time with RFC822 time zone */
69 final SimpleDateFormat mTimeZ =
70 new SimpleDateFormat("HH:mm:ss.SSSZ");
71 /** Format of a time */
72 final SimpleDateFormat mTime =
73 new SimpleDateFormat("HH:mm:ss.SSS");
74 /** Format of a date used by mserver */
75 final SimpleDateFormat mDate =
76 new SimpleDateFormat("yyyy-MM-dd");
77
78 /**
79 * MonetPreparedStatement constructor which checks the arguments for
80 * validity. A MonetPreparedStatement is backed by a
81 * {@link MonetStatement}, which deals with most of the required stuff of
82 * this class.
83 *
84 * @param connection the connection that created this Statement
85 * @param resultSetType type of {@link ResultSet} to produce
86 * @param resultSetConcurrency concurrency of ResultSet to produce
87 * @param prepareQuery the query string to prepare
88 * @throws SQLException if an error occurs during login
89 * @throws IllegalArgumentException is one of the arguments is null or empty
90 */
91 MonetPreparedStatement(
92 MonetConnection connection,
93 int resultSetType,
94 int resultSetConcurrency,
95 int resultSetHoldability,
96 String prepareQuery)
97 throws SQLException, IllegalArgumentException
98 {
99 super(
100 connection,
101 resultSetType,
102 resultSetConcurrency,
103 resultSetHoldability
104 );
105
106 if (!super.execute("PREPARE " + prepareQuery))
107 throw new SQLException("Unexpected server response", "M0M10");
108
109 // cheat a bit to get the ID and the number of columns
110 id = ((MonetConnection.ResultSetResponse)header).id;
111 size = ((MonetConnection.ResultSetResponse)header).tuplecount;
112 rscolcnt = ((MonetConnection.ResultSetResponse)header).columncount;
113
114 // initialise blank finals
115 monetdbType = new String[size];
116 javaType = new int[size];
117 digits = new int[size];
118 scale = new int[size];
119 schema = new String[size];
120 table = new String[size];
121 column = new String[size];
122 values = new String[size];
123
124 this.connection = connection;
125
126 // fill the arrays
127 ResultSet rs = super.getResultSet();
128 for (int i = 0; rs.next(); i++) {
129 monetdbType[i] = rs.getString("type");
130 javaType[i] = MonetDriver.getJavaType(monetdbType[i]);
131 digits[i] = rs.getInt("digits");
132 scale[i] = rs.getInt("scale");
133 if (rscolcnt == 3)
134 continue;
135 schema[i] = rs.getString("schema");
136 table[i] = rs.getString("table");
137 column[i] = rs.getString("column");
138 }
139 rs.close();
140
141 // PreparedStatements are by default poolable
142 poolable = true;
143 }
144
145 /**
146 * Constructs an empty MonetPreparedStatement. This constructor is
147 * in particular useful for extensions of this class.
148 *
149 * @param connection the connection that created this Statement
150 * @param resultSetType type of ResultSet to produce
151 * @param resultSetConcurrency concurrency of ResultSet to produce
152 * @throws SQLException if an error occurs during login
153 */
154 /* Disabled this constructor code as it is not part of the JDBC interface
155 It may be enabled again when a subclass is constructed which needs it.
156 MonetPreparedStatement(
157 MonetConnection connection,
158 int resultSetType,
159 int resultSetConcurrency,
160 int resultSetHoldability)
161 throws SQLException
162 {
163 super(
164 connection,
165 resultSetType,
166 resultSetConcurrency,
167 resultSetHoldability
168 );
169 // initialise blank finals
170 monetdbType = null;
171 javaType = null;
172 digits = null;
173 scale = null;
174 schema = null;
175 table = null;
176 column = null;
177 values = null;
178 id = -1;
179 size = -1;
180 rscolcnt = -1;
181
182 this.connection = connection;
183 }
184 */
185
186 //== methods interface PreparedStatement
187
188 /**
189 * Adds a set of parameters to this PreparedStatement object's batch
190 * of commands.
191 *
192 * @throws SQLException if a database access error occurs
193 */
194 @Override
195 public void addBatch() throws SQLException {
196 super.addBatch(transform());
197 }
198
199 /** override the addBatch from the Statement to throw an SQLException */
200 @Override
201 public void addBatch(String q) throws SQLException {
202 throw new SQLException("This method is not available in a PreparedStatement!", "M1M05");
203 }
204
205 /**
206 * Clears the current parameter values immediately.
207 *
208 * In general, parameter values remain in force for repeated use of a
209 * statement. Setting a parameter value automatically clears its previous
210 * value. However, in some cases it is useful to immediately release the
211 * resources used by the current parameter values; this can be done by
212 * calling the method clearParameters.
213 */
214 @Override
215 public void clearParameters() {
216 for (int i = 0; i < values.length; i++) {
217 values[i] = null;
218 }
219 }
220
221 /**
222 * Executes the SQL statement in this PreparedStatement object,
223 * which may be any kind of SQL statement. Some prepared statements
224 * return multiple results; the execute method handles these complex
225 * statements as well as the simpler form of statements handled by
226 * the methods executeQuery and executeUpdate.
227 *
228 * The execute method returns a boolean to indicate the form of the
229 * first result. You must call either the method getResultSet or
230 * getUpdateCount to retrieve the result; you must call
231 * getMoreResults to move to any subsequent result(s).
232 *
233 * @return true if the first result is a ResultSet object; false if the
234 * first result is an update count or there is no result
235 * @throws SQLException if a database access error occurs or an argument
236 * is supplied to this method
237 */
238 @Override
239 public boolean execute() throws SQLException {
240 return super.execute(transform());
241 }
242
243 /** override the execute from the Statement to throw an SQLException */
244 @Override
245 public boolean execute(String q) throws SQLException {
246 throw new SQLException("This method is not available in a PreparedStatement!", "M1M05");
247 }
248
249 /**
250 * Executes the SQL query in this PreparedStatement object and returns the
251 * ResultSet object generated by the query.
252 *
253 * @return a ResultSet object that contains the data produced by the query;
254 * never null
255 * @throws SQLException if a database access error occurs or the SQL
256 * statement does not return a ResultSet object
257 */
258 @Override
259 public ResultSet executeQuery() throws SQLException{
260 if (execute() != true)
261 throw new SQLException("Query did not produce a result set", "M1M19");
262
263 return getResultSet();
264 }
265
266 /** override the executeQuery from the Statement to throw an SQLException*/
267 @Override
268 public ResultSet executeQuery(String q) throws SQLException {
269 throw new SQLException("This method is not available in a PreparedStatement!", "M1M05");
270 }
271
272 /**
273 * Executes the SQL statement in this PreparedStatement object, which must
274 * be an SQL INSERT, UPDATE or DELETE statement; or an SQL statement that
275 * returns nothing, such as a DDL statement.
276 *
277 * @return either (1) the row count for INSERT, UPDATE, or DELETE
278 * statements or (2) 0 for SQL statements that return nothing
279 * @throws SQLException if a database access error occurs or the SQL
280 * statement returns a ResultSet object
281 */
282 @Override
283 public int executeUpdate() throws SQLException {
284 if (execute() != false)
285 throw new SQLException("Query produced a result set", "M1M17");
286
287 return getUpdateCount();
288 }
289
290 /** override the executeUpdate from the Statement to throw an SQLException*/
291 @Override
292 public int executeUpdate(String q) throws SQLException {
293 throw new SQLException("This method is not available in a PreparedStatement!", "M1M05");
294 }
295
296 /**
297 * Returns the index (0..size-1) in the backing arrays for the given
298 * resultset column number or an SQLException when not found
299 */
300 private int getColumnIdx(int colnr) throws SQLException {
301 int curcol = 0;
302 for (int i = 0; i < size; i++) {
303 if (column[i] == null)
304 continue;
305 curcol++;
306 if (curcol == colnr)
307 return i;
308 }
309 throw new SQLException("No such column with index: " + colnr, "M1M05");
310 }
311 /**
312 * Returns the index (0..size-1) in the backing arrays for the given
313 * parameter number or an SQLException when not found
314 */
315 private int getParamIdx(int paramnr) throws SQLException {
316 int curparam = 0;
317 for (int i = 0; i < size; i++) {
318 if (column[i] != null)
319 continue;
320 curparam++;
321 if (curparam == paramnr)
322 return i;
323 }
324 throw new SQLException("No such parameter with index: " + paramnr, "M1M05");
325 }
326
327
328 /* helper for the anonymous class inside getMetaData */
329 private abstract class rsmdw extends MonetWrapper implements ResultSetMetaData {}
330 /**
331 * Retrieves a ResultSetMetaData object that contains information
332 * about the columns of the ResultSet object that will be returned
333 * when this PreparedStatement object is executed.
334 *
335 * Because a PreparedStatement object is precompiled, it is possible
336 * to know about the ResultSet object that it will return without
337 * having to execute it. Consequently, it is possible to invoke the
338 * method getMetaData on a PreparedStatement object rather than
339 * waiting to execute it and then invoking the ResultSet.getMetaData
340 * method on the ResultSet object that is returned.
341 *
342 * @return the description of a ResultSet object's columns or null if the
343 * driver cannot return a ResultSetMetaData object
344 * @throws SQLException if a database access error occurs
345 */
346 @Override
347 public ResultSetMetaData getMetaData() {
348 if (rscolcnt == 3)
349 return null; // not sufficient data with pre-Dec2011 PREPARE
350
351 // return inner class which implements the ResultSetMetaData interface
352 return new rsmdw() {
353 /**
354 * Returns the number of columns in this ResultSet object.
355 *
356 * @returns the number of columns
357 */
358 @Override
359 public int getColumnCount() {
360 int cnt = 0;
361
362 for (int i = 0; i < size; i++) {
363 if (column[i] != null)
364 cnt++;
365 }
366 return cnt;
367 }
368
369 /**
370 * Indicates whether the designated column is automatically numbered.
371 *
372 * @param column the first column is 1, the second is 2, ...
373 * @return true if so; false otherwise
374 * @throws SQLException if a database access error occurs
375 */
376 @Override
377 public boolean isAutoIncrement(int column) throws SQLException {
378 /* TODO: in MonetDB only numeric (int, decimal) columns could be autoincrement/serial
379 * This however requires an expensive dbmd.getColumns(null, schema, table, column)
380 * query call to pull the IS_AUTOINCREMENT value for this column.
381 * See also ResultSetMetaData.isAutoIncrement()
382 */
383 // For now we simply allways return false.
384 return false;
385 }
386
387 /**
388 * Indicates whether a column's case matters.
389 *
390 * @param column the first column is 1, the second is 2, ...
391 * @returns false
392 */
393 @Override
394 public boolean isCaseSensitive(int column) throws SQLException {
395 switch (javaType[getColumnIdx(column)]) {
396 case Types.CHAR:
397 case Types.VARCHAR:
398 case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR, it's here for completeness
399 case Types.CLOB:
400 return true;
401 }
402
403 return false;
404 }
405
406 /**
407 * Indicates whether the designated column can be used in a
408 * where clause.
409 *
410 * Returning true for all here, even for CLOB, BLOB.
411 *
412 * @param column the first column is 1, the second is 2, ...
413 * @returns true
414 */
415 @Override
416 public boolean isSearchable(int column) {
417 return true;
418 }
419
420 /**
421 * Indicates whether the designated column is a cash value.
422 * From the MonetDB database perspective it is by definition
423 * unknown whether the value is a currency, because there are
424 * no currency datatypes such as MONEY. With this knowledge
425 * we can always return false here.
426 *
427 * @param column the first column is 1, the second is 2, ...
428 * @returns false
429 */
430 @Override
431 public boolean isCurrency(int column) {
432 return false;
433 }
434
435 /**
436 * Indicates whether values in the designated column are signed
437 * numbers.
438 * Within MonetDB all numeric types (except oid and ptr) are signed.
439 *
440 * @param column the first column is 1, the second is 2, ...
441 * @return true if so; false otherwise
442 */
443 @Override
444 public boolean isSigned(int column) throws SQLException {
445 String monettype = getColumnTypeName(column);
446 if (monettype != null) {
447 if ("oid".equals(monettype)
448 || "ptr".equals(monettype))
449 return false;
450 }
451 // we can hardcode this, based on the colum type
452 switch (javaType[getColumnIdx(column)]) {
453 case Types.NUMERIC:
454 case Types.DECIMAL:
455 case Types.TINYINT:
456 case Types.SMALLINT:
457 case Types.INTEGER:
458 case Types.BIGINT:
459 case Types.REAL:
460 case Types.FLOAT:
461 case Types.DOUBLE:
462 return true;
463 case Types.BIT: // we don't use type BIT, it's here for completeness
464 case Types.BOOLEAN:
465 case Types.DATE:
466 case Types.TIME:
467 case Types.TIMESTAMP:
468 default:
469 return false;
470 }
471 }
472
473 /**
474 * Indicates the designated column's normal maximum width in
475 * characters.
476 *
477 * @param column the first column is 1, the second is 2, ...
478 * @return the normal maximum number of characters allowed as the
479 * width of the designated column
480 * @throws SQLException if there is no such column
481 */
482 @Override
483 public int getColumnDisplaySize(int column) throws SQLException {
484 return digits[getColumnIdx(column)];
485 }
486
487 /**
488 * Get the designated column's table's schema.
489 *
490 * @param column the first column is 1, the second is 2, ...
491 * @return schema name or "" if not applicable
492 * @throws SQLException if a database access error occurs
493 */
494 @Override
495 public String getSchemaName(int column) throws SQLException {
496 return schema[getColumnIdx(column)];
497 }
498
499 /**
500 * Gets the designated column's table name.
501 *
502 * @param column the first column is 1, the second is 2, ...
503 * @return table name or "" if not applicable
504 */
505 @Override
506 public String getTableName(int col) throws SQLException {
507 return table[getColumnIdx(col)];
508 }
509
510 /**
511 * Get the designated column's number of decimal digits.
512 * This method is currently very expensive as it needs to
513 * retrieve the information from the database using an SQL
514 * query.
515 *
516 * @param column the first column is 1, the second is 2, ...
517 * @return precision
518 * @throws SQLException if a database access error occurs
519 */
520 @Override
521 public int getPrecision(int column) throws SQLException {
522 return digits[getColumnIdx(column)];
523 }
524
525 /**
526 * Gets the designated column's number of digits to right of
527 * the decimal point. This method is currently very
528 * expensive as it needs to retrieve the information from
529 * the database using an SQL query.
530 *
531 * @param column the first column is 1, the second is 2, ...
532 * @return scale
533 * @throws SQLException if a database access error occurs
534 */
535 @Override
536 public int getScale(int column) throws SQLException {
537 return scale[getColumnIdx(column)];
538 }
539
540 /**
541 * Indicates the nullability of values in the designated
542 * column. This method is currently very expensive as it
543 * needs to retrieve the information from the database using
544 * an SQL query.
545 *
546 * @param column the first column is 1, the second is 2, ...
547 * @return nullability
548 * @throws SQLException if a database access error occurs
549 */
550 @Override
551 public int isNullable(int column) throws SQLException {
552 return columnNullableUnknown;
553 }
554
555 /**
556 * Gets the designated column's table's catalog name.
557 * MonetDB does not support the catalog naming concept as in: catalog.schema.table naming scheme
558 *
559 * @param column the first column is 1, the second is 2, ...
560 * @return the name of the catalog for the table in which the given
561 * column appears or "" if not applicable
562 */
563 @Override
564 public String getCatalogName(int column) throws SQLException {
565 return null; // MonetDB does NOT support catalogs
566 }
567
568 /**
569 * Indicates whether the designated column is definitely not
570 * writable. MonetDB does not support cursor updates, so
571 * nothing is writable.
572 *
573 * @param column the first column is 1, the second is 2, ...
574 * @return true if so; false otherwise
575 */
576 @Override
577 public boolean isReadOnly(int column) {
578 return true;
579 }
580
581 /**
582 * Indicates whether it is possible for a write on the
583 * designated column to succeed.
584 *
585 * @param column the first column is 1, the second is 2, ...
586 * @return true if so; false otherwise
587 */
588 @Override
589 public boolean isWritable(int column) {
590 return false;
591 }
592
593 /**
594 * Indicates whether a write on the designated column will
595 * definitely succeed.
596 *
597 * @param column the first column is 1, the second is 2, ...
598 * @return true if so; false otherwise
599 */
600 @Override
601 public boolean isDefinitelyWritable(int column) {
602 return false;
603 }
604
605 /**
606 * Returns the fully-qualified name of the Java class whose
607 * instances are manufactured if the method
608 * ResultSet.getObject is called to retrieve a value from
609 * the column. ResultSet.getObject may return a subclass of
610 * the class returned by this method.
611 *
612 * @param column the first column is 1, the second is 2, ...
613 * @return the fully-qualified name of the class in the Java
614 * programming language that would be used by the method
615 * ResultSet.getObject to retrieve the value in the
616 * specified column. This is the class name used for custom
617 * mapping.
618 * @throws SQLException if there is no such column
619 */
620 @Override
621 public String getColumnClassName(int column) throws SQLException {
622 return MonetResultSet.getClassForType(javaType[getColumnIdx(column)]).getName();
623 }
624
625 /**
626 * Gets the designated column's suggested title for use in
627 * printouts and displays. This is currently equal to
628 * getColumnName().
629 *
630 * @param column the first column is 1, the second is 2, ...
631 * @return the suggested column title
632 * @throws SQLException if there is no such column
633 */
634 @Override
635 public String getColumnLabel(int column) throws SQLException {
636 return getColumnName(column);
637 }
638
639 /**
640 * Gets the designated column's name
641 *
642 * @param column the first column is 1, the second is 2, ...
643 * @return the column name
644 * @throws SQLException if there is no such column
645 */
646 @Override
647 public String getColumnName(int col) throws SQLException {
648 return column[getColumnIdx(col)];
649 }
650
651 /**
652 * Retrieves the designated column's SQL type.
653 *
654 * @param column the first column is 1, the second is 2, ...
655 * @return SQL type from java.sql.Types
656 * @throws SQLException if there is no such column
657 */
658 @Override
659 public int getColumnType(int column) throws SQLException {
660 return javaType[getColumnIdx(column)];
661 }
662
663 /**
664 * Retrieves the designated column's database-specific type name.
665 *
666 * @param column the first column is 1, the second is 2, ...
667 * @return type name used by the database. If the column type is a
668 * user-defined type, then a fully-qualified type name is
669 * returned.
670 * @throws SQLException if there is no such column
671 */
672 @Override
673 public String getColumnTypeName(int column) throws SQLException {
674 return monetdbType[getColumnIdx(column)];
675 }
676 };
677 }
678
679 /* helper class for the anonymous class in getParameterMetaData */
680 private abstract class pmdw extends MonetWrapper implements ParameterMetaData {}
681 /**
682 * Retrieves the number, types and properties of this
683 * PreparedStatement object's parameters.
684 *
685 * @return a ParameterMetaData object that contains information
686 * about the number, types and properties of this
687 * PreparedStatement object's parameters
688 * @throws SQLException if a database access error occurs
689 */
690 @Override
691 public ParameterMetaData getParameterMetaData() throws SQLException {
692 return new pmdw() {
693 /**
694 * Retrieves the number of parameters in the
695 * PreparedStatement object for which this ParameterMetaData
696 * object contains information.
697 *
698 * @return the number of parameters
699 * @throws SQLException if a database access error occurs
700 */
701 @Override
702 public int getParameterCount() throws SQLException {
703 int cnt = 0;
704
705 for (int i = 0; i < size; i++) {
706 if (column[i] == null)
707 cnt++;
708 }
709
710 return cnt;
711 }
712
713 /**
714 * Retrieves whether null values are allowed in the
715 * designated parameter.
716 *
717 * This is currently always unknown for MonetDB/SQL.
718 *
719 * @param param the first parameter is 1, the second is 2, ...
720 * @return the nullability status of the given parameter;
721 * one of ParameterMetaData.parameterNoNulls,
722 * ParameterMetaData.parameterNullable, or
723 * ParameterMetaData.parameterNullableUnknown
724 * @throws SQLException if a database access error occurs
725 */
726 @Override
727 public int isNullable(int param) throws SQLException {
728 return ParameterMetaData.parameterNullableUnknown;
729 }
730
731 /**
732 * Retrieves whether values for the designated parameter can
733 * be signed numbers.
734 *
735 * @param param the first parameter is 1, the second is 2, ...
736 * @return true if so; false otherwise
737 * @throws SQLException if a database access error occurs
738 */
739 @Override
740 public boolean isSigned(int param) throws SQLException {
741 // we can hardcode this, based on the colum type
742 // (from ResultSetMetaData.isSigned)
743 switch (javaType[getParamIdx(param)]) {
744 case Types.NUMERIC:
745 case Types.DECIMAL:
746 case Types.TINYINT:
747 case Types.SMALLINT:
748 case Types.INTEGER:
749 case Types.BIGINT:
750 case Types.REAL:
751 case Types.FLOAT:
752 case Types.DOUBLE:
753 return true;
754 case Types.BIT: // we don't use type BIT, it's here for completeness
755 case Types.BOOLEAN:
756 case Types.DATE:
757 case Types.TIME:
758 case Types.TIMESTAMP:
759 default:
760 return false;
761 }
762 }
763
764 /**
765 * Retrieves the designated parameter's number of decimal
766 * digits.
767 *
768 * @param param the first parameter is 1, the second is 2, ...
769 * @return precision
770 * @throws SQLException if a database access error occurs
771 */
772 @Override
773 public int getPrecision(int param) throws SQLException {
774 return digits[getParamIdx(param)];
775 }
776
777 /**
778 * Retrieves the designated parameter's number of digits to
779 * right of the decimal point.
780 *
781 * @param param the first parameter is 1, the second is 2, ...
782 * @return scale
783 * @throws SQLException if a database access error occurs
784 */
785 @Override
786 public int getScale(int param) throws SQLException {
787 return scale[getParamIdx(param)];
788 }
789
790 /**
791 * Retrieves the designated parameter's SQL type.
792 *
793 * @param param the first parameter is 1, the second is 2, ...
794 * @return SQL type from java.sql.Types
795 * @throws SQLException if a database access error occurs
796 */
797 @Override
798 public int getParameterType(int param) throws SQLException {
799 return javaType[getParamIdx(param)];
800 }
801
802 /**
803 * Retrieves the designated parameter's database-specific
804 * type name.
805 *
806 * @param param the first parameter is 1, the second is 2, ...
807 * @return type the name used by the database. If the
808 * parameter type is a user-defined type, then a
809 * fully-qualified type name is returned.
810 * @throws SQLException if a database access error occurs
811 */
812 @Override
813 public String getParameterTypeName(int param) throws SQLException {
814 return monetdbType[getParamIdx(param)];
815 }
816
817 /**
818 * Retrieves the fully-qualified name of the Java class
819 * whose instances should be passed to the method
820 * PreparedStatement.setObject.
821 *
822 * @param param the first parameter is 1, the second is 2, ...
823 * @return the fully-qualified name of the class in the Java
824 * programming language that would be used by the
825 * method PreparedStatement.setObject to set the
826 * value in the specified parameter. This is the
827 * class name used for custom mapping.
828 * @throws SQLException if a database access error occurs
829 */
830 @Override
831 public String getParameterClassName(int param) throws SQLException {
832 Map<String,Class<?>> map = getConnection().getTypeMap();
833 Class<?> c;
834 if (map.containsKey(monetdbType[getParamIdx(param)])) {
835 c = (Class)map.get(monetdbType[getParamIdx(param)]);
836 } else {
837 c = MonetResultSet.getClassForType(
838 javaType[getParamIdx(param)]
839 );
840 }
841 return c.getName();
842 }
843
844 /**
845 * Retrieves the designated parameter's mode.
846 * For MonetDB/SQL this is currently always unknown.
847 *
848 * @param param - the first parameter is 1, the second is 2, ...
849 * @return mode of the parameter; one of
850 * ParameterMetaData.parameterModeIn,
851 * ParameterMetaData.parameterModeOut, or
852 * ParameterMetaData.parameterModeInOut
853 * ParameterMetaData.parameterModeUnknown.
854 * @throws SQLException if a database access error occurs
855 */
856 @Override
857 public int getParameterMode(int param) throws SQLException {
858 return ParameterMetaData.parameterModeUnknown;
859 }
860 };
861 }
862
863 /**
864 * Sets the designated parameter to the given Array object. The
865 * driver converts this to an SQL ARRAY value when it sends it to
866 * the database.
867 *
868 * @param i the first parameter is 1, the second is 2, ...
869 * @param x an Array object that maps an SQL ARRAY value
870 * @throws SQLException if a database access error occurs
871 */
872 @Override
873 public void setArray(int i, Array x) throws SQLException {
874 throw new SQLException("Operation setArray(int i, Array x) currently not supported!", "0A000");
875 }
876
877 /**
878 * Sets the designated parameter to the given input stream, which will have
879 * the specified number of bytes. When a very large ASCII value is input to
880 * a LONGVARCHAR parameter, it may be more practical to send it via a
881 * java.io.InputStream. Data will be read from the stream as needed until
882 * end-of-file is reached. The JDBC driver will do any necessary conversion
883 * from ASCII to the database char format.
884 *
885 * Note: This stream object can either be a standard Java stream object or
886 * your own subclass that implements the standard interface.
887 *
888 * @param parameterIndex the first parameter is 1, the second is 2, ...
889 * @param x the Java input stream that contains the ASCII parameter value
890 * @throws SQLException if a database access error occurs
891 * @throws SQLFeatureNotSupportedException the JDBC driver does
892 * not support this method
893 */
894 @Override
895 public void setAsciiStream(int parameterIndex, InputStream x)
896 throws SQLException
897 {
898 throw newSQLFeatureNotSupportedException("setAsciiStream");
899 }
900
901 /**
902 * Sets the designated parameter to the given input stream, which will have
903 * the specified number of bytes. When a very large ASCII value is input to
904 * a LONGVARCHAR parameter, it may be more practical to send it via a
905 * java.io.InputStream. Data will be read from the stream as needed until
906 * end-of-file is reached. The JDBC driver will do any necessary conversion
907 * from ASCII to the database char format.
908 *
909 * Note: This stream object can either be a standard Java stream object or
910 * your own subclass that implements the standard interface.
911 *
912 * @param parameterIndex the first parameter is 1, the second is 2, ...
913 * @param x the Java input stream that contains the ASCII parameter value
914 * @param length the number of bytes in the stream
915 * @throws SQLException if a database access error occurs
916 */
917 @Override
918 public void setAsciiStream(int parameterIndex, InputStream x, int length)
919 throws SQLException
920 {
921 throw newSQLFeatureNotSupportedException("setAsciiStream");
922 }
923
924 /**
925 * Sets the designated parameter to the given input stream, which
926 * will have the specified number of bytes. When a very large ASCII
927 * value is input to a LONGVARCHAR parameter, it may be more
928 * practical to send it via a java.io.InputStream. Data will be read
929 * from the stream as needed until end-of-file is reached. The JDBC
930 * driver will do any necessary conversion from ASCII to the
931 * database char format.
932 *
933 * Note: This stream object can either be a standard Java stream object or
934 * your own subclass that implements the standard interface.
935 *
936 * @param parameterIndex the first parameter is 1, the second is 2, ...
937 * @param x the Java input stream that contains the ASCII parameter value
938 * @param length the number of bytes in the stream
939 * @throws SQLException if a database access error occurs
940 * @throws SQLFeatureNotSupportedException the JDBC driver does
941 * not support this method
942 */
943 @Override
944 public void setAsciiStream(int parameterIndex, InputStream x, long length)
945 throws SQLException
946 {
947 throw newSQLFeatureNotSupportedException("setAsciiStream");
948 }
949
950 /**
951 * Sets the designated parameter to the given java.math.BigDecimal value.
952 * The driver converts this to an SQL NUMERIC value when it sends it to the
953 * database.
954 *
955 * @param idx the first parameter is 1, the second is 2, ...
956 * @param x the parameter value
957 * @throws SQLException if a database access error occurs
958 */
959 @Override
960 public void setBigDecimal(int idx, BigDecimal x)
961 throws SQLException
962 {
963 // get array position
964 int i = getParamIdx(idx);
965
966 // round to the scale of the DB:
967 x = x.setScale(scale[i], RoundingMode.HALF_UP);
968
969 // if precision is now greater than that of the db, throw an error:
970 if (x.precision() > digits[i]) {
971 throw new SQLDataException("DECIMAL value exceeds allowed digits/scale: " + x.toPlainString() + " (" + digits[i] + "/" + scale[i] + ")", "22003");
972 }
973
974 // MonetDB doesn't like leading 0's, since it counts them as part of
975 // the precision, so let's strip them off. (But be careful not to do
976 // this to the exact number "0".) Also strip off trailing
977 // numbers that are inherent to the double representation.
978 String xStr = x.toPlainString();
979 int dot = xStr.indexOf(".");
980 if (dot >= 0)
981 xStr = xStr.substring(0, Math.min(xStr.length(), dot + 1 + scale[i]));
982 while (xStr.startsWith("0") && xStr.length() > 1)
983 xStr = xStr.substring(1);
984 setValue(idx, xStr);
985 }
986
987 /**
988 * Sets the designated parameter to the given input stream, which will have
989 * the specified number of bytes. When a very large binary value is input
990 * to a LONGVARBINARY parameter, it may be more practical to send it via a
991 * java.io.InputStream object. The data will be read from the stream as
992 * needed until end-of-file is reached.
993 *
994 * Note: This stream object can either be a standard Java stream object or
995 * your own subclass that implements the standard interface.
996 *
997 * @param parameterIndex the first parameter is 1, the second is 2, ...
998 * @param x the java input stream which contains the binary parameter value
999 * @throws SQLException if a database access error occurs
1000 * @throws SQLFeatureNotSupportedException the JDBC driver does
1001 * not support this method
1002 */
1003 @Override
1004 public void setBinaryStream(int parameterIndex, InputStream x)
1005 throws SQLException
1006 {
1007 throw newSQLFeatureNotSupportedException("setBinaryStream");
1008 }
1009
1010 /**
1011 * Sets the designated parameter to the given input stream, which will have
1012 * the specified number of bytes. When a very large binary value is input
1013 * to a LONGVARBINARY parameter, it may be more practical to send it via a
1014 * java.io.InputStream object. The data will be read from the stream as
1015 * needed until end-of-file is reached.
1016 *
1017 * Note: This stream object can either be a standard Java stream object or
1018 * your own subclass that implements the standard interface.
1019 *
1020 * @param parameterIndex the first parameter is 1, the second is 2, ...
1021 * @param x the java input stream which contains the binary parameter value
1022 * @param length the number of bytes in the stream
1023 * @throws SQLException if a database access error occurs
1024 * @throws SQLFeatureNotSupportedException the JDBC driver does
1025 * not support this method
1026 */
1027 @Override
1028 public void setBinaryStream(int parameterIndex, InputStream x, int length)
1029 throws SQLException
1030 {
1031 throw newSQLFeatureNotSupportedException("setBinaryStream");
1032 }
1033
1034 /**
1035 * Sets the designated parameter to the given input stream, which will have
1036 * the specified number of bytes. When a very large binary value is input
1037 * to a LONGVARBINARY parameter, it may be more practical to send it via a
1038 * java.io.InputStream object. The data will be read from the stream as
1039 * needed until end-of-file is reached.
1040 *
1041 * Note: This stream object can either be a standard Java stream object or
1042 * your own subclass that implements the standard interface.
1043 *
1044 * @param parameterIndex the first parameter is 1, the second is 2, ...
1045 * @param x the java input stream which contains the binary parameter value
1046 * @param length the number of bytes in the stream
1047 * @throws SQLException if a database access error occurs
1048 * @throws SQLFeatureNotSupportedException the JDBC driver does
1049 * not support this method
1050 */
1051 @Override
1052 public void setBinaryStream(int parameterIndex, InputStream x, long length)
1053 throws SQLException
1054 {
1055 throw newSQLFeatureNotSupportedException("setBinaryStream");
1056 }
1057
1058 /**
1059 * Sets the designated parameter to the given Blob object. The driver
1060 * converts this to an SQL BLOB value when it sends it to the database.
1061 *
1062 * @param i the first parameter is 1, the second is 2, ...
1063 * @param x a Blob object that maps an SQL BLOB value
1064 * @throws SQLException if a database access error occurs
1065 * @throws SQLFeatureNotSupportedException the JDBC driver does
1066 * not support this method
1067 */
1068 @Override
1069 public void setBlob(int i, InputStream x) throws SQLException {
1070 throw newSQLFeatureNotSupportedException("setBlob");
1071 }
1072
1073 /**
1074 * Sets the designated parameter to the given Blob object. The driver
1075 * converts this to an SQL BLOB value when it sends it to the database.
1076 *
1077 * @param i the first parameter is 1, the second is 2, ...
1078 * @param x a Blob object that maps an SQL BLOB value
1079 * @throws SQLException if a database access error occurs
1080 * @throws SQLFeatureNotSupportedException the JDBC driver does
1081 * not support this method
1082 */
1083 @Override
1084 public void setBlob(int i, Blob x) throws SQLException {
1085 throw newSQLFeatureNotSupportedException("setBlob");
1086 }
1087
1088 /**
1089 * Sets the designated parameter to a InputStream object. The
1090 * inputstream must contain the number of characters specified by
1091 * length otherwise a SQLException will be generated when the
1092 * PreparedStatement is executed. This method differs from the
1093 * setBinaryStream (int, InputStream, int) method because it informs
1094 * the driver that the parameter value should be sent to the server
1095 * as a BLOB. When the setBinaryStream method is used, the driver
1096 * may have to do extra work to determine whether the parameter data
1097 * should be sent to the server as a LONGVARBINARY or a BLOB.
1098 *
1099 * @param i the first parameter is 1, the second is 2, ...
1100 * @param is an object that contains the data to set the parameter
1101 * value to
1102 * @param length the number of bytes in the parameter data
1103 * @throws SQLException if a database access error occurs
1104 * @throws SQLFeatureNotSupportedException the JDBC driver does
1105 * not support this method
1106 */
1107 @Override
1108 public void setBlob(int i, InputStream is, long length) throws SQLException {
1109 throw newSQLFeatureNotSupportedException("setBlob");
1110 }
1111
1112 /**
1113 * Sets the designated parameter to the given Java boolean value. The
1114 * driver converts this to an SQL BIT value when it sends it to the
1115 * database.
1116 *
1117 * @param parameterIndex the first parameter is 1, the second is 2, ...
1118 * @param x the parameter value
1119 * @throws SQLException if a database access error occurs
1120 */
1121 @Override
1122 public void setBoolean(int parameterIndex, boolean x) throws SQLException {
1123 setValue(parameterIndex, "" + x);
1124 }
1125
1126 /**
1127 * Sets the designated parameter to the given Java byte value. The driver
1128 * converts this to an SQL TINYINT value when it sends it to the database.
1129 *
1130 * @param parameterIndex the first parameter is 1, the second is 2, ...
1131 * @param x the parameter value
1132 * @throws SQLException if a database access error occurs
1133 */
1134 @Override
1135 public void setByte(int parameterIndex, byte x) throws SQLException {
1136 setValue(parameterIndex, "" + x);
1137 }
1138
1139 static final String HEXES = "0123456789ABCDEF";
1140 /**
1141 * Sets the designated parameter to the given Java array of bytes. The
1142 * driver converts this to an SQL VARBINARY or LONGVARBINARY (depending
1143 * on the argument's size relative to the driver's limits on VARBINARY
1144 * values) when it sends it to the database.
1145 *
1146 * @param parameterIndex the first parameter is 1, the second is 2, ...
1147 * @param x the parameter value
1148 * @throws SQLException if a database access error occurs
1149 */
1150 @Override
1151 public void setBytes(int parameterIndex, byte[] x) throws SQLException {
1152 if (x == null) {
1153 setNull(parameterIndex, -1);
1154 return;
1155 }
1156
1157 StringBuilder hex = new StringBuilder(x.length * 2);
1158 byte b;
1159 for (int i = 0; i < x.length; i++) {
1160 b = x[i];
1161 hex.append(HEXES.charAt((b & 0xF0) >> 4))
1162 .append(HEXES.charAt((b & 0x0F)));
1163 }
1164 setValue(parameterIndex, "blob '" + hex.toString() + "'");
1165 }
1166
1167 /**
1168 * Sets the designated parameter to the given Reader object, which is the
1169 * given number of characters long. When a very large UNICODE value is
1170 * input to a LONGVARCHAR parameter, it may be more practical to send it
1171 * via a java.io.Reader object. The data will be read from the stream as
1172 * needed until end-of-file is reached. The JDBC driver will do any
1173 * necessary conversion from UNICODE to the database char format.
1174 *
1175 * Note: This stream object can either be a standard Java stream object or
1176 * your own subclass that implements the standard interface.
1177 *
1178 * @param parameterIndex the first parameter is 1, the second is 2, ...
1179 * @param reader the java.io.Reader object that contains the Unicode data
1180 * @param length the number of characters in the stream
1181 * @throws SQLException if a database access error occurs
1182 */
1183 @Override
1184 public void setCharacterStream(
1185 int parameterIndex,
1186 Reader reader,
1187 int length)
1188 throws SQLException
1189 {
1190 if (reader == null) {
1191 setNull(parameterIndex, -1);
1192 return;
1193 }
1194
1195 CharBuffer tmp = CharBuffer.allocate(length);
1196 try {
1197 reader.read(tmp);
1198 } catch (IOException e) {
1199 throw new SQLException(e.getMessage(), "M1M25");
1200 }
1201 setString(parameterIndex, tmp.toString());
1202 }
1203
1204 /**
1205 * Sets the designated parameter to the given Reader object, which is the
1206 * given number of characters long. When a very large UNICODE value is
1207 * input to a LONGVARCHAR parameter, it may be more practical to send it
1208 * via a java.io.Reader object. The data will be read from the stream as
1209 * needed until end-of-file is reached. The JDBC driver will do any
1210 * necessary conversion from UNICODE to the database char format.
1211 *
1212 * Note: This stream object can either be a standard Java stream object or
1213 * your own subclass that implements the standard interface.
1214 *
1215 * @param parameterIndex the first parameter is 1, the second is 2, ...
1216 * @param reader the java.io.Reader object that contains the Unicode data
1217 * @throws SQLException if a database access error occurs
1218 * @throws SQLFeatureNotSupportedException the JDBC driver does
1219 * not support this method
1220 */
1221 @Override
1222 public void setCharacterStream(int parameterIndex, Reader reader)
1223 throws SQLException
1224 {
1225 setCharacterStream(parameterIndex, reader, 0);
1226 }
1227
1228 /**
1229 * Sets the designated parameter to the given Reader object, which is the
1230 * given number of characters long. When a very large UNICODE value is
1231 * input to a LONGVARCHAR parameter, it may be more practical to send it
1232 * via a java.io.Reader object. The data will be read from the stream as
1233 * needed until end-of-file is reached. The JDBC driver will do any
1234 * necessary conversion from UNICODE to the database char format.
1235 *
1236 * Note: This stream object can either be a standard Java stream object or
1237 * your own subclass that implements the standard interface.
1238 *
1239 * @param parameterIndex the first parameter is 1, the second is 2, ...
1240 * @param reader the java.io.Reader object that contains the Unicode data
1241 * @param length the number of characters in the stream
1242 * @throws SQLException if a database access error occurs
1243 */
1244 @Override
1245 public void setCharacterStream(
1246 int parameterIndex,
1247 Reader reader,
1248 long length)
1249 throws SQLException
1250 {
1251 // given the implementation of the int-version, downcast is ok
1252 setCharacterStream(parameterIndex, reader, (int)length);
1253 }
1254
1255 /**
1256 * Sets the designated parameter to the given Clob object. The driver
1257 * converts this to an SQL CLOB value when it sends it to the database.
1258 *
1259 * @param i the first parameter is 1, the second is 2, ...
1260 * @param x a Clob object that maps an SQL CLOB value
1261 * @throws SQLException if a database access error occurs
1262 */
1263 @Override
1264 public void setClob(int i, Clob x) throws SQLException {
1265 if (x == null) {
1266 setNull(i, -1);
1267 return;
1268 }
1269
1270 // simply serialise the CLOB into a variable for now... far from
1271 // efficient, but might work for a few cases...
1272 // be on your marks: we have to cast the length down!
1273 setString(i, x.getSubString(1L, (int)(x.length())));
1274 }
1275
1276 /**
1277 * Sets the designated parameter to the given Clob object. The driver
1278 * converts this to an SQL CLOB value when it sends it to the database.
1279 *
1280 * @param i the first parameter is 1, the second is 2, ...
1281 * @param reader an object that contains the data to set the parameter
1282 * value to
1283 * @throws SQLException if a database access error occurs
1284 * @throws SQLFeatureNotSupportedException the JDBC driver does
1285 * not support this method
1286 */
1287 @Override
1288 public void setClob(int i, Reader reader) throws SQLException {
1289 if (reader == null) {
1290 setNull(i, -1);
1291 return;
1292 }
1293 // Some buffer. Size of 8192 is default for BufferedReader, so...
1294 char[] arr = new char[8192];
1295 StringBuilder buf = new StringBuilder(8192 * 8);
1296 int numChars;
1297 try {
1298 while ((numChars = reader.read(arr, 0, arr.length)) > 0) {
1299 buf.append(arr, 0, numChars);
1300 }
1301 setString(i, buf.toString());
1302 } catch (IOException e) {
1303 throw new SQLException(e);
1304 }
1305 }
1306
1307 /**
1308 * Sets the designated parameter to a Reader object. The reader must
1309 * contain the number of characters specified by length otherwise a
1310 * SQLException will be generated when the PreparedStatement is
1311 * executed. This method differs from the setCharacterStream (int,
1312 * Reader, int) method because it informs the driver that the
1313 * parameter value should be sent to the server as a CLOB. When the
1314 * setCharacterStream method is used, the driver may have to do
1315 * extra work to determine whether the parameter data should be sent
1316 * to the server as a LONGVARCHAR or a CLOB.
1317 *
1318 * @param i the first parameter is 1, the second is 2, ...
1319 * @param reader An object that contains the data to set the
1320 * parameter value to.
1321 * @param length the number of characters in the parameter data.
1322 * @throws SQLException if a database access error occurs
1323 */
1324 @Override
1325 public void setClob(int i, Reader reader, long length) throws SQLException {
1326 if (reader == null || length < 0) {
1327 setNull(i, -1);
1328 return;
1329 }
1330 // simply serialise the CLOB into a variable for now... far from
1331 // efficient, but might work for a few cases...
1332 CharBuffer buf = CharBuffer.allocate((int)length); // have to down cast :(
1333 try {
1334 reader.read(buf);
1335 } catch (IOException e) {
1336 throw new SQLException("failed to read from stream: " +
1337 e.getMessage(), "M1M25");
1338 }
1339 // We have to rewind the buffer, because otherwise toString() returns "".
1340 buf.rewind();
1341 setString(i, buf.toString());
1342 }
1343
1344 /**
1345 * Sets the designated parameter to the given java.sql.Date value. The
1346 * driver converts this to an SQL DATE value when it sends it to the
1347 * database.
1348 *
1349 * @param parameterIndex the first parameter is 1, the second is 2, ...
1350 * @param x the parameter value
1351 * @throws SQLException if a database access error occurs
1352 */
1353 @Override
1354 public void setDate(int parameterIndex, java.sql.Date x)
1355 throws SQLException
1356 {
1357 setDate(parameterIndex, x, null);
1358 }
1359
1360 /**
1361 * Sets the designated parameter to the given java.sql.Date value, using
1362 * the given Calendar object. The driver uses the Calendar object to
1363 * construct an SQL DATE value, which the driver then sends to the
1364 * database. With a Calendar object, the driver can calculate the date
1365 * taking into account a custom timezone. If no Calendar object is
1366 * specified, the driver uses the default timezone, which is that of the
1367 * virtual machine running the application.
1368 *
1369 * @param parameterIndex the first parameter is 1, the second is 2, ...
1370 * @param x the parameter value
1371 * @param cal the Calendar object the driver will use to construct the date
1372 * @throws SQLException if a database access error occurs
1373 */
1374 @Override
1375 public void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
1376 throws SQLException
1377 {
1378 if (x == null) {
1379 setNull(parameterIndex, -1);
1380 return;
1381 }
1382
1383 if (cal == null) {
1384 setValue(parameterIndex, "date '" + x.toString() + "'");
1385 } else {
1386 mDate.setTimeZone(cal.getTimeZone());
1387 setValue(parameterIndex, "date '" + mDate.format(x) + "'");
1388 }
1389 }
1390
1391 /**
1392 * Sets the designated parameter to the given Java double value. The driver
1393 * converts this to an SQL DOUBLE value when it sends it to the database.
1394 *
1395 * @param parameterIndex the first parameter is 1, the second is 2, ...
1396 * @param x the parameter value
1397 * @throws SQLException if a database access error occurs
1398 */
1399 @Override
1400 public void setDouble(int parameterIndex, double x) throws SQLException {
1401 setValue(parameterIndex, "" + x);
1402 }
1403
1404 /**
1405 * Sets the designated parameter to the given Java float value. The driver
1406 * converts this to an SQL FLOAT value when it sends it to the database.
1407 *
1408 * @param parameterIndex the first parameter is 1, the second is 2, ...
1409 * @param x the parameter value
1410 * @throws SQLException if a database access error occurs
1411 */
1412 @Override
1413 public void setFloat(int parameterIndex, float x) throws SQLException {
1414 setValue(parameterIndex, "" + x);
1415 }
1416
1417 /**
1418 * Sets the designated parameter to the given Java int value. The driver
1419 * converts this to an SQL INTEGER value when it sends it to the database.
1420 *
1421 * @param parameterIndex the first parameter is 1, the second is 2, ...
1422 * @param x the parameter value
1423 * @throws SQLException if a database access error occurs
1424 */
1425 @Override
1426 public void setInt(int parameterIndex, int x) throws SQLException {
1427 setValue(parameterIndex, "" + x);
1428 }
1429
1430 /**
1431 * Sets the designated parameter to the given Java long value. The driver
1432 * converts this to an SQL BIGINT value when it sends it to the database.
1433 *
1434 * @param parameterIndex the first parameter is 1, the second is 2, ...
1435 * @param x the parameter value
1436 * @throws SQLException if a database access error occurs
1437 */
1438 @Override
1439 public void setLong(int parameterIndex, long x) throws SQLException {
1440 setValue(parameterIndex, "" + x);
1441 }
1442
1443 /**
1444 * Sets the designated parameter to a Reader object. The Reader
1445 * reads the data till end-of-file is reached. The driver does the
1446 * necessary conversion from Java character format to the national
1447 * character set in the database.
1448 *
1449 * @param i the first parameter is 1, the second is 2, ...
1450 * @param value the parameter value
1451 * @throws SQLException if a database access error occurs
1452 * @throws SQLFeatureNotSupportedException the JDBC driver does
1453 * not support this method
1454 */
1455 @Override
1456 public void setNCharacterStream(int i, Reader value) throws SQLException {
1457 throw newSQLFeatureNotSupportedException("setNCharacterStream");
1458 }
1459
1460 /**
1461 * Sets the designated parameter to a Reader object. The Reader
1462 * reads the data till end-of-file is reached. The driver does the
1463 * necessary conversion from Java character format to the national
1464 * character set in the database.
1465 *
1466 * @param i the first parameter is 1, the second is 2, ...
1467 * @param value the parameter value
1468 * @param length the number of characters in the parameter data.
1469 * @throws SQLException if a database access error occurs
1470 * @throws SQLFeatureNotSupportedException the JDBC driver does
1471 * not support this method
1472 */
1473 @Override
1474 public void setNCharacterStream(int i, Reader value, long length)
1475 throws SQLException
1476 {
1477 throw newSQLFeatureNotSupportedException("setNCharacterStream");
1478 }
1479
1480 /**
1481 * Sets the designated parameter to a java.sql.NClob object. The
1482 * driver converts this to a SQL NCLOB value when it sends it to the
1483 * database.
1484 *
1485 * @param i the first parameter is 1, the second is 2, ...
1486 * @param value the parameter value
1487 * @throws SQLException if a database access error occurs
1488 * @throws SQLFeatureNotSupportedException the JDBC driver does
1489 * not support this method
1490 */
1491 @Override
1492 public void setNClob(int i, Reader value) throws SQLException {
1493 throw newSQLFeatureNotSupportedException("setNClob");
1494 }
1495
1496 /**
1497 * Sets the designated parameter to a java.sql.NClob object. The
1498 * driver converts this to a SQL NCLOB value when it sends it to the
1499 * database.
1500 *
1501 * @param i the first parameter is 1, the second is 2, ...
1502 * @param value the parameter value
1503 * @throws SQLException if a database access error occurs
1504 * @throws SQLFeatureNotSupportedException the JDBC driver does
1505 * not support this method
1506 */
1507 @Override
1508 public void setNClob(int i, NClob value) throws SQLException {
1509 throw newSQLFeatureNotSupportedException("setNClob");
1510 }
1511
1512 /**
1513 * Sets the designated parameter to a Reader object. The reader must
1514 * contain the number of characters specified by length otherwise a
1515 * SQLException will be generated when the PreparedStatement is
1516 * executed. This method differs from the setCharacterStream (int,
1517 * Reader, int) method because it informs the driver that the
1518 * parameter value should be sent to the server as a NCLOB. When the
1519 * setCharacterStream method is used, the driver may have to do
1520 * extra work to determine whether the parameter data should be sent
1521 * to the server as a LONGNVARCHAR or a NCLOB.
1522 *
1523 * @param i the first parameter is 1, the second is 2, ...
1524 * @param r An object that contains the data to set the parameter
1525 * value to
1526 * @param length the number of characters in the parameter data
1527 * @throws SQLException if a database access error occurs
1528 * @throws SQLFeatureNotSupportedException the JDBC driver does
1529 * not support this method
1530 */
1531 @Override
1532 public void setNClob(int i, Reader r, long length) throws SQLException {
1533 throw newSQLFeatureNotSupportedException("setNClob");
1534 }
1535
1536 /**
1537 * Sets the designated paramter to the given String object. The
1538 * driver converts this to a SQL NCHAR or NVARCHAR or LONGNVARCHAR
1539 * value (depending on the argument's size relative to the driver's
1540 * limits on NVARCHAR values) when it sends it to the database.
1541 *
1542 * @param i the first parameter is 1, the second is 2, ...
1543 * @param value the parameter value
1544 * @throws SQLException if a database access error occurs
1545 * @throws SQLFeatureNotSupportedException the JDBC driver does
1546 * not support this method
1547 */
1548 @Override
1549 public void setNString(int i, String value) throws SQLException {
1550 throw newSQLFeatureNotSupportedException("setNString");
1551 }
1552
1553 /**
1554 * Sets the designated parameter to SQL NULL.
1555 *
1556 * Note: You must specify the parameter's SQL type.
1557 *
1558 * @param parameterIndex the first parameter is 1, the second is 2, ...
1559 * @param sqlType the SQL type code defined in java.sql.Types
1560 * @throws SQLException if a database access error occurs
1561 */
1562 @Override
1563 public void setNull(int parameterIndex, int sqlType) throws SQLException {
1564 // we discard the given type here, the backend converts the
1565 // value NULL to whatever it needs for the column
1566 setValue(parameterIndex, "NULL");
1567 }
1568
1569 /**
1570 * Sets the designated parameter to SQL NULL. This version of the method
1571 * setNull should be used for user-defined types and REF type parameters.
1572 * Examples of user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT,
1573 * and named array types.
1574 *
1575 * Note: To be portable, applications must give the SQL type code and the
1576 * fully-qualified SQL type name when specifying a NULL user-defined or REF
1577 * parameter. In the case of a user-defined type the name is the type name
1578 * of the parameter itself. For a REF parameter, the name is the type name
1579 * of the referenced type. If a JDBC driver does not need the type code or
1580 * type name information, it may ignore it. Although it is intended for
1581 * user-defined and Ref parameters, this method may be used to set a null
1582 * parameter of any JDBC type. If the parameter does not have a
1583 * user-defined or REF type, the given typeName is ignored.
1584 *
1585 * @param paramIndex the first parameter is 1, the second is 2, ...
1586 * @param sqlType a value from java.sql.Types
1587 * @param typeName the fully-qualified name of an SQL user-defined type;
1588 * ignored if the parameter is not a user-defined type or
1589 * REF
1590 * @throws SQLException if a database access error occurs
1591 */
1592 @Override
1593 public void setNull(int paramIndex, int sqlType, String typeName)
1594 throws SQLException
1595 {
1596 // MonetDB/SQL's NULL needs no type
1597 setNull(paramIndex, sqlType);
1598 }
1599
1600 /**
1601 * Sets the value of the designated parameter using the given
1602 * object. The second parameter must be of type Object; therefore,
1603 * the java.lang equivalent objects should be used for built-in
1604 * types.
1605 *
1606 * The JDBC specification specifies a standard mapping from Java
1607 * Object types to SQL types. The given argument will be converted
1608 * to the corresponding SQL type before being sent to the database.
1609 *
1610 * Note that this method may be used to pass datatabase-specific
1611 * abstract data types, by using a driver-specific Java type. If the
1612 * object is of a class implementing the interface SQLData, the JDBC
1613 * driver should call the method SQLData.writeSQL to write it to the
1614 * SQL data stream. If, on the other hand, the object is of a class
1615 * implementing Ref, Blob, Clob, Struct, or Array, the driver should
1616 * pass it to the database as a value of the corresponding SQL type.
1617 *
1618 * This method throws an exception if there is an ambiguity, for
1619 * example, if the object is of a class implementing more than one
1620 * of the interfaces named above.
1621 *
1622 * @param index the first parameter is 1, the second is 2, ...
1623 * @param x the object containing the input parameter value
1624 * @throws SQLException if a database access error occurs or the type of
1625 * the given object is ambiguous
1626 */
1627 @Override
1628 public void setObject(int index, Object x) throws SQLException {
1629 setObject(index, x, javaType[getParamIdx(index)]);
1630 }
1631
1632 /**
1633 * Sets the value of the designated parameter with the given object. This
1634 * method is like the method setObject below, except that it assumes a scale
1635 * of zero.
1636 *
1637 * @param parameterIndex the first parameter is 1, the second is 2, ...
1638 * @param x the object containing the input parameter value
1639 * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
1640 * sent to the database
1641 * @throws SQLException if a database access error occurs
1642 */
1643 @Override
1644 public void setObject(int parameterIndex, Object x, int targetSqlType)
1645 throws SQLException
1646 {
1647 setObject(parameterIndex, x, targetSqlType, 0);
1648 }
1649
1650 /**
1651 * Sets the value of the designated parameter with the given object. The
1652 * second argument must be an object type; for integral values, the
1653 * java.lang equivalent objects should be used.
1654 *
1655 * The given Java object will be converted to the given targetSqlType
1656 * before being sent to the database. If the object has a custom mapping
1657 * (is of a class implementing the interface SQLData), the JDBC driver
1658 * should call the method SQLData.writeSQL to write it to the SQL data
1659 * stream. If, on the other hand, the object is of a class implementing
1660 * Ref, Blob, Clob, Struct, or Array, the driver should pass it to the
1661 * database as a value of the corresponding SQL type.
1662 *
1663 * Note that this method may be used to pass database-specific abstract
1664 * data types.
1665 *
1666 * To meet the requirements of this interface, the Java object is
1667 * converted in the driver, instead of using a SQL CAST construct.
1668 *
1669 * @param parameterIndex the first parameter is 1, the second is 2, ...
1670 * @param x the object containing the input parameter value
1671 * @param targetSqlType the SQL type (as defined in java.sql.Types) to
1672 * be sent to the database. The scale argument may
1673 * further qualify this type.
1674 * @param scale for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types,
1675 * this is the number of digits after the decimal
1676 * point. For Java Object types InputStream and Reader,
1677 * this is the length of the data in the stream or
1678 * reader. For all other types, this value will be
1679 * ignored.
1680 * @throws SQLException if a database access error occurs
1681 * @see Types
1682 */
1683 @Override
1684 public void setObject(
1685 int parameterIndex,
1686 Object x,
1687 int targetSqlType,
1688 int scale)
1689 throws SQLException
1690 {
1691 // this is according to table B-5
1692 if (x instanceof String) {
1693 switch (targetSqlType) {
1694 case Types.TINYINT:
1695 case Types.SMALLINT:
1696 case Types.INTEGER:
1697 {
1698 int val;
1699 try {
1700 val = Integer.parseInt((String)x);
1701 } catch (NumberFormatException e) {
1702 val = 0;
1703 }
1704 setInt(parameterIndex, val);
1705 } break;
1706 case Types.BIGINT:
1707 {
1708 long val;
1709 try {
1710 val = Long.parseLong((String)x);
1711 } catch (NumberFormatException e) {
1712 val = 0;
1713 }
1714 setLong(parameterIndex, val);
1715 } break;
1716 case Types.REAL:
1717 {
1718 float val;
1719 try {
1720 val = Float.parseFloat((String)x);
1721 } catch (NumberFormatException e) {
1722 val = 0;
1723 }
1724 setFloat(parameterIndex, val);
1725 } break;
1726 case Types.FLOAT:
1727 case Types.DOUBLE:
1728 {
1729 double val;
1730 try {
1731 val = Double.parseDouble((String)x);
1732 } catch (NumberFormatException e) {
1733 val = 0;
1734 }
1735 setDouble(parameterIndex, val);
1736 } break;
1737 case Types.DECIMAL:
1738 case Types.NUMERIC:
1739 {
1740 BigDecimal val;
1741 try {
1742 val = new BigDecimal((String)x);
1743 } catch (NumberFormatException e) {
1744 try {
1745 val = new BigDecimal(0.0);
1746 } catch (NumberFormatException ex) {
1747 throw new SQLException("Internal error: unable to create template BigDecimal: " + ex.getMessage(), "M0M03");
1748 }
1749 }
1750 val = val.setScale(scale, BigDecimal.ROUND_HALF_UP);
1751 setBigDecimal(parameterIndex, val);
1752 } break;
1753 case Types.BIT:
1754 case Types.BOOLEAN:
1755 setBoolean(parameterIndex, (Boolean.valueOf((String)x)).booleanValue());
1756 break;
1757 case Types.CHAR:
1758 case Types.VARCHAR:
1759 case Types.LONGVARCHAR:
1760 setString(parameterIndex, (String)x);
1761 break;
1762 case Types.BINARY:
1763 case Types.VARBINARY:
1764 case Types.LONGVARBINARY:
1765 setBytes(parameterIndex, ((String)x).getBytes());
1766 break;
1767 case Types.DATE:
1768 {
1769 java.sql.Date val;
1770 try {
1771 val = java.sql.Date.valueOf((String)x);
1772 } catch (IllegalArgumentException e) {
1773 val = new java.sql.Date(0L);
1774 }
1775 setDate(parameterIndex, val);
1776 } break;
1777 case Types.TIME:
1778 {
1779 Time val;
1780 try {
1781 val = Time.valueOf((String)x);
1782 } catch (IllegalArgumentException e) {
1783 val = new Time(0L);
1784 }
1785 setTime(parameterIndex, val);
1786 } break;
1787 case Types.TIMESTAMP:
1788 {
1789 Timestamp val;
1790 try {
1791 val = Timestamp.valueOf((String)x);
1792 } catch (IllegalArgumentException e) {
1793 val = new Timestamp(0L);
1794 }
1795 setTimestamp(parameterIndex, val);
1796 } break;
1797 case Types.NCHAR:
1798 case Types.NVARCHAR:
1799 case Types.LONGNVARCHAR:
1800 throw newSQLFeatureNotSupportedException("setObject() with targetType N[VAR]CHAR");
1801 default:
1802 throw new SQLException("Conversion not allowed", "M1M05");
1803 }
1804 } else if (x instanceof BigDecimal ||
1805 x instanceof Byte ||
1806 x instanceof Short ||
1807 x instanceof Integer ||
1808 x instanceof Long ||
1809 x instanceof Float ||
1810 x instanceof Double)
1811 {
1812 Number num = (Number)x;
1813 switch (targetSqlType) {
1814 case Types.TINYINT:
1815 setByte(parameterIndex, num.byteValue());
1816 break;
1817 case Types.SMALLINT:
1818 setShort(parameterIndex, num.shortValue());
1819 break;
1820 case Types.INTEGER:
1821 setInt(parameterIndex, num.intValue());
1822 break;
1823 case Types.BIGINT:
1824 if (x instanceof BigDecimal) {
1825 BigDecimal bd = (BigDecimal)x;
1826 setLong(parameterIndex, bd.setScale(scale, BigDecimal.ROUND_HALF_UP).longValue());
1827 } else {
1828 setLong(parameterIndex, num.longValue());
1829 }
1830 break;
1831 case Types.REAL:
1832 setFloat(parameterIndex, num.floatValue());
1833 break;
1834 case Types.FLOAT:
1835 case Types.DOUBLE:
1836 setDouble(parameterIndex, num.doubleValue());
1837 break;
1838 case Types.DECIMAL:
1839 case Types.NUMERIC:
1840 if (x instanceof BigDecimal) {
1841 setBigDecimal(parameterIndex, (BigDecimal)x);
1842 } else {
1843 setBigDecimal(parameterIndex,
1844 new BigDecimal(num.doubleValue()));
1845 }
1846 break;
1847 case Types.BIT:
1848 case Types.BOOLEAN:
1849 if (num.doubleValue() != 0.0) {
1850 setBoolean(parameterIndex, true);
1851 } else {
1852 setBoolean(parameterIndex, false);
1853 }
1854 break;
1855 case Types.CHAR:
1856 case Types.VARCHAR:
1857 case Types.LONGVARCHAR:
1858 setString(parameterIndex, x.toString());
1859 break;
1860 default:
1861 throw new SQLException("Conversion not allowed", "M1M05");
1862 }
1863 } else if (x instanceof Boolean) {
1864 boolean val = ((Boolean)x).booleanValue();
1865 switch (targetSqlType) {
1866 case Types.TINYINT:
1867 setByte(parameterIndex, (byte)(val ? 1 : 0));
1868 break;
1869 case Types.SMALLINT:
1870 setShort(parameterIndex, (short)(val ? 1 : 0));
1871 break;
1872 case Types.INTEGER:
1873 setInt(parameterIndex, (val ? 1 : 0)); // do not cast to (int) as it generates a compiler warning
1874 break;
1875 case Types.BIGINT:
1876 setLong(parameterIndex, (long)(val ? 1 : 0));
1877 break;
1878 case Types.REAL:
1879 setFloat(parameterIndex, (float)(val ? 1.0 : 0.0));
1880 break;
1881 case Types.FLOAT:
1882 case Types.DOUBLE:
1883 setDouble(parameterIndex, (val ? 1.0 : 0.0)); // do no cast to (double) as it generates a compiler warning
1884 break;
1885 case Types.DECIMAL:
1886 case Types.NUMERIC:
1887 {
1888 BigDecimal dec;
1889 try {
1890 dec = new BigDecimal(val ? 1.0 : 0.0);
1891 } catch (NumberFormatException e) {
1892 throw new SQLException("Internal error: unable to create template BigDecimal: " + e.getMessage(), "M0M03");
1893 }
1894 setBigDecimal(parameterIndex, dec);
1895 } break;
1896 case Types.BIT:
1897 case Types.BOOLEAN:
1898 setBoolean(parameterIndex, val);
1899 break;
1900 case Types.CHAR:
1901 case Types.VARCHAR:
1902 case Types.LONGVARCHAR:
1903 setString(parameterIndex, "" + val);
1904 break;
1905 default:
1906 throw new SQLException("Conversion not allowed", "M1M05");
1907 }
1908 } else if (x instanceof BigInteger) {
1909 BigInteger num = (BigInteger)x;
1910 switch (targetSqlType) {
1911 case Types.BIGINT:
1912 setLong(parameterIndex, num.longValue());
1913 break;
1914 case Types.CHAR:
1915 case Types.VARCHAR:
1916 case Types.LONGVARCHAR:
1917 setString(parameterIndex, x.toString());
1918 break;
1919 default:
1920 throw new SQLException("Conversion not allowed", "M1M05");
1921 }
1922 } else if (x instanceof byte[]) {
1923 switch (targetSqlType) {
1924 case Types.BINARY:
1925 case Types.VARBINARY:
1926 case Types.LONGVARBINARY:
1927 setBytes(parameterIndex, (byte[])x);
1928 break;
1929 default:
1930 throw new SQLException("Conversion not allowed", "M1M05");
1931 }
1932 } else if (x instanceof java.sql.Date ||
1933 x instanceof Timestamp ||
1934 x instanceof Time ||
1935 x instanceof Calendar ||
1936 x instanceof java.util.Date)
1937 {
1938 switch (targetSqlType) {
1939 case Types.CHAR:
1940 case Types.VARCHAR:
1941 case Types.LONGVARCHAR:
1942 setString(parameterIndex, x.toString());
1943 break;
1944 case Types.DATE:
1945 if (x instanceof Time) {
1946 throw new SQLException("Conversion not allowed", "M1M05");
1947 } else if (x instanceof java.sql.Date) {
1948 setDate(parameterIndex, (java.sql.Date)x);
1949 } else if (x instanceof Timestamp) {
1950 setDate(parameterIndex, new java.sql.Date(((Timestamp)x).getTime()));
1951 } else if (x instanceof java.util.Date) {
1952 setDate(parameterIndex, new java.sql.Date(
1953 ((java.util.Date)x).getTime()));
1954 } else if (x instanceof Calendar) {
1955 setDate(parameterIndex, new java.sql.Date(
1956 ((Calendar)x).getTimeInMillis()));
1957 }
1958 break;
1959 case Types.TIME:
1960 if (x instanceof Time) {
1961 setTime(parameterIndex, (Time)x);
1962 } else if (x instanceof java.sql.Date) {
1963 throw new SQLException("Conversion not allowed", "M1M05");
1964 } else if (x instanceof Timestamp) {
1965 setTime(parameterIndex, new Time(((Timestamp)x).getTime()));
1966 } else if (x instanceof java.util.Date) {
1967 setTime(parameterIndex, new java.sql.Time(
1968 ((java.util.Date)x).getTime()));
1969 } else if (x instanceof Calendar) {
1970 setTime(parameterIndex, new java.sql.Time(
1971 ((Calendar)x).getTimeInMillis()));
1972 }
1973 break;
1974 case Types.TIMESTAMP:
1975 if (x instanceof Time) {
1976 throw new SQLException("Conversion not allowed", "M1M05");
1977 } else if (x instanceof java.sql.Date) {
1978 setTimestamp(parameterIndex, new Timestamp(((java.sql.Date)x).getTime()));
1979 } else if (x instanceof Timestamp) {
1980 setTimestamp(parameterIndex, (Timestamp)x);
1981 } else if (x instanceof java.util.Date) {
1982 setTimestamp(parameterIndex, new java.sql.Timestamp(
1983 ((java.util.Date)x).getTime()));
1984 } else if (x instanceof Calendar) {
1985 setTimestamp(parameterIndex, new java.sql.Timestamp(
1986 ((Calendar)x).getTimeInMillis()));
1987 }
1988 break;
1989 default:
1990 throw new SQLException("Conversion not allowed", "M1M05");
1991 }
1992 } else if (x instanceof Array) {
1993 setArray(parameterIndex, (Array)x);
1994 } else if (x instanceof Blob) {
1995 setBlob(parameterIndex, (Blob)x);
1996 } else if (x instanceof Clob) {
1997 setClob(parameterIndex, (Clob)x);
1998 } else if (x instanceof Struct) {
1999 // I have no idea how to do this...
2000 throw newSQLFeatureNotSupportedException("setObject() with object of type Struct");
2001 } else if (x instanceof Ref) {
2002 setRef(parameterIndex, (Ref)x);
2003 } else if (x instanceof java.net.URL) {
2004 setURL(parameterIndex, (java.net.URL)x);
2005 } else if (x instanceof RowId) {
2006 setRowId(parameterIndex, (RowId)x);
2007 } else if (x instanceof NClob) {
2008 throw newSQLFeatureNotSupportedException("setObject() with object of type NClob");
2009 } else if (x instanceof SQLXML) {
2010 throw newSQLFeatureNotSupportedException("setObject() with object of type SQLXML");
2011 } else if (x instanceof SQLData) { // not in JDBC4.1???
2012 SQLData sx = (SQLData)x;
2013 final int paramnr = parameterIndex;
2014 final String sqltype = sx.getSQLTypeName();
2015 SQLOutput out = new SQLOutput() {
2016 @Override
2017 public void writeString(String x) throws SQLException {
2018 // special situation, this is when a string
2019 // representation is given, but we need to prefix it
2020 // with the actual sqltype the server expects, or we
2021 // will get an error back
2022 setValue(
2023 paramnr,
2024 sqltype + " '" + x.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "'"
2025 );
2026 }
2027
2028 @Override
2029 public void writeBoolean(boolean x) throws SQLException {
2030 setBoolean(paramnr, x);
2031 }
2032
2033 @Override
2034 public void writeByte(byte x) throws SQLException {
2035 setByte(paramnr, x);
2036 }
2037
2038 @Override
2039 public void writeShort(short x) throws SQLException {
2040 setShort(paramnr, x);
2041 }
2042
2043 @Override
2044 public void writeInt(int x) throws SQLException {
2045 setInt(paramnr, x);
2046 }
2047
2048 @Override
2049 public void writeLong(long x) throws SQLException {
2050 setLong(paramnr, x);
2051 }
2052
2053 @Override
2054 public void writeFloat(float x) throws SQLException {
2055 setFloat(paramnr, x);
2056 }
2057
2058 @Override
2059 public void writeDouble(double x) throws SQLException {
2060 setDouble(paramnr, x);
2061 }
2062
2063 @Override
2064 public void writeBigDecimal(BigDecimal x) throws SQLException {
2065 setBigDecimal(paramnr, x);
2066 }
2067
2068 @Override
2069 public void writeBytes(byte[] x) throws SQLException {
2070 setBytes(paramnr, x);
2071 }
2072
2073 @Override
2074 public void writeDate(java.sql.Date x) throws SQLException {
2075 setDate(paramnr, x);
2076 }
2077
2078 @Override
2079 public void writeTime(java.sql.Time x) throws SQLException {
2080 setTime(paramnr, x);
2081 }
2082
2083 @Override
2084 public void writeTimestamp(Timestamp x) throws SQLException {
2085 setTimestamp(paramnr, x);
2086 }
2087
2088 @Override
2089 public void writeCharacterStream(Reader x) throws SQLException {
2090 setCharacterStream(paramnr, x);
2091 }
2092
2093 @Override
2094 public void writeAsciiStream(InputStream x) throws SQLException {
2095 setAsciiStream(paramnr, x);
2096 }
2097
2098 @Override
2099 public void writeBinaryStream(InputStream x) throws SQLException {
2100 setBinaryStream(paramnr, x);
2101 }
2102
2103 @Override
2104 public void writeObject(SQLData x) throws SQLException {
2105 setObject(paramnr, x);
2106 }
2107
2108 @Override
2109 public void writeRef(Ref x) throws SQLException {
2110 setRef(paramnr, x);
2111 }
2112
2113 @Override
2114 public void writeBlob(Blob x) throws SQLException {
2115 setBlob(paramnr, x);
2116 }
2117
2118 @Override
2119 public void writeClob(Clob x) throws SQLException {
2120 setClob(paramnr, x);
2121 }
2122
2123 @Override
2124 public void writeStruct(Struct x) throws SQLException {
2125 setObject(paramnr, x);
2126 }
2127
2128 @Override
2129 public void writeArray(Array x) throws SQLException {
2130 setArray(paramnr, x);
2131 }
2132
2133 @Override
2134 public void writeURL(URL x) throws SQLException {
2135 setURL(paramnr, x);
2136 }
2137
2138 @Override
2139 public void writeNString(String x) throws SQLException {
2140 setNString(paramnr, x);
2141 }
2142
2143 @Override
2144 public void writeNClob(NClob x) throws SQLException {
2145 setNClob(paramnr, x);
2146 }
2147
2148 @Override
2149 public void writeRowId(RowId x) throws SQLException {
2150 setRowId(paramnr, x);
2151 }
2152
2153 @Override
2154 public void writeSQLXML(SQLXML x) throws SQLException {
2155 setSQLXML(paramnr, x);
2156 }
2157 };
2158 sx.writeSQL(out);
2159 } else { // java Class
2160 throw newSQLFeatureNotSupportedException("setObject() with object of type Class");
2161 }
2162 }
2163
2164 /**
2165 * Sets the designated parameter to the given REF(<structured-type>) value.
2166 * The driver converts this to an SQL REF value when it sends it to the
2167 * database.
2168 *
2169 * @param i the first parameter is 1, the second is 2, ...
2170 * @param x an SQL REF value
2171 * @throws SQLException if a database access error occurs
2172 * @throws SQLFeatureNotSupportedException the JDBC driver does
2173 * not support this method
2174 */
2175 @Override
2176 public void setRef(int i, Ref x) throws SQLException {
2177 throw newSQLFeatureNotSupportedException("setRef");
2178 }
2179
2180 /**
2181 * Sets the designated parameter to the given java.sql.RowId object.
2182 * The driver converts this to a SQL ROWID value when it sends it to
2183 * the database.
2184 *
2185 * @param i the first parameter is 1, the second is 2, ...
2186 * @param x the parameter value
2187 * @throws SQLException if a database access error occurs
2188 * @throws SQLFeatureNotSupportedException the JDBC driver does
2189 * not support this method
2190 */
2191 @Override
2192 public void setRowId(int i, RowId x) throws SQLException {
2193 throw newSQLFeatureNotSupportedException("setRowId");
2194 }
2195
2196 /**
2197 * Sets the designated parameter to the given Java short value. The driver
2198 * converts this to an SQL SMALLINT value when it sends it to the database.
2199 *
2200 * @param parameterIndex the first parameter is 1, the second is 2, ...
2201 * @param x the parameter value
2202 * @throws SQLException if a database access error occurs
2203 */
2204 @Override
2205 public void setShort(int parameterIndex, short x) throws SQLException {
2206 setValue(parameterIndex, "" + x);
2207 }
2208
2209 /**
2210 * Sets the designated parameter to the given Java String value. The driver
2211 * converts this to an SQL VARCHAR or LONGVARCHAR value (depending on the
2212 * argument's size relative to the driver's limits on VARCHAR values) when
2213 * it sends it to the database.
2214 *
2215 * @param parameterIndex the first parameter is 1, the second is 2, ...
2216 * @param x the parameter value
2217 * @throws SQLException if a database access error occurs
2218 */
2219 @Override
2220 public void setString(int parameterIndex, String x) throws SQLException {
2221 if (x == null) {
2222 setNull(parameterIndex, -1);
2223 return;
2224 }
2225
2226 setValue(
2227 parameterIndex,
2228 "'" + x.replaceAll("\\\\", "\\\\\\\\").replaceAll("'", "\\\\'") + "'"
2229 );
2230 }
2231
2232 /**
2233 * Sets the designated parameter to the given java.sql.SQLXML
2234 * object. The driver converts this to an SQL XML value when it
2235 * sends it to the database.
2236 *
2237 * @param parameterIndex the first parameter is 1, the second is 2, ...
2238 * @param x a SQLXML object that maps an SQL XML value
2239 * @throws SQLException if a database access error occurs
2240 * @throws SQLFeatureNotSupportedException the JDBC driver does
2241 * not support this method
2242 */
2243 @Override
2244 public void setSQLXML(int parameterIndex, SQLXML x) throws SQLException {
2245 throw newSQLFeatureNotSupportedException("setSQLXML");
2246 }
2247
2248 /**
2249 * Sets the designated parameter to the given java.sql.Time value.
2250 * The driver converts this to an SQL TIME value when it sends it to
2251 * the database.
2252 *
2253 * @param index the first parameter is 1, the second is 2, ...
2254 * @param x the parameter value
2255 * @throws SQLException if a database access error occurs
2256 */
2257 @Override
2258 public void setTime(int index, Time x) throws SQLException {
2259 setTime(index, x, null);
2260 }
2261
2262 /**
2263 * Sets the designated parameter to the given java.sql.Time value,
2264 * using the given Calendar object. The driver uses the Calendar
2265 * object to construct an SQL TIME value, which the driver then
2266 * sends to the database. With a Calendar object, the driver can
2267 * calculate the time taking into account a custom timezone. If no
2268 * Calendar object is specified, the driver uses the default
2269 * timezone, which is that of the virtual machine running the
2270 * application.
2271 *
2272 * @param index the first parameter is 1, the second is 2, ...
2273 * @param x the parameter value
2274 * @param cal the Calendar object the driver will use to construct the time
2275 * @throws SQLException if a database access error occurs
2276 */
2277 @Override
2278 public void setTime(int index, Time x, Calendar cal)
2279 throws SQLException
2280 {
2281 if (x == null) {
2282 setNull(index, -1);
2283 return;
2284 }
2285
2286 boolean hasTimeZone = monetdbType[getParamIdx(index)].endsWith("tz");
2287 if (hasTimeZone) {
2288 // timezone shouldn't matter, since the server is timezone
2289 // aware in this case
2290 String RFC822 = mTimeZ.format(x);
2291 setValue(index, "timetz '" +
2292 RFC822.substring(0, 15) + ":" + RFC822.substring(15) + "'");
2293 } else {
2294 // server is not timezone aware for this field, and no
2295 // calendar given, since we told the server our timezone at
2296 // connection creation, we can just write a plain timestamp
2297 // here
2298 if (cal == null) {
2299 setValue(index, "time '" + x.toString() + "'");
2300 } else {
2301 mTime.setTimeZone(cal.getTimeZone());
2302 setValue(index, "time '" + mTime.format(x) + "'");
2303 }
2304 }
2305 }
2306
2307 /**
2308 * Sets the designated parameter to the given java.sql.Timestamp
2309 * value. The driver converts this to an SQL TIMESTAMP value when
2310 * it sends it to the database.
2311 *
2312 * @param index the first parameter is 1, the second is 2, ...
2313 * @param x the parameter value
2314 * @throws SQLException if a database access error occurs
2315 */
2316 @Override
2317 public void setTimestamp(int index, Timestamp x)
2318 throws SQLException
2319 {
2320 setTimestamp(index, x, null);
2321 }
2322
2323 /**
2324 * Sets the designated parameter to the given java.sql.Timestamp
2325 * value, using the given Calendar object. The driver uses the
2326 * Calendar object to construct an SQL TIMESTAMP value, which the
2327 * driver then sends to the database. With a Calendar object, the
2328 * driver can calculate the timestamp taking into account a custom
2329 * timezone. If no Calendar object is specified, the driver uses the
2330 * default timezone, which is that of the virtual machine running
2331 * the application.
2332 *
2333 * @param index the first parameter is 1, the second is 2, ...
2334 * @param x the parameter value
2335 * @param cal the Calendar object the driver will use to construct the
2336 * timestamp
2337 * @throws SQLException if a database access error occurs
2338 */
2339 @Override
2340 public void setTimestamp(int index, Timestamp x, Calendar cal)
2341 throws SQLException
2342 {
2343 if (x == null) {
2344 setNull(index, -1);
2345 return;
2346 }
2347
2348 boolean hasTimeZone = monetdbType[getParamIdx(index)].endsWith("tz");
2349 if (hasTimeZone) {
2350 // timezone shouldn't matter, since the server is timezone
2351 // aware in this case
2352 String RFC822 = mTimestampZ.format(x);
2353 setValue(index, "timestamptz '" +
2354 RFC822.substring(0, 26) + ":" + RFC822.substring(26) + "'");
2355 } else {
2356 // server is not timezone aware for this field, and no
2357 // calendar given, since we told the server our timezone at
2358 // connection creation, we can just write a plain timestamp
2359 // here
2360 if (cal == null) {
2361 setValue(index, "timestamp '" + x.toString() + "'");
2362 } else {
2363 mTimestamp.setTimeZone(cal.getTimeZone());
2364 setValue(index, "timestamp '" + mTimestamp.format(x) + "'");
2365 }
2366 }
2367 }
2368
2369 /**
2370 * Sets the designated parameter to the given input stream, which will have
2371 * the specified number of bytes. A Unicode character has two bytes, with
2372 * the first byte being the high byte, and the second being the low byte.
2373 * When a very large Unicode value is input to a LONGVARCHAR parameter, it
2374 * may be more practical to send it via a java.io.InputStream object. The
2375 * data will be read from the stream as needed until end-of-file is
2376 * reached. The JDBC driver will do any necessary conversion from Unicode
2377 * to the database char format.
2378 *
2379 * Note: This stream object can either be a standard Java stream object or
2380 * your own subclass that implements the standard interface.
2381 *
2382 * @deprecated
2383 * @param parameterIndex the first parameter is 1, the second is 2, ...
2384 * @param x a java.io.InputStream object that contains the Unicode
2385 * parameter value as two-byte Unicode characters
2386 * @param length the number of bytes in the stream
2387 * @throws SQLException if a database access error occurs
2388 */
2389 @Override
2390 @Deprecated
2391 public void setUnicodeStream(int parameterIndex, InputStream x, int length)
2392 throws SQLException
2393 {
2394 throw newSQLFeatureNotSupportedException("setUnicodeStream");
2395 }
2396
2397 /**
2398 * Sets the designated parameter to the given java.net.URL value. The
2399 * driver converts this to an SQL DATALINK value when it sends it to the
2400 * database.
2401 *
2402 * @param parameterIndex the first parameter is 1, the second is 2, ...
2403 * @param x the java.net.URL object to be set
2404 * @throws SQLException if a database access error occurs
2405 */
2406 @Override
2407 public void setURL(int parameterIndex, URL x) throws SQLException {
2408 throw newSQLFeatureNotSupportedException("setURL");
2409 }
2410
2411 /**
2412 * Releases this PreparedStatement object's database and JDBC
2413 * resources immediately instead of waiting for this to happen when
2414 * it is automatically closed. It is generally good practice to
2415 * release resources as soon as you are finished with them to avoid
2416 * tying up database resources.
2417 *
2418 * Calling the method close on a PreparedStatement object that is
2419 * already closed has no effect.
2420 *
2421 * <b>Note:</b> A PreparedStatement object is automatically closed
2422 * when it is garbage collected. When a Statement object is closed,
2423 * its current ResultSet object, if one exists, is also closed.
2424 */
2425 @Override
2426 public void close() {
2427 try {
2428 if (!closed && id != -1)
2429 connection.sendControlCommand("release " + id);
2430 } catch (SQLException e) {
2431 // probably server closed connection
2432 }
2433 super.close();
2434 }
2435
2436 /**
2437 * Call close to release the server-sided handle for this
2438 * PreparedStatement.
2439 */
2440 @Override
2441 protected void finalize() {
2442 close();
2443 }
2444
2445 //== end methods interface PreparedStatement
2446
2447 /**
2448 * Sets the given index with the supplied value. If the given index is
2449 * out of bounds, and SQLException is thrown. The given value should
2450 * never be null.
2451 *
2452 * @param index the parameter index
2453 * @param val the exact String representation to set
2454 * @throws SQLException if the given index is out of bounds
2455 */
2456 void setValue(int index, String val) throws SQLException {
2457 values[getParamIdx(index)] = val;
2458 }
2459
2460 /**
2461 * Transforms the prepare query into a simple SQL query by replacing
2462 * the ?'s with the given column contents.
2463 * Mind that the JDBC specs allow `reuse' of a value for a column over
2464 * multiple executes.
2465 *
2466 * @return the simple SQL string for the prepare query
2467 * @throws SQLException if not all columns are set
2468 */
2469 private String transform() throws SQLException {
2470 StringBuilder buf = new StringBuilder(8 + 12 * size);
2471 buf.append("exec ");
2472 buf.append(id);
2473 buf.append('(');
2474 // check if all columns are set and do a replace
2475 int col = 0;
2476 for (int i = 0; i < size; i++) {
2477 if (column[i] != null)
2478 continue;
2479 col++;
2480 if (col > 1)
2481 buf.append(',');
2482 if (values[i] == null) throw
2483 new SQLException("Cannot execute, parameter " + col + " is missing.", "M1M05");
2484
2485 buf.append(values[i]);
2486 }
2487 buf.append(')');
2488
2489 return buf.toString();
2490 }
2491
2492 /**
2493 * Small helper method that formats the "Method ... not implemented" message
2494 * and creates a new SQLFeatureNotSupportedException object
2495 * whose SQLState is set to "0A000".
2496 *
2497 * @param name the method name
2498 * @return a new created SQLFeatureNotSupportedException object with SQLState 0A000
2499 */
2500 private final static SQLFeatureNotSupportedException newSQLFeatureNotSupportedException(String name) {
2501 return new SQLFeatureNotSupportedException("Method " + name + " not implemented", "0A000");
2502 }
2503 }