001: /*
002: Copyright (C) 2002-2007 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022: */
023: package com.mysql.jdbc;
024:
025: import java.sql.SQLException;
026: import java.sql.Types;
027:
028: import com.mysql.jdbc.exceptions.NotYetImplementedException;
029:
030: /**
031: * A ResultSetMetaData object can be used to find out about the types and
032: * properties of the columns in a ResultSet
033: *
034: * @author Mark Matthews
035: * @version $Id: ResultSetMetaData.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
036: * Exp $
037: *
038: * @see java.sql.ResultSetMetaData
039: */
040: public class ResultSetMetaData implements java.sql.ResultSetMetaData {
041: private static int clampedGetLength(Field f) {
042: long fieldLength = f.getLength();
043:
044: if (fieldLength > Integer.MAX_VALUE) {
045: fieldLength = Integer.MAX_VALUE;
046: }
047:
048: return (int) fieldLength;
049: }
050:
051: /**
052: * Checks if the SQL Type is a Decimal/Number Type
053: *
054: * @param type
055: * SQL Type
056: *
057: * @return ...
058: */
059: private static final boolean isDecimalType(int type) {
060: switch (type) {
061: case Types.BIT:
062: case Types.TINYINT:
063: case Types.SMALLINT:
064: case Types.INTEGER:
065: case Types.BIGINT:
066: case Types.FLOAT:
067: case Types.REAL:
068: case Types.DOUBLE:
069: case Types.NUMERIC:
070: case Types.DECIMAL:
071: return true;
072: }
073:
074: return false;
075: }
076:
077: Field[] fields;
078: boolean useOldAliasBehavior = false;
079:
080: /**
081: * Initialise for a result with a tuple set and a field descriptor set
082: *
083: * @param fields
084: * the array of field descriptors
085: */
086: public ResultSetMetaData(Field[] fields, boolean useOldAliasBehavior) {
087: this .fields = fields;
088: this .useOldAliasBehavior = useOldAliasBehavior;
089: }
090:
091: /**
092: * What's a column's table's catalog name?
093: *
094: * @param column
095: * the first column is 1, the second is 2...
096: *
097: * @return catalog name, or "" if not applicable
098: *
099: * @throws SQLException
100: * if a database access error occurs
101: */
102: public String getCatalogName(int column) throws SQLException {
103: Field f = getField(column);
104:
105: String database = f.getDatabaseName();
106:
107: return (database == null) ? "" : database; //$NON-NLS-1$
108: }
109:
110: /**
111: * What's the Java character encoding name for the given column?
112: *
113: * @param column
114: * the first column is 1, the second is 2, etc.
115: *
116: * @return the Java character encoding name for the given column, or null if
117: * no Java character encoding maps to the MySQL character set for
118: * the given column.
119: *
120: * @throws SQLException
121: * if an invalid column index is given.
122: */
123: public String getColumnCharacterEncoding(int column)
124: throws SQLException {
125: String mysqlName = getColumnCharacterSet(column);
126:
127: String javaName = null;
128:
129: if (mysqlName != null) {
130: javaName = CharsetMapping.getJavaEncodingForMysqlEncoding(
131: mysqlName, null);
132: }
133:
134: return javaName;
135: }
136:
137: /**
138: * What's the MySQL character set name for the given column?
139: *
140: * @param column
141: * the first column is 1, the second is 2, etc.
142: *
143: * @return the MySQL character set name for the given column
144: *
145: * @throws SQLException
146: * if an invalid column index is given.
147: */
148: public String getColumnCharacterSet(int column) throws SQLException {
149: return getField(column).getCharacterSet();
150: }
151:
152: // --------------------------JDBC 2.0-----------------------------------
153:
154: /**
155: * JDBC 2.0
156: *
157: * <p>
158: * Return the fully qualified name of the Java class whose instances are
159: * manufactured if ResultSet.getObject() is called to retrieve a value from
160: * the column. ResultSet.getObject() may return a subClass of the class
161: * returned by this method.
162: * </p>
163: *
164: * @param column
165: * the column number to retrieve information for
166: *
167: * @return the fully qualified name of the Java class whose instances are
168: * manufactured if ResultSet.getObject() is called to retrieve a
169: * value from the column.
170: *
171: * @throws SQLException
172: * if an error occurs
173: */
174: public String getColumnClassName(int column) throws SQLException {
175: Field f = getField(column);
176:
177: return getClassNameForJavaType(f.getSQLType(), f.isUnsigned(),
178: f.getMysqlType(), f.isBinary() || f.isBlob(), f
179: .isOpaqueBinary());
180: }
181:
182: /**
183: * Whats the number of columns in the ResultSet?
184: *
185: * @return the number
186: *
187: * @throws SQLException
188: * if a database access error occurs
189: */
190: public int getColumnCount() throws SQLException {
191: return this .fields.length;
192: }
193:
194: /**
195: * What is the column's normal maximum width in characters?
196: *
197: * @param column
198: * the first column is 1, the second is 2, etc.
199: *
200: * @return the maximum width
201: *
202: * @throws SQLException
203: * if a database access error occurs
204: */
205: public int getColumnDisplaySize(int column) throws SQLException {
206: Field f = getField(column);
207:
208: int lengthInBytes = clampedGetLength(f);
209:
210: return lengthInBytes / f.getMaxBytesPerCharacter();
211: }
212:
213: /**
214: * What is the suggested column title for use in printouts and displays?
215: *
216: * @param column
217: * the first column is 1, the second is 2, etc.
218: *
219: * @return the column label
220: *
221: * @throws SQLException
222: * if a database access error occurs
223: */
224: public String getColumnLabel(int column) throws SQLException {
225: if (this .useOldAliasBehavior) {
226: return getColumnName(column);
227: }
228:
229: return getField(column).getColumnLabel();
230: }
231:
232: /**
233: * What's a column's name?
234: *
235: * @param column
236: * the first column is 1, the second is 2, etc.
237: *
238: * @return the column name
239: *
240: * @throws SQLException
241: * if a databvase access error occurs
242: */
243: public String getColumnName(int column) throws SQLException {
244: if (this .useOldAliasBehavior) {
245: return getField(column).getName();
246: }
247:
248: String name = getField(column).getNameNoAliases();
249:
250: if (name != null && name.length() == 0) {
251: return getField(column).getName();
252: }
253:
254: return name;
255: }
256:
257: /**
258: * What is a column's SQL Type? (java.sql.Type int)
259: *
260: * @param column
261: * the first column is 1, the second is 2, etc.
262: *
263: * @return the java.sql.Type value
264: *
265: * @throws SQLException
266: * if a database access error occurs
267: *
268: * @see java.sql.Types
269: */
270: public int getColumnType(int column) throws SQLException {
271: return getField(column).getSQLType();
272: }
273:
274: /**
275: * Whats is the column's data source specific type name?
276: *
277: * @param column
278: * the first column is 1, the second is 2, etc.
279: *
280: * @return the type name
281: *
282: * @throws SQLException
283: * if a database access error occurs
284: */
285: public String getColumnTypeName(int column)
286: throws java.sql.SQLException {
287: Field field = getField(column);
288:
289: int mysqlType = field.getMysqlType();
290: int jdbcType = field.getSQLType();
291:
292: switch (mysqlType) {
293: case MysqlDefs.FIELD_TYPE_BIT:
294: return "BIT";
295: case MysqlDefs.FIELD_TYPE_DECIMAL:
296: case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
297: return field.isUnsigned() ? "DECIMAL UNSIGNED" : "DECIMAL";
298:
299: case MysqlDefs.FIELD_TYPE_TINY:
300: return field.isUnsigned() ? "TINYINT UNSIGNED" : "TINYINT";
301:
302: case MysqlDefs.FIELD_TYPE_SHORT:
303: return field.isUnsigned() ? "SMALLINT UNSIGNED"
304: : "SMALLINT";
305:
306: case MysqlDefs.FIELD_TYPE_LONG:
307: return field.isUnsigned() ? "INTEGER UNSIGNED" : "INTEGER";
308:
309: case MysqlDefs.FIELD_TYPE_FLOAT:
310: return field.isUnsigned() ? "FLOAT UNSIGNED" : "FLOAT";
311:
312: case MysqlDefs.FIELD_TYPE_DOUBLE:
313: return field.isUnsigned() ? "DOUBLE UNSIGNED" : "DOUBLE";
314:
315: case MysqlDefs.FIELD_TYPE_NULL:
316: return "NULL"; //$NON-NLS-1$
317:
318: case MysqlDefs.FIELD_TYPE_TIMESTAMP:
319: return "TIMESTAMP"; //$NON-NLS-1$
320:
321: case MysqlDefs.FIELD_TYPE_LONGLONG:
322: return field.isUnsigned() ? "BIGINT UNSIGNED" : "BIGINT";
323:
324: case MysqlDefs.FIELD_TYPE_INT24:
325: return field.isUnsigned() ? "MEDIUMINT UNSIGNED"
326: : "MEDIUMINT";
327:
328: case MysqlDefs.FIELD_TYPE_DATE:
329: return "DATE"; //$NON-NLS-1$
330:
331: case MysqlDefs.FIELD_TYPE_TIME:
332: return "TIME"; //$NON-NLS-1$
333:
334: case MysqlDefs.FIELD_TYPE_DATETIME:
335: return "DATETIME"; //$NON-NLS-1$
336:
337: case MysqlDefs.FIELD_TYPE_TINY_BLOB:
338: return "TINYBLOB"; //$NON-NLS-1$
339:
340: case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
341: return "MEDIUMBLOB"; //$NON-NLS-1$
342:
343: case MysqlDefs.FIELD_TYPE_LONG_BLOB:
344: return "LONGBLOB"; //$NON-NLS-1$
345:
346: case MysqlDefs.FIELD_TYPE_BLOB:
347: if (getField(column).isBinary()) {
348: return "BLOB";//$NON-NLS-1$
349: }
350:
351: return "TEXT";//$NON-NLS-1$
352:
353: case MysqlDefs.FIELD_TYPE_VARCHAR:
354: return "VARCHAR"; //$NON-NLS-1$
355:
356: case MysqlDefs.FIELD_TYPE_VAR_STRING:
357: if (jdbcType == Types.VARBINARY) {
358: return "VARBINARY";
359: }
360:
361: return "VARCHAR"; //$NON-NLS-1$
362:
363: case MysqlDefs.FIELD_TYPE_STRING:
364: if (jdbcType == Types.BINARY) {
365: return "BINARY";
366: }
367:
368: return "CHAR"; //$NON-NLS-1$
369:
370: case MysqlDefs.FIELD_TYPE_ENUM:
371: return "ENUM"; //$NON-NLS-1$
372:
373: case MysqlDefs.FIELD_TYPE_YEAR:
374: return "YEAR"; // $NON_NLS-1$
375:
376: case MysqlDefs.FIELD_TYPE_SET:
377: return "SET"; //$NON-NLS-1$
378:
379: default:
380: return "UNKNOWN"; //$NON-NLS-1$
381: }
382: }
383:
384: /**
385: * Returns the field instance for the given column index
386: *
387: * @param columnIndex
388: * the column number to retrieve a field instance for
389: *
390: * @return the field instance for the given column index
391: *
392: * @throws SQLException
393: * if an error occurs
394: */
395: protected Field getField(int columnIndex) throws SQLException {
396: if ((columnIndex < 1) || (columnIndex > this .fields.length)) {
397: throw SQLError.createSQLException(Messages
398: .getString("ResultSetMetaData.46"), //$NON-NLS-1$
399: SQLError.SQL_STATE_INVALID_COLUMN_NUMBER);
400: }
401:
402: return this .fields[columnIndex - 1];
403: }
404:
405: /**
406: * What is a column's number of decimal digits.
407: *
408: * @param column
409: * the first column is 1, the second is 2...
410: *
411: * @return the precision
412: *
413: * @throws SQLException
414: * if a database access error occurs
415: */
416: public int getPrecision(int column) throws SQLException {
417: Field f = getField(column);
418:
419: // if (f.getMysqlType() == MysqlDefs.FIELD_TYPE_NEW_DECIMAL) {
420: // return f.getLength();
421: // }
422:
423: if (isDecimalType(f.getSQLType())) {
424: if (f.getDecimals() > 0) {
425: return clampedGetLength(f) - 1
426: + f.getPrecisionAdjustFactor();
427: }
428:
429: return clampedGetLength(f) + f.getPrecisionAdjustFactor();
430: }
431:
432: switch (f.getMysqlType()) {
433: case MysqlDefs.FIELD_TYPE_TINY_BLOB:
434: case MysqlDefs.FIELD_TYPE_BLOB:
435: case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
436: case MysqlDefs.FIELD_TYPE_LONG_BLOB:
437: return clampedGetLength(f); // this may change in the future
438: // for now, the server only
439: // returns FIELD_TYPE_BLOB for _all_
440: // BLOB types, but varying lengths
441: // indicating the _maximum_ size
442: // for each BLOB type.
443: default:
444: return clampedGetLength(f) / f.getMaxBytesPerCharacter();
445:
446: }
447: }
448:
449: /**
450: * What is a column's number of digits to the right of the decimal point?
451: *
452: * @param column
453: * the first column is 1, the second is 2...
454: *
455: * @return the scale
456: *
457: * @throws SQLException
458: * if a database access error occurs
459: */
460: public int getScale(int column) throws SQLException {
461: Field f = getField(column);
462:
463: if (isDecimalType(f.getSQLType())) {
464: return f.getDecimals();
465: }
466:
467: return 0;
468: }
469:
470: /**
471: * What is a column's table's schema? This relies on us knowing the table
472: * name. The JDBC specification allows us to return "" if this is not
473: * applicable.
474: *
475: * @param column
476: * the first column is 1, the second is 2...
477: *
478: * @return the Schema
479: *
480: * @throws SQLException
481: * if a database access error occurs
482: */
483: public String getSchemaName(int column) throws SQLException {
484: return ""; //$NON-NLS-1$
485: }
486:
487: /**
488: * Whats a column's table's name?
489: *
490: * @param column
491: * the first column is 1, the second is 2...
492: *
493: * @return column name, or "" if not applicable
494: *
495: * @throws SQLException
496: * if a database access error occurs
497: */
498: public String getTableName(int column) throws SQLException {
499: if (this .useOldAliasBehavior) {
500: return getField(column).getTableName();
501: }
502:
503: return getField(column).getTableNameNoAliases();
504: }
505:
506: /**
507: * Is the column automatically numbered (and thus read-only)
508: *
509: * @param column
510: * the first column is 1, the second is 2...
511: *
512: * @return true if so
513: *
514: * @throws SQLException
515: * if a database access error occurs
516: */
517: public boolean isAutoIncrement(int column) throws SQLException {
518: Field f = getField(column);
519:
520: return f.isAutoIncrement();
521: }
522:
523: /**
524: * Does a column's case matter?
525: *
526: * @param column
527: * the first column is 1, the second is 2...
528: *
529: * @return true if so
530: *
531: * @throws java.sql.SQLException
532: * if a database access error occurs
533: */
534: public boolean isCaseSensitive(int column)
535: throws java.sql.SQLException {
536: Field field = getField(column);
537:
538: int sqlType = field.getSQLType();
539:
540: switch (sqlType) {
541: case Types.BIT:
542: case Types.TINYINT:
543: case Types.SMALLINT:
544: case Types.INTEGER:
545: case Types.BIGINT:
546: case Types.FLOAT:
547: case Types.REAL:
548: case Types.DOUBLE:
549: case Types.DATE:
550: case Types.TIME:
551: case Types.TIMESTAMP:
552: return false;
553:
554: case Types.CHAR:
555: case Types.VARCHAR:
556: case Types.LONGVARCHAR:
557:
558: if (field.isBinary()) {
559: return true;
560: }
561:
562: String collationName = field.getCollation();
563:
564: return ((collationName != null) && !collationName
565: .endsWith("_ci"));
566:
567: default:
568: return true;
569: }
570: }
571:
572: /**
573: * Is the column a cash value?
574: *
575: * @param column
576: * the first column is 1, the second is 2...
577: *
578: * @return true if its a cash column
579: *
580: * @throws SQLException
581: * if a database access error occurs
582: */
583: public boolean isCurrency(int column) throws SQLException {
584: return false;
585: }
586:
587: /**
588: * Will a write on this column definately succeed?
589: *
590: * @param column
591: * the first column is 1, the second is 2, etc..
592: *
593: * @return true if so
594: *
595: * @throws SQLException
596: * if a database access error occurs
597: */
598: public boolean isDefinitelyWritable(int column) throws SQLException {
599: return isWritable(column);
600: }
601:
602: /**
603: * Can you put a NULL in this column?
604: *
605: * @param column
606: * the first column is 1, the second is 2...
607: *
608: * @return one of the columnNullable values
609: *
610: * @throws SQLException
611: * if a database access error occurs
612: */
613: public int isNullable(int column) throws SQLException {
614: if (!getField(column).isNotNull()) {
615: return java.sql.ResultSetMetaData.columnNullable;
616: }
617:
618: return java.sql.ResultSetMetaData.columnNoNulls;
619: }
620:
621: /**
622: * Is the column definitely not writable?
623: *
624: * @param column
625: * the first column is 1, the second is 2, etc.
626: *
627: * @return true if so
628: *
629: * @throws SQLException
630: * if a database access error occurs
631: */
632: public boolean isReadOnly(int column) throws SQLException {
633: return getField(column).isReadOnly();
634: }
635:
636: /**
637: * Can the column be used in a WHERE clause? Basically for this, I split the
638: * functions into two types: recognised types (which are always useable),
639: * and OTHER types (which may or may not be useable). The OTHER types, for
640: * now, I will assume they are useable. We should really query the catalog
641: * to see if they are useable.
642: *
643: * @param column
644: * the first column is 1, the second is 2...
645: *
646: * @return true if they can be used in a WHERE clause
647: *
648: * @throws SQLException
649: * if a database access error occurs
650: */
651: public boolean isSearchable(int column) throws SQLException {
652: return true;
653: }
654:
655: /**
656: * Is the column a signed number?
657: *
658: * @param column
659: * the first column is 1, the second is 2...
660: *
661: * @return true if so
662: *
663: * @throws SQLException
664: * if a database access error occurs
665: */
666: public boolean isSigned(int column) throws SQLException {
667: Field f = getField(column);
668: int sqlType = f.getSQLType();
669:
670: switch (sqlType) {
671: case Types.TINYINT:
672: case Types.SMALLINT:
673: case Types.INTEGER:
674: case Types.BIGINT:
675: case Types.FLOAT:
676: case Types.REAL:
677: case Types.DOUBLE:
678: case Types.NUMERIC:
679: case Types.DECIMAL:
680: return !f.isUnsigned();
681:
682: case Types.DATE:
683: case Types.TIME:
684: case Types.TIMESTAMP:
685: return false;
686:
687: default:
688: return false;
689: }
690: }
691:
692: /**
693: * Is it possible for a write on the column to succeed?
694: *
695: * @param column
696: * the first column is 1, the second is 2, etc.
697: *
698: * @return true if so
699: *
700: * @throws SQLException
701: * if a database access error occurs
702: */
703: public boolean isWritable(int column) throws SQLException {
704: return !isReadOnly(column);
705: }
706:
707: /**
708: * Returns a string representation of this object
709: *
710: * @return ...
711: */
712: public String toString() {
713: StringBuffer toStringBuf = new StringBuffer();
714: toStringBuf.append(super .toString());
715: toStringBuf.append(" - Field level information: "); //$NON-NLS-1$
716:
717: for (int i = 0; i < this .fields.length; i++) {
718: toStringBuf.append("\n\t"); //$NON-NLS-1$
719: toStringBuf.append(this .fields[i].toString());
720: }
721:
722: return toStringBuf.toString();
723: }
724:
725: static String getClassNameForJavaType(int javaType,
726: boolean isUnsigned, int mysqlTypeIfKnown,
727: boolean isBinaryOrBlob, boolean isOpaqueBinary) {
728: switch (javaType) {
729: case Types.BIT:
730: case Types.BOOLEAN:
731: return "java.lang.Boolean"; //$NON-NLS-1$
732:
733: case Types.TINYINT:
734:
735: if (isUnsigned) {
736: return "java.lang.Integer"; //$NON-NLS-1$
737: }
738:
739: return "java.lang.Integer"; //$NON-NLS-1$
740:
741: case Types.SMALLINT:
742:
743: if (isUnsigned) {
744: return "java.lang.Integer"; //$NON-NLS-1$
745: }
746:
747: return "java.lang.Integer"; //$NON-NLS-1$
748:
749: case Types.INTEGER:
750:
751: if (!isUnsigned
752: || mysqlTypeIfKnown == MysqlDefs.FIELD_TYPE_INT24) {
753: return "java.lang.Integer"; //$NON-NLS-1$
754: }
755:
756: return "java.lang.Long"; //$NON-NLS-1$
757:
758: case Types.BIGINT:
759:
760: if (!isUnsigned) {
761: return "java.lang.Long"; //$NON-NLS-1$
762: }
763:
764: return "java.math.BigInteger"; //$NON-NLS-1$
765:
766: case Types.DECIMAL:
767: case Types.NUMERIC:
768: return "java.math.BigDecimal"; //$NON-NLS-1$
769:
770: case Types.REAL:
771: return "java.lang.Float"; //$NON-NLS-1$
772:
773: case Types.FLOAT:
774: case Types.DOUBLE:
775: return "java.lang.Double"; //$NON-NLS-1$
776:
777: case Types.CHAR:
778: case Types.VARCHAR:
779: case Types.LONGVARCHAR:
780: if (!isOpaqueBinary) {
781: return "java.lang.String"; //$NON-NLS-1$
782: }
783:
784: return "[B";
785:
786: case Types.BINARY:
787: case Types.VARBINARY:
788: case Types.LONGVARBINARY:
789:
790: if (mysqlTypeIfKnown == MysqlDefs.FIELD_TYPE_GEOMETRY) {
791: return "[B";
792: } else if (isBinaryOrBlob) {
793: return "[B";
794: } else {
795: return "java.lang.String";
796: }
797:
798: case Types.DATE:
799: return "java.sql.Date"; //$NON-NLS-1$
800:
801: case Types.TIME:
802: return "java.sql.Time"; //$NON-NLS-1$
803:
804: case Types.TIMESTAMP:
805: return "java.sql.Timestamp"; //$NON-NLS-1$
806:
807: default:
808: return "java.lang.Object"; //$NON-NLS-1$
809: }
810: }
811:
812: /**
813: * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
814: * for an object that does. Returns false otherwise. If this implements the interface then return true,
815: * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
816: * object. If this does not implement the interface and is not a wrapper, return false.
817: * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
818: * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
819: * returns true then calling <code>unwrap</code> with the same argument should succeed.
820: *
821: * @param interfaces a Class defining an interface.
822: * @return true if this implements the interface or directly or indirectly wraps an object that does.
823: * @throws java.sql.SQLException if an error occurs while determining whether this is a wrapper
824: * for an object with the given interface.
825: * @since 1.6
826: */
827: public boolean isWrapperFor(Class iface) throws SQLException {
828: // This works for classes that aren't actually wrapping
829: // anything
830: return iface.isInstance(this );
831: }
832:
833: /**
834: * Returns an object that implements the given interface to allow access to non-standard methods,
835: * or standard methods not exposed by the proxy.
836: * The result may be either the object found to implement the interface or a proxy for that object.
837: * If the receiver implements the interface then that is the object. If the receiver is a wrapper
838: * and the wrapped object implements the interface then that is the object. Otherwise the object is
839: * the result of calling <code>unwrap</code> recursively on the wrapped object. If the receiver is not a
840: * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
841: *
842: * @param iface A Class defining an interface that the result must implement.
843: * @return an object that implements the interface. May be a proxy for the actual implementing object.
844: * @throws java.sql.SQLException If no object found that implements the interface
845: * @since 1.6
846: */
847: public Object unwrap(Class iface) throws java.sql.SQLException {
848: try {
849: // This works for classes that aren't actually wrapping
850: // anything
851: return Util.cast(iface, this );
852: } catch (ClassCastException cce) {
853: throw SQLError.createSQLException("Unable to unwrap to "
854: + iface.toString(),
855: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
856: }
857: }
858: }
|