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:
024: */
025: package com.mysql.jdbc.jdbc2.optional;
026:
027: import java.io.InputStream;
028: import java.io.Reader;
029: import java.lang.reflect.InvocationHandler;
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032: import java.lang.reflect.Proxy;
033: import java.sql.Array;
034: import java.sql.Blob;
035: import java.sql.Clob;
036: import java.sql.Connection;
037: import java.sql.NClob;
038: import java.sql.PreparedStatement;
039: import java.sql.RowId;
040: import java.sql.SQLClientInfoException;
041: import java.sql.SQLException;
042: import java.sql.SQLXML;
043: import java.sql.Statement;
044: import java.util.HashMap;
045: import java.util.List;
046: import java.util.Map;
047: import java.util.Properties;
048:
049: import com.mysql.jdbc.ConnectionImpl;
050: import com.mysql.jdbc.SQLError;
051: import com.mysql.jdbc.jdbc2.optional.ConnectionWrapper;
052: import com.mysql.jdbc.jdbc2.optional.MysqlPooledConnection;
053:
054: /**
055: */
056: public class JDBC4PreparedStatementWrapper extends
057: PreparedStatementWrapper {
058:
059: JDBC4PreparedStatementWrapper(ConnectionWrapper c,
060: MysqlPooledConnection conn, PreparedStatement toWrap) {
061: super (c, conn, toWrap);
062: }
063:
064: public void close() throws SQLException {
065: try {
066: super .close();
067: } finally {
068: this .unwrappedInterfaces = null;
069: }
070: }
071:
072: public boolean isClosed() throws SQLException {
073: try {
074: if (this .wrappedStmt != null) {
075: return this .wrappedStmt.isClosed();
076: } else {
077: throw SQLError.createSQLException(
078: "Statement already closed",
079: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
080: }
081: } catch (SQLException sqlEx) {
082: checkAndFireConnectionError(sqlEx);
083: }
084:
085: return false; // never get here - compiler can't tell
086: }
087:
088: public void setPoolable(boolean poolable) throws SQLException {
089: try {
090: if (this .wrappedStmt != null) {
091: this .wrappedStmt.setPoolable(poolable);
092: } else {
093: throw SQLError.createSQLException(
094: "Statement already closed",
095: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
096: }
097: } catch (SQLException sqlEx) {
098: checkAndFireConnectionError(sqlEx);
099: }
100: }
101:
102: public boolean isPoolable() throws SQLException {
103: try {
104: if (this .wrappedStmt != null) {
105: return this .wrappedStmt.isPoolable();
106: } else {
107: throw SQLError.createSQLException(
108: "Statement already closed",
109: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
110: }
111: } catch (SQLException sqlEx) {
112: checkAndFireConnectionError(sqlEx);
113: }
114:
115: return false; // never get here - compiler can't tell
116: }
117:
118: public void setRowId(int parameterIndex, RowId x)
119: throws SQLException {
120: try {
121: if (this .wrappedStmt != null) {
122: ((PreparedStatement) this .wrappedStmt).setRowId(
123: parameterIndex, x);
124: } else {
125: throw SQLError.createSQLException(
126: "No operations allowed after statement closed",
127: SQLError.SQL_STATE_GENERAL_ERROR);
128: }
129: } catch (SQLException sqlEx) {
130: checkAndFireConnectionError(sqlEx);
131: }
132: }
133:
134: public void setNClob(int parameterIndex, NClob value)
135: throws SQLException {
136: try {
137: if (this .wrappedStmt != null) {
138: ((PreparedStatement) this .wrappedStmt).setNClob(
139: parameterIndex, value);
140: } else {
141: throw SQLError.createSQLException(
142: "No operations allowed after statement closed",
143: SQLError.SQL_STATE_GENERAL_ERROR);
144: }
145: } catch (SQLException sqlEx) {
146: checkAndFireConnectionError(sqlEx);
147: }
148: }
149:
150: public void setSQLXML(int parameterIndex, SQLXML xmlObject)
151: throws SQLException {
152: try {
153: if (this .wrappedStmt != null) {
154: ((PreparedStatement) this .wrappedStmt).setSQLXML(
155: parameterIndex, xmlObject);
156: } else {
157: throw SQLError.createSQLException(
158: "No operations allowed after statement closed",
159: SQLError.SQL_STATE_GENERAL_ERROR);
160: }
161: } catch (SQLException sqlEx) {
162: checkAndFireConnectionError(sqlEx);
163: }
164: }
165:
166: public void setNString(int parameterIndex, String value)
167: throws SQLException {
168: try {
169: if (this .wrappedStmt != null) {
170: ((PreparedStatement) this .wrappedStmt).setNString(
171: parameterIndex, value);
172: } else {
173: throw SQLError.createSQLException(
174: "No operations allowed after statement closed",
175: SQLError.SQL_STATE_GENERAL_ERROR);
176: }
177: } catch (SQLException sqlEx) {
178: checkAndFireConnectionError(sqlEx);
179: }
180: }
181:
182: public void setNCharacterStream(int parameterIndex, Reader value,
183: long length) throws SQLException {
184: try {
185: if (this .wrappedStmt != null) {
186: ((PreparedStatement) this .wrappedStmt)
187: .setNCharacterStream(parameterIndex, value,
188: length);
189: } else {
190: throw SQLError.createSQLException(
191: "No operations allowed after statement closed",
192: SQLError.SQL_STATE_GENERAL_ERROR);
193: }
194: } catch (SQLException sqlEx) {
195: checkAndFireConnectionError(sqlEx);
196: }
197: }
198:
199: public void setClob(int parameterIndex, Reader reader, long length)
200: throws SQLException {
201: try {
202: if (this .wrappedStmt != null) {
203: ((PreparedStatement) this .wrappedStmt).setClob(
204: parameterIndex, reader, length);
205: } else {
206: throw SQLError.createSQLException(
207: "No operations allowed after statement closed",
208: SQLError.SQL_STATE_GENERAL_ERROR);
209: }
210: } catch (SQLException sqlEx) {
211: checkAndFireConnectionError(sqlEx);
212: }
213: }
214:
215: public void setBlob(int parameterIndex, InputStream inputStream,
216: long length) throws SQLException {
217: try {
218: if (this .wrappedStmt != null) {
219: ((PreparedStatement) this .wrappedStmt).setBlob(
220: parameterIndex, inputStream, length);
221: } else {
222: throw SQLError.createSQLException(
223: "No operations allowed after statement closed",
224: SQLError.SQL_STATE_GENERAL_ERROR);
225: }
226: } catch (SQLException sqlEx) {
227: checkAndFireConnectionError(sqlEx);
228: }
229: }
230:
231: public void setNClob(int parameterIndex, Reader reader, long length)
232: throws SQLException {
233: try {
234: if (this .wrappedStmt != null) {
235: ((PreparedStatement) this .wrappedStmt).setNClob(
236: parameterIndex, reader, length);
237: } else {
238: throw SQLError.createSQLException(
239: "No operations allowed after statement closed",
240: SQLError.SQL_STATE_GENERAL_ERROR);
241: }
242: } catch (SQLException sqlEx) {
243: checkAndFireConnectionError(sqlEx);
244: }
245: }
246:
247: public void setAsciiStream(int parameterIndex, InputStream x,
248: long length) throws SQLException {
249: try {
250: if (this .wrappedStmt != null) {
251: ((PreparedStatement) this .wrappedStmt).setAsciiStream(
252: parameterIndex, x, length);
253: } else {
254: throw SQLError.createSQLException(
255: "No operations allowed after statement closed",
256: SQLError.SQL_STATE_GENERAL_ERROR);
257: }
258: } catch (SQLException sqlEx) {
259: checkAndFireConnectionError(sqlEx);
260: }
261: }
262:
263: public void setBinaryStream(int parameterIndex, InputStream x,
264: long length) throws SQLException {
265: try {
266: if (this .wrappedStmt != null) {
267: ((PreparedStatement) this .wrappedStmt).setBinaryStream(
268: parameterIndex, x, length);
269: } else {
270: throw SQLError.createSQLException(
271: "No operations allowed after statement closed",
272: SQLError.SQL_STATE_GENERAL_ERROR);
273: }
274: } catch (SQLException sqlEx) {
275: checkAndFireConnectionError(sqlEx);
276: }
277: }
278:
279: public void setCharacterStream(int parameterIndex, Reader reader,
280: long length) throws SQLException {
281: try {
282: if (this .wrappedStmt != null) {
283: ((PreparedStatement) this .wrappedStmt)
284: .setCharacterStream(parameterIndex, reader,
285: length);
286: } else {
287: throw SQLError.createSQLException(
288: "No operations allowed after statement closed",
289: SQLError.SQL_STATE_GENERAL_ERROR);
290: }
291: } catch (SQLException sqlEx) {
292: checkAndFireConnectionError(sqlEx);
293: }
294: }
295:
296: public void setAsciiStream(int parameterIndex, InputStream x)
297: throws SQLException {
298: try {
299: if (this .wrappedStmt != null) {
300: ((PreparedStatement) this .wrappedStmt).setAsciiStream(
301: parameterIndex, x);
302: } else {
303: throw SQLError.createSQLException(
304: "No operations allowed after statement closed",
305: SQLError.SQL_STATE_GENERAL_ERROR);
306: }
307: } catch (SQLException sqlEx) {
308: checkAndFireConnectionError(sqlEx);
309: }
310: }
311:
312: public void setBinaryStream(int parameterIndex, InputStream x)
313: throws SQLException {
314: try {
315: if (this .wrappedStmt != null) {
316: ((PreparedStatement) this .wrappedStmt).setBinaryStream(
317: parameterIndex, x);
318: } else {
319: throw SQLError.createSQLException(
320: "No operations allowed after statement closed",
321: SQLError.SQL_STATE_GENERAL_ERROR);
322: }
323: } catch (SQLException sqlEx) {
324: checkAndFireConnectionError(sqlEx);
325: }
326: }
327:
328: public void setCharacterStream(int parameterIndex, Reader reader)
329: throws SQLException {
330: try {
331: if (this .wrappedStmt != null) {
332: ((PreparedStatement) this .wrappedStmt)
333: .setCharacterStream(parameterIndex, reader);
334: } else {
335: throw SQLError.createSQLException(
336: "No operations allowed after statement closed",
337: SQLError.SQL_STATE_GENERAL_ERROR);
338: }
339: } catch (SQLException sqlEx) {
340: checkAndFireConnectionError(sqlEx);
341: }
342:
343: }
344:
345: public void setNCharacterStream(int parameterIndex, Reader value)
346: throws SQLException {
347: try {
348: if (this .wrappedStmt != null) {
349: ((PreparedStatement) this .wrappedStmt)
350: .setNCharacterStream(parameterIndex, value);
351: } else {
352: throw SQLError.createSQLException(
353: "No operations allowed after statement closed",
354: SQLError.SQL_STATE_GENERAL_ERROR);
355: }
356: } catch (SQLException sqlEx) {
357: checkAndFireConnectionError(sqlEx);
358: }
359:
360: }
361:
362: public void setClob(int parameterIndex, Reader reader)
363: throws SQLException {
364: try {
365: if (this .wrappedStmt != null) {
366: ((PreparedStatement) this .wrappedStmt).setClob(
367: parameterIndex, reader);
368: } else {
369: throw SQLError.createSQLException(
370: "No operations allowed after statement closed",
371: SQLError.SQL_STATE_GENERAL_ERROR);
372: }
373: } catch (SQLException sqlEx) {
374: checkAndFireConnectionError(sqlEx);
375: }
376:
377: }
378:
379: public void setBlob(int parameterIndex, InputStream inputStream)
380: throws SQLException {
381: try {
382: if (this .wrappedStmt != null) {
383: ((PreparedStatement) this .wrappedStmt).setBlob(
384: parameterIndex, inputStream);
385: } else {
386: throw SQLError.createSQLException(
387: "No operations allowed after statement closed",
388: SQLError.SQL_STATE_GENERAL_ERROR);
389: }
390: } catch (SQLException sqlEx) {
391: checkAndFireConnectionError(sqlEx);
392: }
393: }
394:
395: public void setNClob(int parameterIndex, Reader reader)
396: throws SQLException {
397: try {
398: if (this .wrappedStmt != null) {
399: ((PreparedStatement) this .wrappedStmt).setNClob(
400: parameterIndex, reader);
401: } else {
402: throw SQLError.createSQLException(
403: "No operations allowed after statement closed",
404: SQLError.SQL_STATE_GENERAL_ERROR);
405: }
406: } catch (SQLException sqlEx) {
407: checkAndFireConnectionError(sqlEx);
408: }
409: }
410:
411: /**
412: * Returns true if this either implements the interface argument or is
413: * directly or indirectly a wrapper for an object that does. Returns false
414: * otherwise. If this implements the interface then return true, else if
415: * this is a wrapper then return the result of recursively calling
416: * <code>isWrapperFor</code> on the wrapped object. If this does not
417: * implement the interface and is not a wrapper, return false. This method
418: * should be implemented as a low-cost operation compared to
419: * <code>unwrap</code> so that callers can use this method to avoid
420: * expensive <code>unwrap</code> calls that may fail. If this method
421: * returns true then calling <code>unwrap</code> with the same argument
422: * should succeed.
423: *
424: * @param interfaces
425: * a Class defining an interface.
426: * @return true if this implements the interface or directly or indirectly
427: * wraps an object that does.
428: * @throws java.sql.SQLException
429: * if an error occurs while determining whether this is a
430: * wrapper for an object with the given interface.
431: * @since 1.6
432: */
433: public boolean isWrapperFor(Class<?> iface) throws SQLException {
434:
435: boolean isInstance = iface.isInstance(this );
436:
437: if (isInstance) {
438: return true;
439: }
440:
441: String interfaceClassName = iface.getName();
442:
443: return (interfaceClassName.equals("com.mysql.jdbc.Statement")
444: || interfaceClassName.equals("java.sql.Statement")
445: || interfaceClassName
446: .equals("java.sql.PreparedStatement") || interfaceClassName
447: .equals("java.sql.Wrapper"));
448: }
449:
450: /**
451: * Returns an object that implements the given interface to allow access to
452: * non-standard methods, or standard methods not exposed by the proxy. The
453: * result may be either the object found to implement the interface or a
454: * proxy for that object. If the receiver implements the interface then that
455: * is the object. If the receiver is a wrapper and the wrapped object
456: * implements the interface then that is the object. Otherwise the object is
457: * the result of calling <code>unwrap</code> recursively on the wrapped
458: * object. If the receiver is not a wrapper and does not implement the
459: * interface, then an <code>SQLException</code> is thrown.
460: *
461: * @param iface
462: * A Class defining an interface that the result must implement.
463: * @return an object that implements the interface. May be a proxy for the
464: * actual implementing object.
465: * @throws java.sql.SQLException
466: * If no object found that implements the interface
467: * @since 1.6
468: */
469: public synchronized <T> T unwrap(java.lang.Class<T> iface)
470: throws java.sql.SQLException {
471: try {
472: if ("java.sql.Statement".equals(iface.getName())
473: || "java.sql.PreparedStatement".equals(iface
474: .getName())
475: || "java.sql.Wrapper.class".equals(iface.getName())) {
476: return iface.cast(this );
477: }
478:
479: if (unwrappedInterfaces == null) {
480: unwrappedInterfaces = new HashMap();
481: }
482:
483: Object cachedUnwrapped = unwrappedInterfaces.get(iface);
484:
485: if (cachedUnwrapped == null) {
486: if (cachedUnwrapped == null) {
487: cachedUnwrapped = Proxy.newProxyInstance(
488: this .wrappedStmt.getClass()
489: .getClassLoader(),
490: new Class[] { iface },
491: new ConnectionErrorFiringInvocationHandler(
492: this .wrappedStmt));
493: unwrappedInterfaces.put(iface, cachedUnwrapped);
494: }
495: unwrappedInterfaces.put(iface, cachedUnwrapped);
496: }
497:
498: return iface.cast(cachedUnwrapped);
499: } catch (ClassCastException cce) {
500: throw SQLError.createSQLException("Unable to unwrap to "
501: + iface.toString(),
502: SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
503: }
504: }
505: }
|