0001: /**
0002: * Derby - org.apache.derbyTesting.functionTests.tests.jdbc4.UnsupportedVetter
0003: *
0004: Licensed to the Apache Software Foundation (ASF) under one or more
0005: contributor license agreements. See the NOTICE file distributed with
0006: this work for additional information regarding copyright ownership.
0007: The ASF licenses this file to You under the Apache License, Version 2.0
0008: (the "License"); you may not use this file except in compliance with
0009: the License. You may obtain a copy of the License at
0010:
0011: http://www.apache.org/licenses/LICENSE-2.0
0012:
0013: Unless required by applicable law or agreed to in writing, software
0014: distributed under the License is distributed on an "AS IS" BASIS,
0015: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016: See the License for the specific language governing permissions and
0017: limitations under the License.
0018: *
0019: */package org.apache.derbyTesting.functionTests.tests.jdbc4;
0020:
0021: import java.io.*;
0022: import java.sql.*;
0023: import javax.sql.*;
0024:
0025: import java.lang.reflect.*;
0026: import java.util.*;
0027: import junit.framework.*;
0028:
0029: import java.net.URL;
0030:
0031: import org.apache.derbyTesting.functionTests.util.TestUtil;
0032: import org.apache.derbyTesting.functionTests.util.TestDataSourceFactory;
0033: import org.apache.derbyTesting.junit.BaseJDBCTestCase;
0034:
0035: /**
0036: * JUnit test which checks that only expected methods throw
0037: * SQLFeatureNotSupporteException. As currently compiled, this class
0038: * does not object to a handful of mandatory LOB-supporting methods which Derby
0039: * does not implement. You can expose these methods by setting
0040: * the STRICT_ENFORCEMENT constant to true.
0041: *
0042: */
0043: public class UnsupportedVetter extends BaseJDBCTestCase {
0044: /////////////////////////////////////////////////////////////
0045: //
0046: // CONSTANTS
0047: //
0048: /////////////////////////////////////////////////////////////
0049:
0050: public static final String SQL_PACKAGE_NAME = "java.sql";
0051:
0052: private static final boolean STRICT_ENFORCEMENT = false;
0053:
0054: /////////////////////////////////////////////////////////////
0055: //
0056: // STATE
0057: //
0058: /////////////////////////////////////////////////////////////
0059:
0060: //
0061: // Table of methods which are allowed to raise
0062: // SQLFeatureNotSupportedException. Derived from the 1.6 Javadoc.
0063: //
0064: private static Exclusions[] rawExcludables = new Exclusions[] {
0065: new Exclusions(java.sql.Connection.class, new MD[] {
0066: new MD("createArrayOf", new Class[] { String.class,
0067: Object[].class }),
0068: new MD("createNClob", new Class[] {}),
0069: new MD("createSQLXML", new Class[] {}),
0070: new MD("createStruct", new Class[] { String.class,
0071: Object[].class }),
0072: new MD("getTypeMap", new Class[] {}),
0073: new MD("prepareStatement", new Class[] {
0074: String.class, int[].class }),
0075: new MD("prepareStatement", new Class[] {
0076: String.class, String[].class }),
0077: new MD("setTypeMap", new Class[] { Map.class }), }),
0078: new Exclusions(java.sql.Statement.class, new MD[] {
0079: new MD("cancel", new Class[] {}),
0080: new MD("execute", new Class[] { String.class,
0081: int[].class }),
0082: new MD("execute", new Class[] { String.class,
0083: String[].class }),
0084: new MD("executeUpdate", new Class[] { String.class,
0085: int[].class }),
0086: new MD("executeUpdate", new Class[] { String.class,
0087: String[].class }) }),
0088:
0089: new Exclusions(
0090: java.sql.PreparedStatement.class,
0091: new MD[] {
0092: new MD("setArray", new Class[] { int.class,
0093: java.sql.Array.class }),
0094: new MD("setNCharacterStream", new Class[] {
0095: int.class, java.io.Reader.class }),
0096: new MD("setNCharacterStream", new Class[] {
0097: int.class, java.io.Reader.class,
0098: long.class }),
0099: new MD("setNClob", new Class[] { int.class,
0100: NClob.class }),
0101: new MD("setNClob", new Class[] { int.class,
0102: java.io.Reader.class }),
0103: new MD("setNClob", new Class[] { int.class,
0104: java.io.Reader.class, long.class }),
0105: new MD("setNString", new Class[] {
0106: int.class, String.class }),
0107: new MD("setRef", new Class[] { int.class,
0108: Ref.class }),
0109: new MD("setRowId", new Class[] { int.class,
0110: RowId.class }),
0111: new MD("setSQLXML", new Class[] {
0112: int.class, SQLXML.class }),
0113: new MD("setURL", new Class[] { int.class,
0114: URL.class }),
0115: new MD("setNull", new Class[] { int.class,
0116: int.class, String.class }),
0117: new MD("setUnicodeStream", new Class[] {
0118: int.class, InputStream.class,
0119: int.class }), }),
0120: new Exclusions(
0121: java.sql.CallableStatement.class,
0122: new MD[] {
0123: //
0124: // THE FOLLOWING METHODS ARE MANDATORY ACCORDING TO THE
0125: // JDBC SPEC. HOWEVER, DERBY DOES NOT IMPLEMENT THEM IN ONE
0126: // OR THE OTHER OF OUR CLIENTS.
0127: //
0128: new FD("getBlob", new Class[] { int.class }),
0129: new FD("getClob", new Class[] { int.class }),
0130:
0131: //
0132: // According to the JDBC4 spec and javadoc, the following
0133: // methods are optional and do not have to be implemented.
0134: //
0135:
0136: new MD("getArray",
0137: new Class[] { int.class }),
0138: new MD("getArray",
0139: new Class[] { String.class }),
0140: new MD("getBigDecimal",
0141: new Class[] { String.class }),
0142: new MD("getBoolean",
0143: new Class[] { String.class }),
0144: new MD("getBlob",
0145: new Class[] { String.class }),
0146: new MD("getBoolean",
0147: new Class[] { String.class }),
0148: new MD("getByte",
0149: new Class[] { String.class }),
0150: new MD("getBytes",
0151: new Class[] { String.class }),
0152: new MD("getCharacterStream",
0153: new Class[] { String.class }),
0154: new MD("getClob",
0155: new Class[] { String.class }),
0156: new MD("getDate",
0157: new Class[] { String.class }),
0158: new MD("getDate", new Class[] {
0159: String.class, Calendar.class }),
0160: new MD("getDouble",
0161: new Class[] { String.class }),
0162: new MD("getFloat",
0163: new Class[] { String.class }),
0164: new MD("getInt",
0165: new Class[] { String.class }),
0166: new MD("getLong",
0167: new Class[] { String.class }),
0168: new MD("getNCharacterStream",
0169: new Class[] { int.class }),
0170: new MD("getNCharacterStream",
0171: new Class[] { String.class }),
0172: new MD("getNClob",
0173: new Class[] { int.class }),
0174: new MD("getNClob",
0175: new Class[] { String.class }),
0176: new MD("getNString",
0177: new Class[] { int.class }),
0178: new MD("getNString",
0179: new Class[] { String.class }),
0180: new MD("getObject",
0181: new Class[] { String.class }),
0182: new MD("getRef", new Class[] { int.class }),
0183: new MD("getRef",
0184: new Class[] { String.class }),
0185: new MD("getRowId",
0186: new Class[] { int.class }),
0187: new MD("getRowId",
0188: new Class[] { String.class }),
0189: new MD("getShort",
0190: new Class[] { String.class }),
0191: new MD("getSQLXML",
0192: new Class[] { int.class }),
0193: new MD("getSQLXML",
0194: new Class[] { String.class }),
0195: new MD("getString",
0196: new Class[] { String.class }),
0197: new MD("getTime",
0198: new Class[] { String.class }),
0199: new MD("getTime", new Class[] {
0200: String.class,
0201: java.util.Calendar.class }),
0202: new MD("getTimestamp",
0203: new Class[] { String.class }),
0204: new MD("getTimestamp", new Class[] {
0205: String.class,
0206: java.util.Calendar.class }),
0207: new MD("getURL", new Class[] { int.class }),
0208: new MD("getURL",
0209: new Class[] { String.class }),
0210: new MD("registerOutParameter", new Class[] {
0211: String.class, int.class }),
0212: new MD("registerOutParameter",
0213: new Class[] { String.class,
0214: int.class, int.class }),
0215: new MD("registerOutParameter", new Class[] {
0216: String.class, int.class,
0217: String.class }),
0218: new MD("registerOutParameter",
0219: new Class[] { int.class, int.class,
0220: String.class }),
0221: new MD("setArray", new Class[] { int.class,
0222: java.sql.Array.class }),
0223: new MD("setAsciiStream", new Class[] {
0224: String.class,
0225: java.io.InputStream.class }),
0226: new MD("setAsciiStream", new Class[] {
0227: String.class,
0228: java.io.InputStream.class,
0229: int.class }),
0230: new MD("setAsciiStream", new Class[] {
0231: String.class,
0232: java.io.InputStream.class,
0233: long.class }),
0234: new MD("setBigDecimal", new Class[] {
0235: String.class,
0236: java.math.BigDecimal.class }),
0237: new MD("setBinaryStream", new Class[] {
0238: String.class,
0239: java.io.InputStream.class }),
0240: new MD("setBinaryStream", new Class[] {
0241: String.class,
0242: java.io.InputStream.class,
0243: int.class }),
0244: new MD("setBinaryStream", new Class[] {
0245: String.class,
0246: java.io.InputStream.class,
0247: long.class }),
0248: new MD("setBlob", new Class[] {
0249: String.class,
0250: java.io.InputStream.class }),
0251: new MD("setBlob", new Class[] {
0252: String.class,
0253: java.io.InputStream.class,
0254: long.class }),
0255: new MD("setBlob", new Class[] {
0256: String.class, Blob.class }),
0257: new MD("setBoolean", new Class[] {
0258: String.class, boolean.class }),
0259: new MD("setByte", new Class[] {
0260: String.class, byte.class }),
0261: new MD("setBytes", new Class[] {
0262: String.class, byte[].class }),
0263: new MD("setCharacterStream",
0264: new Class[] { String.class,
0265: java.io.Reader.class }),
0266: new MD("setCharacterStream", new Class[] {
0267: String.class, java.io.Reader.class,
0268: int.class }),
0269: new MD("setCharacterStream", new Class[] {
0270: String.class, java.io.Reader.class,
0271: long.class }),
0272: new MD("setClob",
0273: new Class[] { String.class,
0274: java.io.Reader.class }),
0275: new MD("setClob", new Class[] {
0276: String.class, java.io.Reader.class,
0277: long.class }),
0278: new MD("setClob", new Class[] {
0279: String.class, Clob.class }),
0280: new MD("setDate", new Class[] {
0281: String.class, java.sql.Date.class }),
0282: new MD("setDate", new Class[] {
0283: String.class, java.sql.Date.class,
0284: Calendar.class }),
0285: new MD("setDouble", new Class[] {
0286: String.class, double.class }),
0287: new MD("setFloat", new Class[] {
0288: String.class, float.class }),
0289: new MD("setInt", new Class[] {
0290: String.class, int.class }),
0291: new MD("setLong", new Class[] {
0292: String.class, long.class }),
0293: new MD("setNCharacterStream", new Class[] {
0294: int.class, java.io.Reader.class,
0295: long.class }),
0296: new MD("setNCharacterStream",
0297: new Class[] { String.class,
0298: java.io.Reader.class }),
0299: new MD("setNCharacterStream", new Class[] {
0300: String.class, java.io.Reader.class,
0301: long.class }),
0302: new MD("setNClob", new Class[] { int.class,
0303: java.io.Reader.class, long.class }),
0304: new MD("setNClob", new Class[] { int.class,
0305: NClob.class }),
0306: new MD("setNClob",
0307: new Class[] { String.class,
0308: java.io.Reader.class }),
0309: new MD("setNClob", new Class[] {
0310: String.class, java.io.Reader.class,
0311: long.class }),
0312: new MD("setNClob", new Class[] {
0313: String.class, NClob.class }),
0314: new MD("setNString", new Class[] {
0315: int.class, String.class }),
0316: new MD("setNString", new Class[] {
0317: String.class, String.class }),
0318: new MD("setNull", new Class[] {
0319: String.class, int.class }),
0320: new MD("setNull", new Class[] {
0321: String.class, int.class,
0322: String.class }),
0323: new MD("setObject", new Class[] {
0324: String.class, Object.class }),
0325: new MD("setObject", new Class[] {
0326: String.class, Object.class,
0327: int.class }),
0328: new MD("setObject", new Class[] {
0329: String.class, Object.class,
0330: int.class, int.class }),
0331: new MD("setRef", new Class[] { int.class,
0332: Ref.class }),
0333: new MD("setRowId", new Class[] { int.class,
0334: RowId.class }),
0335: new MD("setRowId", new Class[] {
0336: String.class, RowId.class }),
0337: new MD("setSQLXML", new Class[] {
0338: int.class, SQLXML.class }),
0339: new MD("setSQLXML", new Class[] {
0340: String.class, SQLXML.class }),
0341: new MD("setShort", new Class[] {
0342: String.class, short.class }),
0343: new MD("setString", new Class[] {
0344: String.class, String.class }),
0345: new MD("setTime", new Class[] {
0346: String.class, Time.class }),
0347: new MD("setTime", new Class[] {
0348: String.class, Time.class,
0349: Calendar.class }),
0350: new MD("setTimestamp", new Class[] {
0351: String.class, Timestamp.class }),
0352: new MD("setTimestamp", new Class[] {
0353: String.class, Timestamp.class,
0354: Calendar.class }),
0355: new MD("setURL", new Class[] { int.class,
0356: URL.class }),
0357: new MD("setURL", new Class[] {
0358: String.class, URL.class }) }),
0359: new Exclusions(
0360: java.sql.ResultSet.class,
0361: new MD[] {
0362: //
0363: // THE FOLLOWING METHODS ARE MANDATORY ACCORDING TO THE
0364: // JDBC SPEC. HOWEVER, DERBY DOES NOT IMPLEMENT THEM IN ONE
0365: // OR THE OTHER OF OUR CLIENTS.
0366: //
0367: new FD("updateBlob", new Class[] {
0368: int.class, Blob.class }),
0369: new FD("updateBlob", new Class[] {
0370: String.class, Blob.class }),
0371: new FD("updateBlob", new Class[] {
0372: int.class, InputStream.class,
0373: long.class }),
0374: new FD("updateBlob", new Class[] {
0375: String.class, InputStream.class,
0376: long.class }),
0377: new FD("updateClob", new Class[] {
0378: int.class, Clob.class }),
0379: new FD("updateClob", new Class[] {
0380: String.class, Clob.class }),
0381: new FD("updateClob",
0382: new Class[] { int.class,
0383: Reader.class, long.class }),
0384: new FD("updateClob", new Class[] {
0385: String.class, Reader.class,
0386: long.class }),
0387: new FD("updateNClob",
0388: new Class[] { int.class,
0389: Reader.class, long.class }),
0390: new FD("updateNClob", new Class[] {
0391: String.class, Reader.class,
0392: long.class }),
0393:
0394: //
0395: // According to the JDBC4 spec and javadoc, the following
0396: // methods are optional and do not have to be implemented.
0397: //
0398:
0399: new MD("getNCharacterStream",
0400: new Class[] { int.class }),
0401: new MD("getNCharacterStream",
0402: new Class[] { String.class }),
0403: new MD("getNString",
0404: new Class[] { int.class }),
0405: new MD("getNString",
0406: new Class[] { String.class }),
0407: new MD("getURL", new Class[] { int.class }),
0408: new MD("getURL",
0409: new Class[] { String.class }),
0410: new MD("getArray",
0411: new Class[] { int.class }),
0412: new MD("getArray",
0413: new Class[] { String.class }),
0414: new MD("getNClob",
0415: new Class[] { int.class }),
0416: new MD("getNClob",
0417: new Class[] { String.class }),
0418: new MD("getRef", new Class[] { int.class }),
0419: new MD("getRef",
0420: new Class[] { String.class }),
0421: new MD("getRowId",
0422: new Class[] { int.class }),
0423: new MD("getRowId",
0424: new Class[] { String.class }),
0425: new MD("getSQLXML",
0426: new Class[] { int.class }),
0427: new MD("getSQLXML",
0428: new Class[] { String.class }),
0429: new MD("getUnicodeStream",
0430: new Class[] { int.class }),
0431: new MD("getUnicodeStream",
0432: new Class[] { String.class }),
0433: new MD("refreshRow", new Class[] {}),
0434: new MD("updateArray", new Class[] {
0435: int.class, java.sql.Array.class }),
0436: new MD("updateArray",
0437: new Class[] { String.class,
0438: java.sql.Array.class }),
0439: new MD("updateNCharacterStream",
0440: new Class[] { int.class,
0441: java.io.Reader.class }),
0442: new MD("updateNCharacterStream",
0443: new Class[] { int.class,
0444: java.io.Reader.class,
0445: long.class }),
0446: new MD("updateNCharacterStream",
0447: new Class[] { String.class,
0448: java.io.Reader.class }),
0449: new MD("updateNCharacterStream",
0450: new Class[] { String.class,
0451: java.io.Reader.class,
0452: long.class }),
0453: new MD("updateNClob", new Class[] {
0454: int.class, NClob.class }),
0455: new MD("updateNClob", new Class[] {
0456: int.class, Reader.class }),
0457: new MD("updateNClob", new Class[] {
0458: String.class, NClob.class }),
0459: new MD("updateNClob", new Class[] {
0460: String.class, Reader.class }),
0461: new MD("updateNString", new Class[] {
0462: int.class, String.class }),
0463: new MD("updateNString", new Class[] {
0464: String.class, String.class }),
0465: new MD("updateRef", new Class[] {
0466: int.class, Ref.class }),
0467: new MD("updateRef", new Class[] {
0468: String.class, Ref.class }),
0469: new MD("updateRowId", new Class[] {
0470: int.class, RowId.class }),
0471: new MD("updateRowId", new Class[] {
0472: String.class, RowId.class }),
0473: new MD("updateSQLXML", new Class[] {
0474: int.class, SQLXML.class }),
0475: new MD("updateSQLXML", new Class[] {
0476: String.class, SQLXML.class }) }),
0477: //
0478: // Lance Andersen, spec lead for JDBC4, says:
0479: // If you support a datatype, then you have to implement
0480: // all of its methods.
0481: //
0482:
0483: new Exclusions(
0484: //
0485: // THE FOLLOWING METHODS ARE MANDATORY ACCORDING TO THE
0486: // JDBC SPEC. HOWEVER, DERBY DOES NOT IMPLEMENT THEM IN ONE
0487: // OR THE OTHER OF OUR CLIENTS.
0488: //
0489: java.sql.Blob.class, new MD[] {
0490: new FD("getBinaryStream", new Class[] {
0491: long.class, long.class }),
0492: new FD("setBinaryStream",
0493: new Class[] { long.class }),
0494: new FD("setBytes", new Class[] {
0495: long.class, byte[].class }),
0496: new FD("setBytes", new Class[] {
0497: long.class, byte[].class,
0498: int.class, int.class }),
0499: new FD("truncate",
0500: new Class[] { long.class }) }),
0501: new Exclusions(
0502: //
0503: // THE FOLLOWING METHODS ARE MANDATORY ACCORDING TO THE
0504: // JDBC SPEC. HOWEVER, DERBY DOES NOT IMPLEMENT THEM IN ONE
0505: // OR THE OTHER OF OUR CLIENTS.
0506: //
0507: java.sql.Clob.class, new MD[] {
0508: new FD("getCharacterStream", new Class[] {
0509: long.class, long.class }),
0510: new FD("setAsciiStream",
0511: new Class[] { long.class }),
0512: new FD("setCharacterStream",
0513: new Class[] { long.class }),
0514: new FD("setString", new Class[] {
0515: long.class, String.class }),
0516: new FD("setString", new Class[] {
0517: long.class, String.class,
0518: int.class, int.class }),
0519: new FD("truncate",
0520: new Class[] { long.class }) }) };
0521:
0522: //
0523: // This is the Hashtable where we keep the exclusions.
0524: //
0525: private static Hashtable<Class, HashSet<Method>> excludableMap;
0526:
0527: /////////////////////////////////////////////////////////////
0528: //
0529: // CONSTRUCTOR
0530: //
0531: /////////////////////////////////////////////////////////////
0532:
0533: /**
0534: * Creates a new instance.
0535: */
0536: public UnsupportedVetter() {
0537: super ("UnsupportedVetter");
0538: }
0539:
0540: /////////////////////////////////////////////////////////////
0541: //
0542: // ENTRY POINTS
0543: //
0544: /////////////////////////////////////////////////////////////
0545:
0546: /**
0547: * <p>
0548: * Find all methods in this framework which raise SQLFeatureNotSupportedException.
0549: * </p>
0550: */
0551: public void testSupportedMethods() throws Exception {
0552: getTestConfiguration().setVerbosity(true);
0553:
0554: HashSet<String> vanishedMethodList = new HashSet<String>();
0555: HashSet<String> unsupportedList = new HashSet<String>();
0556: HashSet<String> notUnderstoodList = new HashSet<String>();
0557:
0558: // Build map of interfaces to their methods which may raise SQLFeatureNotSupportedException.
0559: initializeExcludableMap(vanishedMethodList);
0560:
0561: vetDataSource(unsupportedList, notUnderstoodList);
0562: vetConnectionPooledDataSource(unsupportedList,
0563: notUnderstoodList);
0564: vetXADataSource(unsupportedList, notUnderstoodList);
0565:
0566: //
0567: // Print methods which behave unexpectedly.
0568: //
0569: printVanishedMethodList(vanishedMethodList);
0570: printUnsupportedList(unsupportedList);
0571: printNotUnderstoodList(notUnderstoodList);
0572:
0573: int actualErrorCount = vanishedMethodList.size()
0574: + unsupportedList.size() + notUnderstoodList.size();
0575:
0576: assertEquals("Unexpected discrepancies.", 0, actualErrorCount);
0577: }
0578:
0579: //
0580: // Find all the objects inside the DataSource and vet them.
0581: //
0582: private void vetDataSource(HashSet<String> unsupportedList,
0583: HashSet<String> notUnderstoodList) throws Exception {
0584: DataSource ds = TestDataSourceFactory.getDataSource();
0585: Connection conn = ds.getConnection();
0586:
0587: vetObject(ds, unsupportedList, notUnderstoodList);
0588:
0589: connectionWorkhorse(conn, unsupportedList, notUnderstoodList);
0590: }
0591:
0592: //
0593: // Find all the objects inside the ConnectionPooledDataSource and vet them.
0594: //
0595: private void vetConnectionPooledDataSource(
0596: HashSet<String> unsupportedList,
0597: HashSet<String> notUnderstoodList) throws Exception {
0598: ConnectionPoolDataSource ds = TestDataSourceFactory
0599: .getConnectionPoolDataSource();
0600: PooledConnection pc = ds.getPooledConnection(
0601: getTestConfiguration().getUserName(),
0602: getTestConfiguration().getUserPassword());
0603: Connection conn = pc.getConnection();
0604:
0605: vetObject(ds, unsupportedList, notUnderstoodList);
0606: vetObject(pc, unsupportedList, notUnderstoodList);
0607:
0608: connectionWorkhorse(conn, unsupportedList, notUnderstoodList);
0609: }
0610:
0611: //
0612: // Find all the objects inside the XADataSource and vet them.
0613: //
0614: private void vetXADataSource(HashSet<String> unsupportedList,
0615: HashSet<String> notUnderstoodList) throws Exception {
0616: XADataSource ds = TestDataSourceFactory.getXADataSource();
0617: XAConnection xaconn = ds.getXAConnection(getTestConfiguration()
0618: .getUserName(), getTestConfiguration()
0619: .getUserPassword());
0620: Connection conn = xaconn.getConnection();
0621:
0622: vetObject(ds, unsupportedList, notUnderstoodList);
0623: vetObject(xaconn, unsupportedList, notUnderstoodList);
0624:
0625: connectionWorkhorse(conn, unsupportedList, notUnderstoodList);
0626: }
0627:
0628: //
0629: // Find all the methods for java.sql objects in the Connection which raise
0630: // SQLFeatureNotSupportedException.
0631: //
0632: private void connectionWorkhorse(Connection conn,
0633: HashSet<String> unsupportedList,
0634: HashSet<String> notUnderstoodList) throws Exception {
0635: vetSavepoint(conn, unsupportedList, notUnderstoodList);
0636: vetLargeObjects(conn, unsupportedList, notUnderstoodList);
0637:
0638: DatabaseMetaData dbmd = conn.getMetaData();
0639: PreparedStatement ps = conn
0640: .prepareStatement("select * from sys.systables where tablename = ?");
0641:
0642: ps.setString(1, "foo");
0643:
0644: ParameterMetaData parameterMetaData = ps.getParameterMetaData();
0645: ResultSet rs = ps.executeQuery();
0646: ResultSetMetaData rsmd = rs.getMetaData();
0647: Statement stmt = conn.createStatement();
0648:
0649: CallableStatement cs = conn
0650: .prepareCall("CALL SYSCS_UTIL.SYSCS_SET_RUNTIMESTATISTICS(0)");
0651: ParameterMetaData csmd = cs.getParameterMetaData();
0652:
0653: //
0654: // The vetObject() method calls all of the methods in these objects
0655: // in a deterministic order, calling the close() method last.
0656: // Inspect these objects in an order which respects the fact that
0657: // the objects are closed as a result of calling vetObject().
0658: //
0659: vetObject(dbmd, unsupportedList, notUnderstoodList);
0660: vetObject(stmt, unsupportedList, notUnderstoodList);
0661: vetObject(csmd, unsupportedList, notUnderstoodList);
0662: vetObject(cs, unsupportedList, notUnderstoodList);
0663: vetObject(rsmd, unsupportedList, notUnderstoodList);
0664: vetObject(rs, unsupportedList, notUnderstoodList);
0665: vetObject(parameterMetaData, unsupportedList, notUnderstoodList);
0666: vetObject(ps, unsupportedList, notUnderstoodList);
0667: vetObject(conn, unsupportedList, notUnderstoodList);
0668:
0669: // No need to close the objects. They were closed by vetObject().
0670: }
0671:
0672: //
0673: // Examine Savepoints.
0674: //
0675: private void vetSavepoint(Connection conn,
0676: HashSet<String> unsupportedList,
0677: HashSet<String> notUnderstoodList) throws Exception {
0678: conn.setAutoCommit(false);
0679:
0680: Savepoint sp = conn.setSavepoint();
0681:
0682: vetObject(sp, unsupportedList, notUnderstoodList);
0683:
0684: conn.releaseSavepoint(sp);
0685: }
0686:
0687: //
0688: // Examine BLOBs and CLOBs.
0689: //
0690: private void vetLargeObjects(Connection conn,
0691: HashSet<String> unsupportedList,
0692: HashSet<String> notUnderstoodList) throws Exception {
0693: Statement stmt = conn.createStatement();
0694:
0695: stmt.execute("CREATE TABLE t (id INT PRIMARY KEY, "
0696: + "b BLOB(10), c CLOB(10))");
0697: stmt.execute("INSERT INTO t (id, b, c) VALUES (1, " + "CAST ("
0698: + TestUtil.stringToHexLiteral("101010001101")
0699: + "AS BLOB(10)), CAST ('hello' AS CLOB(10)))");
0700:
0701: ResultSet rs = stmt.executeQuery("SELECT id, b, c FROM t");
0702:
0703: rs.next();
0704:
0705: Blob blob = rs.getBlob(2);
0706: Clob clob = rs.getClob(3);
0707:
0708: vetObject(blob, unsupportedList, notUnderstoodList);
0709: vetObject(clob, unsupportedList, notUnderstoodList);
0710:
0711: stmt.close();
0712: conn.rollback();
0713: }
0714:
0715: /////////////////////////////////////////////////////////////
0716: //
0717: // MINIONS
0718: //
0719: /////////////////////////////////////////////////////////////
0720:
0721: //
0722: // Initialize the hashtable of methods which are allowed to raise
0723: // SQLFeatureNotSupportedException.
0724: //
0725: private void initializeExcludableMap(
0726: HashSet<String> vanishedMethodList) throws Exception {
0727: excludableMap = new Hashtable<Class, HashSet<Method>>();
0728:
0729: int count = rawExcludables.length;
0730:
0731: for (int i = 0; i < count; i++) {
0732: Exclusions exclusions = rawExcludables[i];
0733: Class iface = exclusions.getInterface();
0734: MD[] mds = exclusions.getExcludedMethods();
0735: int exclusionCount = mds.length;
0736: HashSet<Method> excludedMethodSet = new HashSet<Method>();
0737:
0738: for (int j = 0; j < exclusionCount; j++) {
0739: MD md = mds[j];
0740:
0741: //
0742: // If we are strictly enforcing the JDBC standard,
0743: // then expose the mandatory methods which we know Derby
0744: // doesn't implement.
0745: //
0746: if (STRICT_ENFORCEMENT && !md.isOptional()) {
0747: continue;
0748: }
0749:
0750: Method method = null;
0751:
0752: try {
0753: method = iface.getMethod(md.getMethodName(), md
0754: .getArgTypes());
0755: } catch (NoSuchMethodException e) {
0756: }
0757:
0758: if (method == null) {
0759: vanishedMethodList
0760: .add("Method has vanished from SQL interface: "
0761: + iface.getName() + "." + md);
0762: }
0763:
0764: excludedMethodSet.add(method);
0765: }
0766:
0767: excludableMap.put(iface, excludedMethodSet);
0768: }
0769: }
0770:
0771: //
0772: // Find all the methods from java.sql interfaces which are implemented by an object
0773: // and which raise SQLFeatureNotSupportedException.
0774: //
0775: private void vetObject(Object candidate,
0776: HashSet<String> unsupportedList,
0777: HashSet<String> notUnderstoodList) throws Exception {
0778: Class myClass = candidate.getClass();
0779:
0780: vetInterfaces(candidate, myClass, unsupportedList,
0781: notUnderstoodList);
0782: }
0783:
0784: //
0785: // Find all the java.sql interfaces implemented by a class and find
0786: // the methods in those interfaces which raise
0787: // SQLFeatureNotSupportedException when called on the passed-in candidate object.
0788: //
0789: private void vetInterfaces(Object candidate, Class myClass,
0790: HashSet<String> unsupportedList,
0791: HashSet<String> notUnderstoodList) throws Exception {
0792: Class super Class = myClass.getSuperclass();
0793:
0794: if (super Class != null) {
0795: vetInterfaces(candidate, super Class, unsupportedList,
0796: notUnderstoodList);
0797: }
0798:
0799: //
0800: // The contract for Class.getInterfaces() states that the interfaces
0801: // come back in a deterministic order, namely, in the order that
0802: // they were declared in the "extends" clause.
0803: //
0804: Class<?>[] interfaces = myClass.getInterfaces();
0805: int interfaceCount = interfaces.length;
0806:
0807: for (int i = 0; i < interfaceCount; i++) {
0808: Class<?> iface = interfaces[i];
0809:
0810: if (iface.getPackage().getName().equals(SQL_PACKAGE_NAME)) {
0811: vetInterfaceMethods(candidate, iface, unsupportedList,
0812: notUnderstoodList);
0813: }
0814:
0815: vetInterfaces(candidate, iface, unsupportedList,
0816: notUnderstoodList);
0817: }
0818: }
0819:
0820: //
0821: // Examine all the methods in an interface to determine which ones
0822: // raise SQLFeatureNotSupportedException.
0823: //
0824: private void vetInterfaceMethods(Object candidate, Class iface,
0825: HashSet<String> unsupportedList,
0826: HashSet<String> notUnderstoodList) throws Exception {
0827: Method[] methods = sortMethods(iface);
0828: int methodCount = methods.length;
0829:
0830: for (int i = 0; i < methodCount; i++) {
0831: Method method = methods[i];
0832:
0833: vetMethod(candidate, iface, method, unsupportedList,
0834: notUnderstoodList);
0835: }
0836: }
0837:
0838: //
0839: // Return the methods of an interface in a deterministic
0840: // order. Class.getMethods() does not do us this favor.
0841: //
0842: private Method[] sortMethods(Class iface) throws Exception {
0843: Method[] raw = iface.getMethods();
0844: int count = raw.length;
0845: Method[] cooked = new Method[count];
0846: MethodSortable[] sortables = new MethodSortable[count];
0847:
0848: for (int i = 0; i < count; i++) {
0849: sortables[i] = new MethodSortable(raw[i]);
0850: }
0851:
0852: Arrays.sort(sortables);
0853:
0854: for (int i = 0; i < count; i++) {
0855: cooked[i] = sortables[i].getMethod();
0856: }
0857:
0858: return cooked;
0859: }
0860:
0861: //
0862: // Examine a single method to see if it raises SQLFeatureNotSupportedException.
0863: //
0864: private void vetMethod(Object candidate, Class iface,
0865: Method method, HashSet<String> unsupportedList,
0866: HashSet<String> notUnderstoodList) throws Exception {
0867: try {
0868: method.invoke(candidate, getNullArguments(method
0869: .getParameterTypes()));
0870:
0871: // it's ok for the method to succeed
0872: } catch (Throwable e) {
0873: if (!(e instanceof InvocationTargetException)) {
0874: recordUnexpectedError(candidate, iface, method,
0875: notUnderstoodList, e);
0876: } else {
0877: Throwable cause = e.getCause();
0878:
0879: if (cause instanceof SQLFeatureNotSupportedException) {
0880: boolean isExcludable = isExcludable(method);
0881:
0882: if (!isExcludable) {
0883: StackTraceElement[] stack = cause
0884: .getStackTrace();
0885: int i = 0;
0886: while (i < stack.length
0887: && !stack[i].getMethodName().equals(
0888: "notImplemented")) {
0889: ++i;
0890: }
0891: while (i < stack.length
0892: && stack[i].getMethodName().equals(
0893: "notImplemented")) {
0894: ++i;
0895: }
0896: if (i == stack.length) {
0897: //cause.printStackTrace();
0898: }
0899:
0900: unsupportedList.add(candidate.getClass()
0901: .getName()
0902: + ": "
0903: + method
0904: + "@"
0905: + (i == stack.length ? "no source"
0906: : cause.getStackTrace()[i]));
0907: } else {
0908:
0909: }
0910: } else if (cause instanceof SQLException) {
0911: // swallow other SQLExceptions, caused by bogus args
0912: } else if (cause instanceof NullPointerException) {
0913: // swallow other NPEs, caused by bogus args
0914: } else if (cause instanceof ArrayIndexOutOfBoundsException) {
0915: // swallow these, caused by bogus args
0916: } else {
0917: recordUnexpectedError(candidate, iface, method,
0918: notUnderstoodList, cause);
0919: }
0920:
0921: }
0922: }
0923: }
0924:
0925: //
0926: // Record an unexpected error.
0927: //
0928: private void recordUnexpectedError(Object candidate, Class iface,
0929: Method method, HashSet<String> notUnderstoodList,
0930: Throwable cause) throws Exception {
0931: notUnderstoodList.add(candidate.getClass().getName() + " "
0932: + method + " raises " + cause);
0933: }
0934:
0935: //
0936: // Returns true if this method is allowed to raise SQLFeatureNotSupportedException.
0937: //
0938: private boolean isExcludable(Method method) throws Exception {
0939: Class iface = method.getDeclaringClass();
0940: HashSet<Method> excludableMethods = excludableMap.get(iface);
0941:
0942: if (excludableMethods == null) {
0943: return false;
0944: }
0945:
0946: return excludableMethods.contains(method);
0947: }
0948:
0949: /**
0950: * Takes an array of classes and returns an array of objects with
0951: * null values compatible with the classes. Helper method for
0952: * converting a parameter list to an argument list.
0953: *
0954: * @param params a <code>Class[]</code> value
0955: * @return an <code>Object[]</code> value
0956: */
0957: private Object[] getNullArguments(Class[] params) {
0958: Object[] args = new Object[params.length];
0959: for (int i = 0; i < params.length; i++) {
0960: args[i] = getNullValueForType(params[i]);
0961: }
0962: return args;
0963: }
0964:
0965: /**
0966: * Returns a null value compatible with the class. For instance,
0967: * return <code>Boolean.FALSE</code> for primitive booleans, 0 for
0968: * primitive integers and <code>null</code> for non-primitive
0969: * types.
0970: *
0971: * @param type a <code>Class</code> value
0972: * @return a null value
0973: */
0974: private Object getNullValueForType(Class type) {
0975: if (!type.isPrimitive()) {
0976: return null;
0977: }
0978: if (type == Boolean.TYPE) {
0979: return Boolean.FALSE;
0980: }
0981: if (type == Character.TYPE) {
0982: return new Character((char) 0);
0983: }
0984: if (type == Byte.TYPE) {
0985: return new Byte((byte) 0);
0986: }
0987: if (type == Short.TYPE) {
0988: return new Short((short) 0);
0989: }
0990: if (type == Integer.TYPE) {
0991: return new Integer(0);
0992: }
0993: if (type == Long.TYPE) {
0994: return new Long(0L);
0995: }
0996: if (type == Float.TYPE) {
0997: return new Float(0f);
0998: }
0999: if (type == Double.TYPE) {
1000: return new Double(0d);
1001: }
1002: fail("Don't know how to handle type " + type);
1003: return null; // unreachable statement
1004: }
1005:
1006: // debug print the list of methods which throw SQLFeatureNotSupportedException
1007: private void printUnsupportedList(HashSet<String> unsupportedList) {
1008: int count = unsupportedList.size();
1009:
1010: if (count == 0) {
1011: return;
1012: }
1013:
1014: println("--------------- UNSUPPORTED METHODS ------------------");
1015: println("--");
1016:
1017: String[] result = new String[count];
1018:
1019: unsupportedList.toArray(result);
1020: Arrays.sort(result);
1021:
1022: for (int i = 0; i < count; i++) {
1023: println(result[i]);
1024: }
1025: }
1026:
1027: // debug print the list of methods which have disappeared from the SQL interface
1028: private void printVanishedMethodList(
1029: HashSet<String> vanishedMethodList) {
1030: int count = vanishedMethodList.size();
1031:
1032: if (count == 0) {
1033: return;
1034: }
1035:
1036: println("--------------- VANISHED METHODS ------------------");
1037: println("--");
1038:
1039: String[] result = new String[count];
1040:
1041: vanishedMethodList.toArray(result);
1042: Arrays.sort(result);
1043:
1044: for (int i = 0; i < count; i++) {
1045: println(result[i]);
1046: }
1047: }
1048:
1049: // Debug print the list of method failures which we don't understand
1050: private void printNotUnderstoodList(
1051: HashSet<String> notUnderstoodList) {
1052: int count = notUnderstoodList.size();
1053:
1054: if (count == 0) {
1055: return;
1056: }
1057:
1058: println("\n\n");
1059: println("--------------- NOT UNDERSTOOD METHODS ------------------");
1060: println("--");
1061:
1062: String[] result = new String[count];
1063:
1064: notUnderstoodList.toArray(result);
1065: Arrays.sort(result);
1066:
1067: for (int i = 0; i < count; i++) {
1068: println(result[i]);
1069: }
1070: }
1071:
1072: /////////////////////////////////////////////////////////////
1073: //
1074: // INNER CLASSES
1075: //
1076: /////////////////////////////////////////////////////////////
1077:
1078: /**
1079: * <p>
1080: * Method descriptor for optional methods which Derby does not have
1081: * to implement. We abbreviate the name of this class to make
1082: * arrays of these declarations compact and readable.
1083: * </p>
1084: */
1085: public static class MD {
1086: private String _methodName;
1087: private Class[] _argTypes;
1088:
1089: /** Construct from methodName and argument types. */
1090: public MD(String methodName, Class[] argTypes) {
1091: _methodName = methodName;
1092: _argTypes = argTypes;
1093: }
1094:
1095: /** Get the name of this method. */
1096: public String getMethodName() {
1097: return _methodName;
1098: }
1099:
1100: /** Get the types of the method's arguments */
1101: public Class[] getArgTypes() {
1102: return _argTypes;
1103: }
1104:
1105: /** Return whether this method is optional */
1106: public boolean isOptional() {
1107: return true;
1108: }
1109:
1110: public String toString() {
1111: StringBuffer buffer = new StringBuffer();
1112:
1113: buffer.append(_methodName);
1114: buffer.append("( ");
1115:
1116: if (_argTypes != null) {
1117: int count = _argTypes.length;
1118:
1119: for (int i = 0; i < count; i++) {
1120: if (i > 0) {
1121: buffer.append(", ");
1122: }
1123:
1124: buffer.append(_argTypes[i].getName());
1125: }
1126: }
1127:
1128: buffer.append(" )");
1129:
1130: return buffer.toString();
1131: }
1132:
1133: }
1134:
1135: /**
1136: * <p>
1137: * Method descriptor for mandatory methods which we know Derby does not
1138: * implement. We abbreviate the name of this class to make
1139: * arrays of these declarations compact and readable.
1140: * </p>
1141: */
1142: public static final class FD extends MD {
1143: private String _methodName;
1144: private Class[] _argTypes;
1145:
1146: /** Construct from methodName and argument types. */
1147: public FD(String methodName, Class[] argTypes) {
1148: super (methodName, argTypes);
1149: }
1150:
1151: /** Return whether this method is optional */
1152: public boolean isOptional() {
1153: return false;
1154: }
1155: }
1156:
1157: /**
1158: * <p>
1159: * Describes all of the methods for an interface which are allowed
1160: * to raise SQLFeatureNotSupportedException.
1161: * </p>
1162: */
1163: public static final class Exclusions {
1164: private Class _class;
1165: private MD[] _excludedMethods;
1166:
1167: /** Construct from the interface and descriptors for the methods which
1168: are allowed to raise SQLFeatureNotSupportedException */
1169: public Exclusions(Class theInterface, MD[] excludedMethods) {
1170: _class = theInterface;
1171: _excludedMethods = excludedMethods;
1172: }
1173:
1174: /** Get the interface. */
1175: public Class getInterface() {
1176: return _class;
1177: }
1178:
1179: /** Get descriptors for the methods which may raise
1180: SQLFeatureNotSupportedException. */
1181: public MD[] getExcludedMethods() {
1182: return _excludedMethods;
1183: }
1184: }
1185:
1186: /**
1187: * <p>
1188: * Used for sorting methods, which don't come back from Class.getMethods()
1189: * in a deterministic order. For extra credit, we put the close() method at
1190: * the end of the sort order so that, when we invoke the sorted methods, we
1191: * don't accidentally invalidate the receiver.
1192: * </p>
1193: */
1194: public static final class MethodSortable implements Comparable {
1195: private Method _method;
1196:
1197: /** Conjure out of a Method */
1198: public MethodSortable(Method method) {
1199: _method = method;
1200: }
1201:
1202: /** Get the wrapped Method */
1203: public Method getMethod() {
1204: return _method;
1205: }
1206:
1207: //////////////////////////////////////////////////
1208: //
1209: // Comparable BEHAVIOR
1210: //
1211: //////////////////////////////////////////////////
1212:
1213: public int compareTo(Object other) {
1214: MethodSortable that = (MethodSortable) other;
1215: boolean this IsClose = this .isCloseMethod();
1216: boolean thatIsClose = that.isCloseMethod();
1217:
1218: // throw the close() method to the end of the sort order
1219: if (this IsClose) {
1220: if (thatIsClose) {
1221: return 0;
1222: } else {
1223: return 1;
1224: }
1225: } else if (thatIsClose) {
1226: return -1;
1227: }
1228:
1229: return this .toString().compareTo(that.toString());
1230: }
1231:
1232: //////////////////////////////////////////////////
1233: //
1234: // Object OVERRIDES
1235: //
1236: //////////////////////////////////////////////////
1237:
1238: public String toString() {
1239: return _method.toString();
1240: }
1241:
1242: //////////////////////////////////////////////////
1243: //
1244: // MINIONS
1245: //
1246: //////////////////////////////////////////////////
1247:
1248: // Returns true if the wrapped method is close().
1249: private boolean isCloseMethod() {
1250: return (toString().startsWith("close()"));
1251: }
1252:
1253: }
1254:
1255: }
|