001: /*
002: DBPool - JDBC Connection Pool Manager
003: Copyright (c) Giles Winstanley
004: */
005: package snaq.db;
006:
007: import snaq.util.Reusable;
008: import java.sql.*;
009: import java.util.*;
010:
011: /**
012: * Connection wrapper that implements statement caching.
013: * @see snaq.db.CachedStatement
014: * @see snaq.db.CachedPreparedStatement
015: * @see snaq.db.CachedCallableStatement
016: * @author Giles Winstanley
017: */
018: public final class CacheConnection implements Connection,
019: StatementListener, Reusable {
020: // Constants for determining ResultSet parameters for statements.
021: private static int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_FORWARD_ONLY;
022: private static int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY;
023: private static int DEFAULT_RESULTSET_HOLDABILITY = ResultSet.HOLD_CURSORS_OVER_COMMIT;
024:
025: protected ConnectionPool pool;
026: protected Connection con;
027: // Statement cache (List of Statement)
028: protected List ss = new ArrayList();
029: protected List ssUsed = new ArrayList();
030: // PreparedStatement cache (Map of List of PreparedStatement)
031: protected Map ps = new HashMap();
032: protected List psUsed = new ArrayList();
033: // CallableStatement cache (Map of List of CallableStatement)
034: protected Map cs = new HashMap();
035: protected List csUsed = new ArrayList();
036: // Non-cached statements
037: protected List nonCachable = new ArrayList();
038: // Other variables
039: private boolean cacheS, cacheP, cacheC;
040: private int ssReq, ssHit;
041: private int psReq, psHit;
042: private int csReq, csHit;
043: private boolean open = true;
044:
045: /**
046: * Creates a new CacheConnection object, using the supplied Connection.
047: */
048: public CacheConnection(ConnectionPool pool, Connection con) {
049: this .pool = pool;
050: this .con = con;
051: setCacheAll(true);
052: ssReq = ssHit = psReq = psHit = csReq = csHit = 0;
053: }
054:
055: /**
056: * Added to provide caching support.
057: */
058: void setOpen() {
059: open = true;
060: }
061:
062: /**
063: * Added to provide caching support.
064: */
065: boolean isOpen() {
066: return open;
067: }
068:
069: /**
070: * Sets whether to use caching for Statements.
071: */
072: public void setCacheStatements(boolean cache) {
073: // Release statements if required
074: if (cacheS && !cache) {
075: try {
076: flushSpareStatements();
077: } catch (SQLException sqle) {
078: pool.log(sqle);
079: }
080: }
081: this .cacheS = cache;
082: }
083:
084: /**
085: * Sets whether to use caching for PreparedStatements.
086: */
087: public void setCachePreparedStatements(boolean cache) {
088: // Release statements if required
089: if (cacheP && !cache) {
090: try {
091: flushSparePreparedStatements();
092: } catch (SQLException sqle) {
093: pool.log(sqle);
094: }
095: }
096: this .cacheP = cache;
097: }
098:
099: /**
100: * Sets whether to use caching for CallableStatements.
101: */
102: public void setCacheCallableStatements(boolean cache) {
103: // Release statements if required
104: if (cacheC && !cache) {
105: try {
106: flushSpareCallableStatements();
107: } catch (SQLException sqle) {
108: pool.log(sqle);
109: }
110: }
111: this .cacheC = cache;
112: }
113:
114: /**
115: * Sets whether to use caching for all types of Statement.
116: */
117: public void setCacheAll(boolean cache) {
118: setCacheStatements(cache);
119: setCachePreparedStatements(cache);
120: setCacheCallableStatements(cache);
121: }
122:
123: /** Returns whether caching of CallableStatements is enabled. */
124: public boolean isCachingAllStatements() {
125: return cacheS && cacheP && cacheC;
126: }
127:
128: /** Returns whether caching of CallableStatements is enabled. */
129: public boolean isCachingStatements() {
130: return cacheS;
131: }
132:
133: /** Returns whether caching of CallableStatements is enabled. */
134: public boolean isCachingPreparedStatements() {
135: return cacheP;
136: }
137:
138: /** Returns whether caching of CallableStatements is enabled. */
139: public boolean isCachingCallableStatements() {
140: return cacheC;
141: }
142:
143: /**
144: * Returns the raw underlying Connection object for which this provides
145: * a wrapper. This is provided as a convenience method for using database-specific
146: * features for which the Connection object needs to be upcast.
147: * (e.g. to use Oracle-specific features needs to be cast to oracle.jdbc.OracleConnection).
148: * <em>To maintain the stability of the pooling system it is important that the
149: * raw connection is not destabilized when used in this way.</em>
150: */
151: public Connection getRawConnection() {
152: return con;
153: }
154:
155: //******************************
156: // Connection interface methods
157: //******************************
158:
159: /** Overrides method to provide caching support. */
160: public Statement createStatement() throws SQLException {
161: return createStatement(DEFAULT_RESULTSET_TYPE,
162: DEFAULT_RESULTSET_CONCURRENCY,
163: DEFAULT_RESULTSET_HOLDABILITY);
164: }
165:
166: /** Overrides method to provide caching support. */
167: public Statement createStatement(int resultSetType,
168: int resultSetConcurrency) throws SQLException {
169: return createStatement(resultSetType, resultSetConcurrency,
170: DEFAULT_RESULTSET_HOLDABILITY);
171: }
172:
173: /** Overrides method to provide caching support. */
174: public Statement createStatement(int resultSetType,
175: int resultSetConcurrency, int resultSetHoldability)
176: throws SQLException {
177: CachedStatement cs = null;
178: if (!cacheS) {
179: cs = new CachedStatement(con.createStatement(resultSetType,
180: resultSetConcurrency, resultSetHoldability));
181: cs.setStatementListener(this );
182: cs.setOpen();
183: } else {
184: synchronized (ss) {
185: ssReq++;
186: // Find Statement matching criteria required
187: for (Iterator it = ss.iterator(); it.hasNext();) {
188: CachedStatement x = (CachedStatement) it.next();
189: if (x.getResultSetType() == resultSetType
190: && x.getResultSetConcurrency() == resultSetConcurrency
191: && x.getResultSetHoldability() == resultSetHoldability) {
192: cs = x;
193: it.remove();
194: }
195: }
196: // Prepare Statement for user
197: if (cs != null) {
198: cs.setOpen();
199: ssHit++;
200: if (pool.isDebug())
201: pool.log("Statement cache hit ["
202: + cs.getParametersString() + "] - "
203: + calcHitRate(ssHit, ssReq));
204: } else {
205: cs = new CachedStatement(con.createStatement(
206: resultSetType, resultSetConcurrency,
207: resultSetHoldability));
208: cs.setStatementListener(this );
209: cs.setOpen();
210: if (pool.isDebug())
211: pool.log("Statement cache miss ["
212: + cs.getParametersString() + "] - "
213: + calcHitRate(ssHit, ssReq));
214: }
215: }
216: }
217: ssUsed.add(cs);
218: return cs;
219: }
220:
221: /** Overrides method to provide caching support. */
222: public PreparedStatement prepareStatement(String sql)
223: throws SQLException {
224: return prepareStatement(sql, DEFAULT_RESULTSET_TYPE,
225: DEFAULT_RESULTSET_CONCURRENCY,
226: DEFAULT_RESULTSET_HOLDABILITY);
227: }
228:
229: /** Overrides method to provide caching support. */
230: public PreparedStatement prepareStatement(String sql,
231: int resultSetType, int resultSetConcurrency)
232: throws SQLException {
233: return prepareStatement(sql, resultSetType,
234: resultSetConcurrency, DEFAULT_RESULTSET_HOLDABILITY);
235: }
236:
237: /**
238: * Overrides method to provide caching support.
239: */
240: public PreparedStatement prepareStatement(String sql,
241: int resultSetType, int resultSetConcurrency,
242: int resultSetHoldability) throws SQLException {
243: CachedPreparedStatement cps = null;
244: if (!cacheP) {
245: cps = new CachedPreparedStatement(sql, con
246: .prepareStatement(sql, resultSetType,
247: resultSetConcurrency, resultSetHoldability));
248: cps.setStatementListener(this );
249: cps.setOpen();
250: } else {
251: synchronized (ps) {
252: psReq++;
253: // Get List of cached PreparedStatements with matching SQL
254: List list = (List) ps.get(sql);
255: if (list != null && !list.isEmpty()) {
256: // Find first free PreparedStatement with matching parameters
257: for (Iterator it = list.iterator(); it.hasNext();) {
258: CachedPreparedStatement x = (CachedPreparedStatement) it
259: .next();
260: if (x.getResultSetType() == resultSetType
261: && x.getResultSetConcurrency() == resultSetConcurrency
262: && x.getResultSetHoldability() == resultSetHoldability) {
263: cps = x;
264: it.remove();
265: }
266: }
267: // Remove cache mapping if list empty
268: if (list.isEmpty())
269: ps.remove(sql);
270: }
271: // Prepare PreparedStatement for user
272: if (cps != null) {
273: cps.setOpen();
274: psHit++;
275: if (pool.isDebug())
276: pool.log("PreparedStatement cache hit [" + sql
277: + "," + cps.getParametersString()
278: + "] - " + calcHitRate(psHit, psReq));
279: } else {
280: cps = new CachedPreparedStatement(sql, con
281: .prepareStatement(sql, resultSetType,
282: resultSetConcurrency,
283: resultSetHoldability));
284: cps.setStatementListener(this );
285: cps.setOpen();
286: if (pool.isDebug())
287: pool.log("PreparedStatement cache miss [" + sql
288: + "," + cps.getParametersString()
289: + "] - " + calcHitRate(psHit, psReq));
290: }
291: }
292: }
293: psUsed.add(cps);
294: return cps;
295: }
296:
297: /** Overrides method to provide caching support. */
298: public CallableStatement prepareCall(String sql)
299: throws SQLException {
300: return prepareCall(sql, DEFAULT_RESULTSET_TYPE,
301: DEFAULT_RESULTSET_CONCURRENCY,
302: DEFAULT_RESULTSET_HOLDABILITY);
303: }
304:
305: /** Overrides method to provide caching support. */
306: public CallableStatement prepareCall(String sql, int resultSetType,
307: int resultSetConcurrency) throws SQLException {
308: return prepareCall(sql, resultSetType, resultSetConcurrency,
309: DEFAULT_RESULTSET_HOLDABILITY);
310: }
311:
312: /**
313: * Overrides method to provide caching support.
314: */
315: public CallableStatement prepareCall(String sql, int resultSetType,
316: int resultSetConcurrency, int resultSetHoldability)
317: throws SQLException {
318: CachedCallableStatement ccs = null;
319: if (!cacheC) {
320: ccs = new CachedCallableStatement(sql, con.prepareCall(sql));
321: ccs.setStatementListener(this );
322: ccs.setOpen();
323: } else {
324: synchronized (cs) {
325: csReq++;
326: // Get List of cached CallableStatements with matching SQL
327: List list = (List) cs.get(sql);
328: if (list != null && !list.isEmpty()) {
329: // Find first free CallableStatement with matching parameters
330: for (Iterator it = list.iterator(); it.hasNext();) {
331: CachedCallableStatement x = (CachedCallableStatement) it
332: .next();
333: if (x.getResultSetType() == resultSetType
334: && x.getResultSetConcurrency() == resultSetConcurrency
335: && x.getResultSetHoldability() == resultSetHoldability) {
336: ccs = x;
337: it.remove();
338: }
339: }
340: // Remove cache mapping if list empty
341: if (list.isEmpty())
342: cs.remove(sql);
343: }
344: // Prepare CallableStatement for user
345: if (ccs != null) {
346: ccs.setOpen();
347: csHit++;
348: if (pool.isDebug())
349: pool.log("CallableStatement cache hit [" + sql
350: + "," + ccs.getParametersString()
351: + "] - " + calcHitRate(csHit, csReq));
352: } else {
353: CallableStatement st = con.prepareCall(sql);
354: ccs = new CachedCallableStatement(sql, st);
355: ccs.setStatementListener(this );
356: ccs.setOpen();
357: if (pool.isDebug())
358: pool.log("CallableStatement cache miss [" + sql
359: + "," + ccs.getParametersString()
360: + "] - " + calcHitRate(csHit, csReq));
361: }
362: }
363: }
364: csUsed.add(ccs);
365: return ccs;
366: }
367:
368: /**
369: * Callback invoked when a statement is closed.
370: */
371: public void statementClosed(CachedStatement s) throws SQLException {
372: if (s instanceof CachedPreparedStatement) {
373: synchronized (ps) {
374: String key = ((CachedPreparedStatement) s)
375: .getSQLString();
376: psUsed.remove(s);
377: // If caching disabled close statement
378: if (!cacheP)
379: s.release();
380: else // else try to recycle it
381: {
382: try {
383: s.recycle();
384: // Place back in cache
385: List list = (List) ps.get(key);
386: if (list == null) {
387: list = new ArrayList();
388: ps.put(key, list);
389: }
390: list.add(s);
391: } catch (SQLException sqle) {
392: s.release();
393: }
394: }
395: }
396: } else if (s instanceof CachedCallableStatement) {
397: synchronized (cs) {
398: String key = ((CachedCallableStatement) s)
399: .getSQLString();
400: csUsed.remove(s);
401: // If caching disabled close statement
402: if (!cacheC)
403: s.release();
404: else // else try to recycle it
405: {
406: try {
407: s.recycle();
408: // Place back in cache
409: List list = (List) cs.get(key);
410: if (list == null) {
411: list = new ArrayList();
412: cs.put(key, list);
413: }
414: list.add(s);
415: } catch (SQLException sqle) {
416: s.release();
417: }
418: }
419: }
420: } else if (s instanceof CachedStatement) {
421: synchronized (ss) {
422: ssUsed.remove(s);
423: // If caching disabled close statement
424: if (!cacheS)
425: s.release();
426: else // else try to recycle it
427: {
428: try {
429: s.recycle();
430: ss.add(s);
431: } catch (SQLException sqle) {
432: s.release();
433: }
434: }
435: }
436: }
437: }
438:
439: private String calcHitRate(int hits, int reqs) {
440: return (reqs == 0) ? "" : (((float) hits / reqs) * 100f)
441: + "% hit rate";
442: }
443:
444: public String nativeSQL(String sql) throws SQLException {
445: return con.nativeSQL(sql);
446: }
447:
448: public void setAutoCommit(boolean autoCommit) throws SQLException {
449: con.setAutoCommit(autoCommit);
450: }
451:
452: public boolean getAutoCommit() throws SQLException {
453: return con.getAutoCommit();
454: }
455:
456: public void commit() throws SQLException {
457: con.commit();
458: }
459:
460: public void rollback() throws SQLException {
461: con.rollback();
462: }
463:
464: /**
465: * Puts connection back in a state where it can be reused.
466: */
467: public void recycle() throws SQLException {
468: // Close all open Statements
469: if (cacheS) {
470: int count = (ssUsed != null) ? ssUsed.size() : 0;
471: if (count > 0) {
472: if (pool.isDebug())
473: pool.log("Cleaning " + count + " cached Statement"
474: + (count > 1 ? "s" : ""));
475: synchronized (ssUsed) {
476: while (!ssUsed.isEmpty())
477: ((Statement) ssUsed.remove(0)).close();
478: }
479: }
480: } else {
481: flushOpenStatements();
482: flushSpareStatements();
483: }
484:
485: // Close all open PreparedStatements
486: if (cacheP) {
487: int count = (psUsed != null) ? psUsed.size() : 0;
488: if (count > 0) {
489: if (pool.isDebug())
490: pool.log("Cleaning " + count
491: + " cached PreparedStatement"
492: + (count > 1 ? "s" : ""));
493: synchronized (psUsed) {
494: while (!psUsed.isEmpty())
495: ((CachedPreparedStatement) psUsed.remove(0))
496: .close();
497: }
498: }
499: } else {
500: flushOpenPreparedStatements();
501: flushSparePreparedStatements();
502: }
503:
504: // Close all open CallableStatements
505: if (cacheC) {
506: int count = (csUsed != null) ? csUsed.size() : 0;
507: if (count > 0) {
508: if (pool.isDebug())
509: pool.log("Cleaning " + count
510: + " cached CallableStatement"
511: + (count > 1 ? "s" : ""));
512: synchronized (csUsed) {
513: while (!csUsed.isEmpty())
514: ((CachedCallableStatement) csUsed.remove(0))
515: .close();
516: }
517: }
518: } else {
519: flushOpenCallableStatements();
520: flushSpareCallableStatements();
521: }
522:
523: // Close all open non-cachable PreparedStatements.
524: flushOpenNonCachableStatements();
525:
526: // Put connection back in default state
527: if (!getAutoCommit()) {
528: try {
529: rollback();
530: } catch (SQLException sqle) {
531: pool.log(sqle);
532: }
533: setAutoCommit(true);
534: }
535: clearWarnings();
536:
537: // Clear type map entries.
538: Map tm = getTypeMap();
539: if (tm != null)
540: tm.clear();
541: }
542:
543: /**
544: * Overrides method to provide caching support.
545: */
546: public void close() throws SQLException {
547: if (!open)
548: throw new SQLException("Connection already closed");
549: open = false;
550: // Hand itself back to the pool
551: pool.freeConnection(this );
552: }
553:
554: /**
555: * Returns the current number of spare Statements that are cached.
556: */
557: public int getSpareStatementCount() {
558: return ss.size();
559: }
560:
561: /**
562: * Returns the current number of Statements that are in use
563: * (not including PreparedStatements & CallableStatements).
564: */
565: public int getOpenStatementCount() {
566: return ssUsed.size();
567: }
568:
569: /**
570: * Returns the current number of spare PreparedStatements that are cached.
571: */
572: public int getSparePreparedStatementCount() {
573: int count = 0;
574: synchronized (ps) {
575: for (Iterator it = ps.values().iterator(); it.hasNext();)
576: count += ((List) it.next()).size();
577: }
578: return count;
579: }
580:
581: /**
582: * Returns the current number of PreparedStatements that are in use
583: * (not including CallableStatements).
584: */
585: public int getOpenPreparedStatementCount() {
586: return psUsed.size();
587: }
588:
589: /**
590: * Returns the current number of spare CallableStatements that are cached.
591: */
592: public int getSpareCallableStatementCount() {
593: int count = 0;
594: synchronized (cs) {
595: for (Iterator it = cs.values().iterator(); it.hasNext();)
596: count += ((List) it.next()).size();
597: }
598: return count;
599: }
600:
601: /**
602: * Returns the current number of CallableStatements that are in use.
603: */
604: public int getOpenCallableStatementCount() {
605: return csUsed.size();
606: }
607:
608: /**
609: * Returns the current number of non-cachable statements that are in use.
610: * (Currently only some PreparedStatements are non-cachable by virtue of
611: * a request made at creation for support for auto-generated keys.)
612: * @see snaq.db.CacheConnection#prepareStatement(String, int)
613: * @see snaq.db.CacheConnection#prepareStatement(String, int[])
614: * @see snaq.db.CacheConnection#prepareStatement(String, String[])
615: */
616: public int getOpenNonCachableStatementCount() {
617: return nonCachable.size();
618: }
619:
620: /**
621: * Flushes the spare Statement caches for this connection.
622: */
623: protected void flushSpareStatements() throws SQLException {
624: // Close all cached Statements
625: int count = (ss != null) ? ss.size() : 0;
626: if (count > 0) {
627: if (pool.isDebug())
628: pool.log("Closing " + count + " cached Statement"
629: + (count > 1 ? "s" : ""));
630: synchronized (ss) {
631: while (!ss.isEmpty())
632: ((CachedStatement) ss.remove(0)).release();
633: }
634: }
635: }
636:
637: /**
638: * Flushes the open Statement cache for this connection.
639: */
640: protected void flushOpenStatements() throws SQLException {
641: // Close all open Statements
642: int count = (ssUsed != null) ? ssUsed.size() : 0;
643: if (count > 0) {
644: if (pool.isDebug())
645: pool.log("Closing " + count + " open Statement"
646: + (count > 1 ? "s" : ""));
647: synchronized (ssUsed) {
648: while (!ssUsed.isEmpty())
649: ((CachedStatement) ssUsed.remove(0)).release();
650: }
651: }
652: }
653:
654: /**
655: * Flushes the spare PreparedStatement cache for this connection.
656: */
657: protected void flushSparePreparedStatements() throws SQLException {
658: // Close all cached PreparedStatements
659: int count = (ps != null) ? ps.size() : 0;
660: if (count > 0) {
661: if (pool.isDebug())
662: pool.log("Closing " + count
663: + " cached PreparedStatement"
664: + (count > 1 ? "s" : ""));
665: synchronized (ps) {
666: for (Iterator iter = ps.values().iterator(); iter
667: .hasNext();) {
668: List list = (List) iter.next();
669: for (Iterator it = list.iterator(); it.hasNext();)
670: ((CachedPreparedStatement) it.next()).release();
671: }
672: ps.clear();
673: }
674: }
675: }
676:
677: /**
678: * Flushes the open PreparedStatement cache for this connection.
679: */
680: protected void flushOpenPreparedStatements() throws SQLException {
681: // Close all open PreparedStatements
682: int count = (psUsed != null) ? psUsed.size() : 0;
683: if (count > 0) {
684: if (pool.isDebug())
685: pool.log("Closing " + count + " open PreparedStatement"
686: + (count > 1 ? "s" : ""));
687: synchronized (psUsed) {
688: while (!psUsed.isEmpty())
689: ((CachedPreparedStatement) psUsed.remove(0))
690: .release();
691: }
692: }
693: }
694:
695: /**
696: * Flushes the spare CallableStatement cache for this connection.
697: */
698: protected void flushSpareCallableStatements() throws SQLException {
699: // Close all cached CallableStatements
700: int count = (cs != null) ? cs.size() : 0;
701: if (count > 0) {
702: if (pool.isDebug())
703: pool.log("Closing " + count
704: + " cached CallableStatement"
705: + (count > 1 ? "s" : ""));
706: synchronized (cs) {
707: for (Iterator iter = cs.values().iterator(); iter
708: .hasNext();) {
709: List list = (List) iter.next();
710: for (Iterator it = list.iterator(); it.hasNext();)
711: ((CachedCallableStatement) it.next()).release();
712: }
713: cs.clear();
714: }
715: }
716: }
717:
718: /**
719: * Flushes the open CallableStatement cache for this connection.
720: */
721: protected void flushOpenCallableStatements() throws SQLException {
722: // Close all open CallableStatements
723: int count = (csUsed != null) ? csUsed.size() : 0;
724: if (count > 0) {
725: if (pool.isDebug())
726: pool.log("Closing " + count + " open CallableStatement"
727: + (count > 1 ? "s" : ""));
728: synchronized (csUsed) {
729: while (!csUsed.isEmpty())
730: ((CachedCallableStatement) csUsed.remove(0))
731: .release();
732: }
733: }
734: }
735:
736: /**
737: * Flushes the non-cachable Statements for this connection.
738: */
739: protected void flushOpenNonCachableStatements() throws SQLException {
740: int count = (nonCachable != null) ? nonCachable.size() : 0;
741: if (count > 0) {
742: if (pool.isDebug())
743: pool.log("Closing " + count
744: + " open non-cachable Statement"
745: + (count > 1 ? "s" : ""));
746: synchronized (nonCachable) {
747: while (!nonCachable.isEmpty()) {
748: try {
749: ((Statement) nonCachable.remove(0)).close();
750: } catch (SQLException sqle) {
751: pool.log(sqle);
752: }
753: }
754: }
755: }
756: }
757:
758: /**
759: * Destroys the wrapped connection.
760: */
761: public void release() throws SQLException {
762: open = false;
763: ArrayList list = new ArrayList();
764:
765: try {
766: flushSpareStatements();
767: flushOpenStatements();
768: } catch (SQLException e) {
769: list.add(e);
770: }
771: try {
772: flushSparePreparedStatements();
773: flushOpenPreparedStatements();
774: } catch (SQLException e) {
775: list.add(e);
776: }
777: try {
778: flushSpareCallableStatements();
779: flushOpenCallableStatements();
780: } catch (SQLException e) {
781: list.add(e);
782: }
783: try {
784: flushOpenNonCachableStatements();
785: } catch (SQLException e) {
786: list.add(e);
787: }
788:
789: try {
790: con.close();
791: } catch (SQLException e) {
792: list.add(e);
793: }
794:
795: if (!list.isEmpty()) {
796: SQLException sqle = new SQLException(
797: "Problem releasing connection resources");
798: for (Iterator it = list.iterator(); it.hasNext();) {
799: SQLException x = (SQLException) it.next();
800: sqle.setNextException(x);
801: sqle = x;
802: }
803: throw sqle;
804: }
805: }
806:
807: public boolean isClosed() throws SQLException {
808: return con.isClosed();
809: }
810:
811: public DatabaseMetaData getMetaData() throws SQLException {
812: return con.getMetaData();
813: }
814:
815: public void setReadOnly(boolean readOnly) throws SQLException {
816: con.setReadOnly(readOnly);
817: }
818:
819: public boolean isReadOnly() throws SQLException {
820: return con.isReadOnly();
821: }
822:
823: public void setCatalog(String catalog) throws SQLException {
824: con.setCatalog(catalog);
825: }
826:
827: public String getCatalog() throws SQLException {
828: return con.getCatalog();
829: }
830:
831: public void setTransactionIsolation(int level) throws SQLException {
832: con.setTransactionIsolation(level);
833: }
834:
835: public int getTransactionIsolation() throws SQLException {
836: return con.getTransactionIsolation();
837: }
838:
839: public SQLWarning getWarnings() throws SQLException {
840: return con.getWarnings();
841: }
842:
843: public void clearWarnings() throws SQLException {
844: con.clearWarnings();
845: }
846:
847: public Map getTypeMap() throws SQLException {
848: return con.getTypeMap();
849: }
850:
851: public void setTypeMap(Map map) throws SQLException {
852: con.setTypeMap(map);
853: }
854:
855: //**********************************
856: // Interface methods from JDBC 3.0
857: //**********************************
858:
859: public void setHoldability(int holdability) throws SQLException {
860: con.setHoldability(holdability);
861: }
862:
863: public int getHoldability() throws SQLException {
864: return con.getHoldability();
865: }
866:
867: public Savepoint setSavepoint() throws SQLException {
868: return con.setSavepoint();
869: }
870:
871: public Savepoint setSavepoint(String name) throws SQLException {
872: return con.setSavepoint(name);
873: }
874:
875: public void rollback(Savepoint savepoint) throws SQLException {
876: con.rollback(savepoint);
877: }
878:
879: public void releaseSavepoint(Savepoint savepoint)
880: throws SQLException {
881: con.releaseSavepoint(savepoint);
882: }
883:
884: public PreparedStatement prepareStatement(String sql,
885: int autoGeneratedKeys) throws SQLException {
886: PreparedStatement x = con.prepareStatement(sql,
887: autoGeneratedKeys);
888: nonCachable.add(x);
889: return x;
890: }
891:
892: public PreparedStatement prepareStatement(String sql,
893: int[] columnIndexes) throws SQLException {
894: PreparedStatement x = con.prepareStatement(sql, columnIndexes);
895: nonCachable.add(x);
896: return x;
897: }
898:
899: public PreparedStatement prepareStatement(String sql,
900: String[] columnNames) throws SQLException {
901: PreparedStatement x = con.prepareStatement(sql, columnNames);
902: nonCachable.add(x);
903: return x;
904: }
905: }
|