0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019: package org.apache.openjpa.lib.jdbc;
0020:
0021: import java.io.InputStream;
0022: import java.io.Reader;
0023: import java.math.BigDecimal;
0024: import java.sql.Array;
0025: import java.sql.BatchUpdateException;
0026: import java.sql.Blob;
0027: import java.sql.Clob;
0028: import java.sql.Connection;
0029: import java.sql.DatabaseMetaData;
0030: import java.sql.Date;
0031: import java.sql.PreparedStatement;
0032: import java.sql.Ref;
0033: import java.sql.ResultSet;
0034: import java.sql.ResultSetMetaData;
0035: import java.sql.SQLException;
0036: import java.sql.SQLWarning;
0037: import java.sql.Savepoint;
0038: import java.sql.Statement;
0039: import java.sql.Time;
0040: import java.sql.Timestamp;
0041: import java.util.ArrayList;
0042: import java.util.Arrays;
0043: import java.util.Calendar;
0044: import java.util.Iterator;
0045: import java.util.List;
0046:
0047: import org.apache.openjpa.lib.log.Log;
0048: import org.apache.openjpa.lib.util.J2DoPrivHelper;
0049:
0050: /**
0051: * A {@link ConnectionDecorator} that creates logging connections and
0052: * {@link ReportingSQLException}s.
0053: *
0054: * @author Marc Prud'hommeaux
0055: * @nojavadoc
0056: */
0057: public class LoggingConnectionDecorator implements ConnectionDecorator {
0058:
0059: private static final String SEP = J2DoPrivHelper.getLineSeparator();
0060:
0061: private static final int WARN_IGNORE = 0;
0062: private static final int WARN_LOG_TRACE = 1;
0063: private static final int WARN_LOG_INFO = 2;
0064: private static final int WARN_LOG_WARN = 3;
0065: private static final int WARN_LOG_ERROR = 4;
0066: private static final int WARN_THROW = 5;
0067: private static final int WARN_HANDLE = 6;
0068: private static final String[] WARNING_ACTIONS = new String[7];
0069:
0070: static {
0071: WARNING_ACTIONS[WARN_IGNORE] = "ignore";
0072: WARNING_ACTIONS[WARN_LOG_TRACE] = "trace";
0073: WARNING_ACTIONS[WARN_LOG_INFO] = "info";
0074: WARNING_ACTIONS[WARN_LOG_WARN] = "warn";
0075: WARNING_ACTIONS[WARN_LOG_ERROR] = "error";
0076: WARNING_ACTIONS[WARN_THROW] = "throw";
0077: WARNING_ACTIONS[WARN_HANDLE] = "handle";
0078: }
0079:
0080: private final DataSourceLogs _logs = new DataSourceLogs();
0081: private SQLFormatter _formatter;
0082: private boolean _prettyPrint;
0083: private int _prettyPrintLineLength = 60;
0084: private int _warningAction = WARN_IGNORE;
0085: private SQLWarningHandler _warningHandler;
0086: private boolean _trackParameters = true;
0087:
0088: /**
0089: * If set to <code>true</code>, pretty-print SQL by running it
0090: * through {@link SQLFormatter#prettyPrint}. If
0091: * <code>false</code>, don't pretty-print, and output SQL logs in
0092: * a single line. Pretty-printed SQL can be easier for a human to
0093: * read, but is harder to parse with tools like grep.
0094: */
0095: public void setPrettyPrint(boolean prettyPrint) {
0096: _prettyPrint = prettyPrint;
0097: if (_formatter == null && _prettyPrint) {
0098: _formatter = new SQLFormatter();
0099: _formatter.setLineLength(_prettyPrintLineLength);
0100: } else if (!_prettyPrint)
0101: _formatter = null;
0102: }
0103:
0104: /**
0105: * @see #setPrettyPrint
0106: */
0107: public boolean getPrettyPrint() {
0108: return _prettyPrint;
0109: }
0110:
0111: /**
0112: * The number of characters to print per line when
0113: * pretty-printing of SQL is enabled. Defaults to 60 to provide
0114: * some space for any ant-related characters on the left of a
0115: * standard 80-character display.
0116: */
0117: public void setPrettyPrintLineLength(int length) {
0118: _prettyPrintLineLength = length;
0119: if (_formatter != null)
0120: _formatter.setLineLength(length);
0121: }
0122:
0123: /**
0124: * @see #setPrettyPrintLineLength
0125: */
0126: public int getPrettyPrintLineLength() {
0127: return _prettyPrintLineLength;
0128: }
0129:
0130: /**
0131: * Whether to track parameters for the purposes of reporting exceptions.
0132: */
0133: public void setTrackParameters(boolean trackParameters) {
0134: _trackParameters = trackParameters;
0135: }
0136:
0137: /**
0138: * Whether to track parameters for the purposes of reporting exceptions.
0139: */
0140: public boolean getTrackParameters() {
0141: return _trackParameters;
0142: }
0143:
0144: /**
0145: * What to do with SQL warnings.
0146: */
0147: public void setWarningAction(String warningAction) {
0148: int index = Arrays.asList(WARNING_ACTIONS).indexOf(
0149: warningAction);
0150: if (index < 0)
0151: index = WARN_IGNORE;
0152: _warningAction = index;
0153: }
0154:
0155: /**
0156: * What to do with SQL warnings.
0157: */
0158: public String getWarningAction() {
0159: return WARNING_ACTIONS[_warningAction];
0160: }
0161:
0162: /**
0163: * What to do with SQL warnings.
0164: */
0165: public void setWarningHandler(SQLWarningHandler warningHandler) {
0166: _warningHandler = warningHandler;
0167: }
0168:
0169: /**
0170: * What to do with SQL warnings.
0171: */
0172: public SQLWarningHandler getWarningHandler() {
0173: return _warningHandler;
0174: }
0175:
0176: /**
0177: * The log to write to.
0178: */
0179: public DataSourceLogs getLogs() {
0180: return _logs;
0181: }
0182:
0183: public Connection decorate(Connection conn) throws SQLException {
0184: return new LoggingConnection(conn);
0185: }
0186:
0187: /**
0188: * Include SQL in exception.
0189: */
0190: private SQLException wrap(SQLException sqle, Statement stmnt) {
0191: if (sqle instanceof ReportingSQLException)
0192: return (ReportingSQLException) sqle;
0193: return new ReportingSQLException(sqle, stmnt);
0194: }
0195:
0196: /**
0197: * Include SQL in exception.
0198: */
0199: private SQLException wrap(SQLException sqle, String sql) {
0200: if (sqle instanceof ReportingSQLException)
0201: return (ReportingSQLException) sqle;
0202: return new ReportingSQLException(sqle, sql);
0203: }
0204:
0205: /**
0206: * Interface that allows customization of what to do when
0207: * {@link SQLWarning}s occur.
0208: */
0209: public static interface SQLWarningHandler {
0210:
0211: public void handleWarning(SQLWarning warning)
0212: throws SQLException;
0213: }
0214:
0215: /**
0216: * Logging connection.
0217: */
0218: private class LoggingConnection extends DelegatingConnection {
0219:
0220: public LoggingConnection(Connection conn) throws SQLException {
0221: super (conn);
0222: }
0223:
0224: protected PreparedStatement prepareStatement(String sql,
0225: boolean wrap) throws SQLException {
0226: try {
0227: PreparedStatement stmnt = super .prepareStatement(sql,
0228: false);
0229: return new LoggingPreparedStatement(stmnt, sql);
0230: } catch (SQLException se) {
0231: throw wrap(se, sql);
0232: }
0233: }
0234:
0235: protected PreparedStatement prepareStatement(String sql,
0236: int rsType, int rsConcur, boolean wrap)
0237: throws SQLException {
0238: try {
0239: PreparedStatement stmnt = super .prepareStatement(sql,
0240: rsType, rsConcur, false);
0241: return new LoggingPreparedStatement(stmnt, sql);
0242: } catch (SQLException se) {
0243: throw wrap(se, sql);
0244: }
0245: }
0246:
0247: protected Statement createStatement(boolean wrap)
0248: throws SQLException {
0249: Statement stmnt = super .createStatement(false);
0250: return new LoggingStatement(stmnt);
0251: }
0252:
0253: protected Statement createStatement(int type, int concurrency,
0254: boolean wrap) throws SQLException {
0255: Statement stmnt = super .createStatement(type, concurrency,
0256: false);
0257: return new LoggingStatement(stmnt);
0258: }
0259:
0260: public void commit() throws SQLException {
0261: long start = System.currentTimeMillis();
0262: try {
0263: super .commit();
0264: } finally {
0265: if (_logs.isJDBCEnabled())
0266: _logs.logJDBC("commit", start, this );
0267: handleSQLWarning();
0268: }
0269: }
0270:
0271: public void rollback() throws SQLException {
0272: long start = System.currentTimeMillis();
0273: try {
0274: super .rollback();
0275: } finally {
0276: if (_logs.isJDBCEnabled())
0277: _logs.logJDBC("rollback", start, this );
0278: handleSQLWarning();
0279: }
0280: }
0281:
0282: public void close() throws SQLException {
0283: long start = System.currentTimeMillis();
0284: try {
0285: super .close();
0286: } finally {
0287: if (_logs.isJDBCEnabled())
0288: _logs.logJDBC("close", start, this );
0289: }
0290: }
0291:
0292: public Savepoint setSavepoint() throws SQLException {
0293: long start = System.currentTimeMillis();
0294: try {
0295: return super .setSavepoint();
0296: } finally {
0297: if (_logs.isJDBCEnabled())
0298: _logs.logJDBC("savepoint", start, this );
0299: handleSQLWarning();
0300: }
0301: }
0302:
0303: public Savepoint setSavepoint(String name) throws SQLException {
0304: long start = System.currentTimeMillis();
0305: try {
0306: return super .setSavepoint(name);
0307: } finally {
0308: if (_logs.isJDBCEnabled())
0309: _logs.logJDBC("savepoint: " + name, start, this );
0310: handleSQLWarning();
0311: }
0312: }
0313:
0314: public void rollback(Savepoint savepoint) throws SQLException {
0315: long start = System.currentTimeMillis();
0316: try {
0317: super .rollback(savepoint);
0318: } finally {
0319: if (_logs.isJDBCEnabled()) {
0320: String name = null;
0321: try {
0322: name = savepoint.getSavepointName();
0323: } catch (SQLException sqe) {
0324: name = String.valueOf(savepoint
0325: .getSavepointId());
0326: }
0327: _logs.logJDBC("rollback: " + name, start, this );
0328: }
0329: handleSQLWarning();
0330: }
0331: }
0332:
0333: public void releaseSavepoint(Savepoint savepoint)
0334: throws SQLException {
0335: long start = System.currentTimeMillis();
0336: try {
0337: super .releaseSavepoint(savepoint);
0338: } finally {
0339: if (_logs.isJDBCEnabled()) {
0340: String name = null;
0341: try {
0342: name = savepoint.getSavepointName();
0343: } catch (SQLException sqe) {
0344: name = String.valueOf(savepoint
0345: .getSavepointId());
0346: }
0347: _logs.logJDBC("release: " + name, start, this );
0348: }
0349: handleSQLWarning();
0350: }
0351: }
0352:
0353: protected Statement createStatement(int resultSetType,
0354: int resultSetConcurrency, int resultSetHoldability,
0355: boolean wrap) throws SQLException {
0356: Statement stmnt = super .createStatement(resultSetType,
0357: resultSetConcurrency, resultSetHoldability, false);
0358: handleSQLWarning();
0359: return new LoggingStatement(stmnt);
0360: }
0361:
0362: protected PreparedStatement prepareStatement(String sql,
0363: int resultSetType, int resultSetConcurrency,
0364: int resultSetHoldability, boolean wrap)
0365: throws SQLException {
0366: try {
0367: PreparedStatement stmnt = super .prepareStatement(sql,
0368: resultSetType, resultSetConcurrency,
0369: resultSetHoldability, false);
0370: handleSQLWarning();
0371: return new LoggingPreparedStatement(stmnt, sql);
0372: } catch (SQLException se) {
0373: throw wrap(se, sql);
0374: }
0375: }
0376:
0377: protected PreparedStatement prepareStatement(String sql,
0378: int autoGeneratedKeys, boolean wrap)
0379: throws SQLException {
0380: try {
0381: PreparedStatement stmnt = super .prepareStatement(sql,
0382: autoGeneratedKeys, false);
0383: handleSQLWarning();
0384: return new LoggingPreparedStatement(stmnt, sql);
0385: } catch (SQLException se) {
0386: throw wrap(se, sql);
0387: }
0388: }
0389:
0390: protected PreparedStatement prepareStatement(String sql,
0391: int[] columnIndexes, boolean wrap) throws SQLException {
0392: try {
0393: PreparedStatement stmnt = super .prepareStatement(sql,
0394: columnIndexes, false);
0395: handleSQLWarning();
0396: return new LoggingPreparedStatement(stmnt, sql);
0397: } catch (SQLException se) {
0398: throw wrap(se, sql);
0399: }
0400: }
0401:
0402: protected PreparedStatement prepareStatement(String sql,
0403: String[] columnNames, boolean wrap) throws SQLException {
0404: try {
0405: PreparedStatement stmnt = super .prepareStatement(sql,
0406: columnNames, false);
0407: handleSQLWarning();
0408: return new LoggingPreparedStatement(stmnt, sql);
0409: } catch (SQLException se) {
0410: throw wrap(se, sql);
0411: }
0412: }
0413:
0414: protected DatabaseMetaData getMetaData(boolean wrap)
0415: throws SQLException {
0416: return new LoggingDatabaseMetaData(super .getMetaData(false));
0417: }
0418:
0419: /**
0420: * Log time elapsed since given start.
0421: */
0422: private void logTime(long startTime) throws SQLException {
0423: if (_logs.isSQLEnabled())
0424: _logs.logSQL("spent", startTime, this );
0425: }
0426:
0427: /**
0428: * Log time elapsed since given start.
0429: */
0430: private void logSQL(Statement stmnt) throws SQLException {
0431: if (_logs.isSQLEnabled())
0432: _logs.logSQL("executing " + stmnt, this );
0433: }
0434:
0435: /**
0436: * Log time elapsed since given start.
0437: */
0438: private void logBatchSQL(Statement stmnt) throws SQLException {
0439: if (_logs.isSQLEnabled())
0440: _logs.logSQL("executing batch " + stmnt, this );
0441: }
0442:
0443: /**
0444: * Handle any {@link SQLWarning}s on the current {@link Connection}.
0445: *
0446: * @see #handleSQLWarning(SQLWarning)
0447: */
0448: private void handleSQLWarning() throws SQLException {
0449: if (_warningAction == WARN_IGNORE)
0450: return;
0451:
0452: try {
0453: handleSQLWarning(getWarnings());
0454: } finally {
0455: clearWarnings();
0456: }
0457: }
0458:
0459: /**
0460: * Handle any {@link SQLWarning}s on the specified {@link Statement}.
0461: *
0462: * @see #handleSQLWarning(SQLWarning)
0463: */
0464: private void handleSQLWarning(Statement stmnt)
0465: throws SQLException {
0466: if (_warningAction == WARN_IGNORE)
0467: return;
0468:
0469: try {
0470: handleSQLWarning(stmnt.getWarnings());
0471: } finally {
0472: stmnt.clearWarnings();
0473: }
0474: }
0475:
0476: /**
0477: * Handle any {@link SQLWarning}s on the specified {@link ResultSet}.
0478: *
0479: * @see #handleSQLWarning(SQLWarning)
0480: */
0481: private void handleSQLWarning(ResultSet rs) throws SQLException {
0482: if (_warningAction == WARN_IGNORE)
0483: return;
0484:
0485: try {
0486: handleSQLWarning(rs.getWarnings());
0487: } finally {
0488: rs.clearWarnings();
0489: }
0490: }
0491:
0492: /**
0493: * Handle the specified {@link SQLWarning} depending on the
0494: * setting of the {@link #setWarningAction} attribute.
0495: *
0496: * @param warning the warning to handle
0497: */
0498: private void handleSQLWarning(SQLWarning warning)
0499: throws SQLException {
0500: if (warning == null)
0501: return;
0502: if (_warningAction == WARN_IGNORE)
0503: return;
0504:
0505: Log log = _logs.getJDBCLog();
0506: for (; warning != null; warning = warning.getNextWarning()) {
0507: switch (_warningAction) {
0508: case WARN_LOG_TRACE:
0509: if (log.isTraceEnabled())
0510: log.trace(warning);
0511: break;
0512: case WARN_LOG_INFO:
0513: if (log.isInfoEnabled())
0514: log.info(warning);
0515: break;
0516: case WARN_LOG_WARN:
0517: if (log.isWarnEnabled())
0518: log.warn(warning);
0519: break;
0520: case WARN_LOG_ERROR:
0521: if (log.isErrorEnabled())
0522: log.error(warning);
0523: break;
0524: case WARN_THROW:
0525: // just throw it as if it were a SQLException
0526: throw warning;
0527: case WARN_HANDLE:
0528: if (_warningHandler != null)
0529: _warningHandler.handleWarning(warning);
0530: break;
0531: default:
0532: // ignore
0533: break;
0534: }
0535: }
0536: }
0537:
0538: /**
0539: * Metadata wrapper that logs actions.
0540: */
0541: private class LoggingDatabaseMetaData extends
0542: DelegatingDatabaseMetaData {
0543:
0544: public LoggingDatabaseMetaData(DatabaseMetaData meta) {
0545: super (meta, LoggingConnection.this );
0546: }
0547:
0548: public ResultSet getBestRowIdentifier(String catalog,
0549: String schema, String table, int scope,
0550: boolean nullable) throws SQLException {
0551: if (_logs.isJDBCEnabled())
0552: _logs.logJDBC("getBestRowIdentifier: " + catalog
0553: + ", " + schema + ", " + table,
0554: LoggingConnection.this );
0555: return super .getBestRowIdentifier(catalog, schema,
0556: table, scope, nullable);
0557: }
0558:
0559: public ResultSet getCatalogs() throws SQLException {
0560: if (_logs.isJDBCEnabled())
0561: _logs
0562: .logJDBC("getCatalogs",
0563: LoggingConnection.this );
0564: return super .getCatalogs();
0565: }
0566:
0567: public ResultSet getColumnPrivileges(String catalog,
0568: String schema, String table,
0569: String columnNamePattern) throws SQLException {
0570: if (_logs.isJDBCEnabled())
0571: _logs.logJDBC("getColumnPrivileges: " + catalog
0572: + ", " + schema + ", " + table,
0573: LoggingConnection.this );
0574: return super .getColumnPrivileges(catalog, schema,
0575: table, columnNamePattern);
0576: }
0577:
0578: public ResultSet getColumns(String catalog,
0579: String schemaPattern, String tableNamePattern,
0580: String columnNamePattern) throws SQLException {
0581: if (_logs.isJDBCEnabled())
0582: _logs.logJDBC("getColumns: " + catalog + ", "
0583: + schemaPattern + ", " + tableNamePattern
0584: + ", " + columnNamePattern,
0585: LoggingConnection.this );
0586: return super .getColumns(catalog, schemaPattern,
0587: tableNamePattern, columnNamePattern);
0588: }
0589:
0590: public ResultSet getCrossReference(String primaryCatalog,
0591: String primarySchema, String primaryTable,
0592: String foreignCatalog, String foreignSchema,
0593: String foreignTable) throws SQLException {
0594: if (_logs.isJDBCEnabled())
0595: _logs.logJDBC("getCrossReference: "
0596: + primaryCatalog + ", " + primarySchema
0597: + ", " + primaryTable + ", "
0598: + foreignCatalog + ", " + foreignSchema
0599: + ", " + foreignSchema,
0600: LoggingConnection.this );
0601: return super .getCrossReference(primaryCatalog,
0602: primarySchema, primaryTable, foreignCatalog,
0603: foreignSchema, foreignTable);
0604: }
0605:
0606: public ResultSet getExportedKeys(String catalog,
0607: String schema, String table) throws SQLException {
0608: if (_logs.isJDBCEnabled())
0609: _logs.logJDBC("getExportedKeys: " + catalog + ", "
0610: + schema + ", " + table,
0611: LoggingConnection.this );
0612: return super .getExportedKeys(catalog, schema, table);
0613: }
0614:
0615: public ResultSet getImportedKeys(String catalog,
0616: String schema, String table) throws SQLException {
0617: if (_logs.isJDBCEnabled())
0618: _logs.logJDBC("getImportedKeys: " + catalog + ", "
0619: + schema + ", " + table,
0620: LoggingConnection.this );
0621: return super .getImportedKeys(catalog, schema, table);
0622: }
0623:
0624: public ResultSet getIndexInfo(String catalog,
0625: String schema, String table, boolean unique,
0626: boolean approximate) throws SQLException {
0627: if (_logs.isJDBCEnabled())
0628: _logs.logJDBC("getIndexInfo: " + catalog + ", "
0629: + schema + ", " + table,
0630: LoggingConnection.this );
0631: return super .getIndexInfo(catalog, schema, table,
0632: unique, approximate);
0633: }
0634:
0635: public ResultSet getPrimaryKeys(String catalog,
0636: String schema, String table) throws SQLException {
0637: if (_logs.isJDBCEnabled())
0638: _logs.logJDBC("getPrimaryKeys: " + catalog + ", "
0639: + schema + ", " + table,
0640: LoggingConnection.this );
0641: return super .getPrimaryKeys(catalog, schema, table);
0642: }
0643:
0644: public ResultSet getProcedureColumns(String catalog,
0645: String schemaPattern, String procedureNamePattern,
0646: String columnNamePattern) throws SQLException {
0647: if (_logs.isJDBCEnabled())
0648: _logs
0649: .logJDBC("getProcedureColumns: " + catalog
0650: + ", " + schemaPattern + ", "
0651: + procedureNamePattern + ", "
0652: + columnNamePattern,
0653: LoggingConnection.this );
0654: return super .getProcedureColumns(catalog,
0655: schemaPattern, procedureNamePattern,
0656: columnNamePattern);
0657: }
0658:
0659: public ResultSet getProcedures(String catalog,
0660: String schemaPattern, String procedureNamePattern)
0661: throws SQLException {
0662: if (_logs.isJDBCEnabled())
0663: _logs.logJDBC("getProcedures: " + catalog + ", "
0664: + schemaPattern + ", "
0665: + procedureNamePattern,
0666: LoggingConnection.this );
0667: return super .getProcedures(catalog, schemaPattern,
0668: procedureNamePattern);
0669: }
0670:
0671: public ResultSet getSchemas() throws SQLException {
0672: if (_logs.isJDBCEnabled())
0673: _logs.logJDBC("getSchemas", LoggingConnection.this );
0674: return super .getSchemas();
0675: }
0676:
0677: public ResultSet getTablePrivileges(String catalog,
0678: String schemaPattern, String tableNamePattern)
0679: throws SQLException {
0680: if (_logs.isJDBCEnabled())
0681: _logs.logJDBC("getTablePrivileges",
0682: LoggingConnection.this );
0683: return super .getTablePrivileges(catalog, schemaPattern,
0684: tableNamePattern);
0685: }
0686:
0687: public ResultSet getTables(String catalog,
0688: String schemaPattern, String tableNamePattern,
0689: String[] types) throws SQLException {
0690: if (_logs.isJDBCEnabled())
0691: _logs.logJDBC("getTables: " + catalog + ", "
0692: + schemaPattern + ", " + tableNamePattern,
0693: LoggingConnection.this );
0694: return super .getTables(catalog, schemaPattern,
0695: tableNamePattern, types);
0696: }
0697:
0698: public ResultSet getTableTypes() throws SQLException {
0699: if (_logs.isJDBCEnabled())
0700: _logs.logJDBC("getTableTypes",
0701: LoggingConnection.this );
0702: return super .getTableTypes();
0703: }
0704:
0705: public ResultSet getTypeInfo() throws SQLException {
0706: if (_logs.isJDBCEnabled())
0707: _logs
0708: .logJDBC("getTypeInfo",
0709: LoggingConnection.this );
0710: return super .getTypeInfo();
0711: }
0712:
0713: public ResultSet getUDTs(String catalog,
0714: String schemaPattern, String typeNamePattern,
0715: int[] types) throws SQLException {
0716: if (_logs.isJDBCEnabled())
0717: _logs.logJDBC("getUDTs", LoggingConnection.this );
0718: return super .getUDTs(catalog, schemaPattern,
0719: typeNamePattern, types);
0720: }
0721:
0722: public ResultSet getVersionColumns(String catalog,
0723: String schema, String table) throws SQLException {
0724: if (_logs.isJDBCEnabled())
0725: _logs.logJDBC("getVersionColumns: " + catalog
0726: + ", " + schema + ", " + table,
0727: LoggingConnection.this );
0728: return super .getVersionColumns(catalog, schema, table);
0729: }
0730: }
0731:
0732: /**
0733: * Statement wrapper that logs SQL to the parent data source and
0734: * remembers the last piece of SQL to be executed on it.
0735: */
0736: private class LoggingStatement extends DelegatingStatement {
0737:
0738: private String _sql = null;
0739:
0740: public LoggingStatement(Statement stmnt)
0741: throws SQLException {
0742: super (stmnt, LoggingConnection.this );
0743: }
0744:
0745: public void appendInfo(StringBuffer buf) {
0746: if (_sql != null) {
0747: buf.append(" ");
0748: if (_formatter != null) {
0749: buf.append(SEP);
0750: buf.append(_formatter.prettyPrint(_sql));
0751: } else {
0752: buf.append(_sql);
0753: }
0754: }
0755: }
0756:
0757: protected ResultSet wrapResult(ResultSet rs, boolean wrap) {
0758: if (!wrap || rs == null)
0759: return super .wrapResult(rs, wrap);
0760: return new LoggingResultSet(rs, this );
0761: }
0762:
0763: public void cancel() throws SQLException {
0764: if (_logs.isJDBCEnabled())
0765: _logs.logJDBC("cancel " + this ,
0766: LoggingConnection.this );
0767: super .cancel();
0768: }
0769:
0770: protected ResultSet executeQuery(String sql, boolean wrap)
0771: throws SQLException {
0772: _sql = sql;
0773: logSQL(this );
0774: long start = System.currentTimeMillis();
0775: try {
0776: return super .executeQuery(sql, wrap);
0777: } catch (SQLException se) {
0778: throw wrap(se, LoggingStatement.this );
0779: } finally {
0780: logTime(start);
0781: handleSQLWarning(LoggingStatement.this );
0782: }
0783: }
0784:
0785: public int executeUpdate(String sql) throws SQLException {
0786: _sql = sql;
0787: logSQL(this );
0788: long start = System.currentTimeMillis();
0789: try {
0790: return super .executeUpdate(sql);
0791: } catch (SQLException se) {
0792: throw wrap(se, LoggingStatement.this );
0793: } finally {
0794: logTime(start);
0795: handleSQLWarning(LoggingStatement.this );
0796: }
0797: }
0798:
0799: public boolean execute(String sql) throws SQLException {
0800: _sql = sql;
0801: logSQL(this );
0802: long start = System.currentTimeMillis();
0803: try {
0804: return super .execute(sql);
0805: } catch (SQLException se) {
0806: throw wrap(se, LoggingStatement.this );
0807: } finally {
0808: logTime(start);
0809: handleSQLWarning(LoggingStatement.this );
0810: }
0811: }
0812: }
0813:
0814: private class LoggingPreparedStatement extends
0815: DelegatingPreparedStatement {
0816:
0817: private final String _sql;
0818: private List _params = null;
0819: private List _paramBatch = null;
0820:
0821: public LoggingPreparedStatement(PreparedStatement stmnt,
0822: String sql) throws SQLException {
0823: super (stmnt, LoggingConnection.this );
0824: _sql = sql;
0825: }
0826:
0827: protected ResultSet wrapResult(ResultSet rs, boolean wrap) {
0828: if (!wrap || rs == null)
0829: return super .wrapResult(rs, wrap);
0830: return new LoggingResultSet(rs, this );
0831: }
0832:
0833: protected ResultSet executeQuery(String sql, boolean wrap)
0834: throws SQLException {
0835: logSQL(this );
0836: long start = System.currentTimeMillis();
0837: try {
0838: return super .executeQuery(sql, wrap);
0839: } catch (SQLException se) {
0840: throw wrap(se, LoggingPreparedStatement.this );
0841: } finally {
0842: logTime(start);
0843: clearLogParameters(true);
0844: handleSQLWarning(LoggingPreparedStatement.this );
0845: }
0846: }
0847:
0848: public int executeUpdate(String sql) throws SQLException {
0849: logSQL(this );
0850: long start = System.currentTimeMillis();
0851: try {
0852: return super .executeUpdate(sql);
0853: } catch (SQLException se) {
0854: throw wrap(se, LoggingPreparedStatement.this );
0855: } finally {
0856: logTime(start);
0857: clearLogParameters(true);
0858: handleSQLWarning(LoggingPreparedStatement.this );
0859: }
0860: }
0861:
0862: public boolean execute(String sql) throws SQLException {
0863: logSQL(this );
0864: long start = System.currentTimeMillis();
0865: try {
0866: return super .execute(sql);
0867: } catch (SQLException se) {
0868: throw wrap(se, LoggingPreparedStatement.this );
0869: } finally {
0870: logTime(start);
0871: clearLogParameters(true);
0872: handleSQLWarning(LoggingPreparedStatement.this );
0873: }
0874: }
0875:
0876: protected ResultSet executeQuery(boolean wrap)
0877: throws SQLException {
0878: logSQL(this );
0879: long start = System.currentTimeMillis();
0880: try {
0881: return super .executeQuery(wrap);
0882: } catch (SQLException se) {
0883: throw wrap(se, LoggingPreparedStatement.this );
0884: } finally {
0885: logTime(start);
0886: clearLogParameters(true);
0887: handleSQLWarning(LoggingPreparedStatement.this );
0888: }
0889: }
0890:
0891: public int executeUpdate() throws SQLException {
0892: logSQL(this );
0893: long start = System.currentTimeMillis();
0894: try {
0895: return super .executeUpdate();
0896: } catch (SQLException se) {
0897: throw wrap(se, LoggingPreparedStatement.this );
0898: } finally {
0899: logTime(start);
0900: clearLogParameters(true);
0901: handleSQLWarning(LoggingPreparedStatement.this );
0902: }
0903: }
0904:
0905: public int[] executeBatch() throws SQLException {
0906: logBatchSQL(this );
0907: long start = System.currentTimeMillis();
0908: try {
0909: return super .executeBatch();
0910: } catch (SQLException se) {
0911: // if the exception is a BatchUpdateException, and
0912: // we are tracking parameters, then set the current
0913: // parameter set to be the index of the failed
0914: // statement so that the ReportingSQLException will
0915: // show the correct param
0916: if (se instanceof BatchUpdateException
0917: && _paramBatch != null
0918: && shouldTrackParameters()) {
0919: int[] count = ((BatchUpdateException) se)
0920: .getUpdateCounts();
0921: if (count != null
0922: && count.length <= _paramBatch.size()) {
0923: int index = -1;
0924: for (int i = 0; i < count.length; i++) {
0925: // -3 is Statement.STATEMENT_FAILED, but is
0926: // only available in JDK 1.4+
0927: if (count[i] == -3) {
0928: index = i;
0929: break;
0930: }
0931: }
0932:
0933: // no -3 element: it may be that the server stopped
0934: // processing, so the size of the count will be
0935: // the index
0936: if (index == -1)
0937: index = count.length + 1;
0938:
0939: // set the current params to the saved values
0940: if (index < _paramBatch.size())
0941: _params = (List) _paramBatch.get(index);
0942: }
0943: }
0944: throw wrap(se, LoggingPreparedStatement.this );
0945: } finally {
0946: logTime(start);
0947: clearLogParameters(true);
0948: handleSQLWarning(LoggingPreparedStatement.this );
0949: }
0950: }
0951:
0952: public boolean execute() throws SQLException {
0953: logSQL(this );
0954: long start = System.currentTimeMillis();
0955: try {
0956: return super .execute();
0957: } catch (SQLException se) {
0958: throw wrap(se, LoggingPreparedStatement.this );
0959: } finally {
0960: logTime(start);
0961: clearLogParameters(true);
0962: handleSQLWarning(LoggingPreparedStatement.this );
0963: }
0964: }
0965:
0966: public void cancel() throws SQLException {
0967: if (_logs.isJDBCEnabled())
0968: _logs.logJDBC("cancel " + this + ": " + _sql,
0969: LoggingConnection.this );
0970:
0971: super .cancel();
0972: }
0973:
0974: public void setNull(int i1, int i2) throws SQLException {
0975: setLogParameter(i1, "null", null);
0976: super .setNull(i1, i2);
0977: }
0978:
0979: public void setBoolean(int i, boolean b)
0980: throws SQLException {
0981: setLogParameter(i, b);
0982: super .setBoolean(i, b);
0983: }
0984:
0985: public void setByte(int i, byte b) throws SQLException {
0986: setLogParameter(i, b);
0987: super .setByte(i, b);
0988: }
0989:
0990: public void setShort(int i, short s) throws SQLException {
0991: setLogParameter(i, s);
0992: super .setShort(i, s);
0993: }
0994:
0995: public void setInt(int i1, int i2) throws SQLException {
0996: setLogParameter(i1, i2);
0997: super .setInt(i1, i2);
0998: }
0999:
1000: public void setLong(int i, long l) throws SQLException {
1001: setLogParameter(i, l);
1002: super .setLong(i, l);
1003: }
1004:
1005: public void setFloat(int i, float f) throws SQLException {
1006: setLogParameter(i, f);
1007: super .setFloat(i, f);
1008: }
1009:
1010: public void setDouble(int i, double d) throws SQLException {
1011: setLogParameter(i, d);
1012: super .setDouble(i, d);
1013: }
1014:
1015: public void setBigDecimal(int i, BigDecimal bd)
1016: throws SQLException {
1017: setLogParameter(i, "BigDecimal", bd);
1018: super .setBigDecimal(i, bd);
1019: }
1020:
1021: public void setString(int i, String s) throws SQLException {
1022: setLogParameter(i, "String", s);
1023: super .setString(i, s);
1024: }
1025:
1026: public void setBytes(int i, byte[] b) throws SQLException {
1027: setLogParameter(i, "byte[]", b);
1028: super .setBytes(i, b);
1029: }
1030:
1031: public void setDate(int i, Date d) throws SQLException {
1032: setLogParameter(i, "Date", d);
1033: super .setDate(i, d);
1034: }
1035:
1036: public void setTime(int i, Time t) throws SQLException {
1037: setLogParameter(i, "Time", t);
1038: super .setTime(i, t);
1039: }
1040:
1041: public void setTimestamp(int i, Timestamp t)
1042: throws SQLException {
1043: setLogParameter(i, "Timestamp", t);
1044: super .setTimestamp(i, t);
1045: }
1046:
1047: public void setAsciiStream(int i1, InputStream is, int i2)
1048: throws SQLException {
1049: setLogParameter(i1, "InputStream", is);
1050: super .setAsciiStream(i1, is, i2);
1051: }
1052:
1053: public void setUnicodeStream(int i1, InputStream is, int i2)
1054: throws SQLException {
1055: setLogParameter(i1, "InputStream", is);
1056: super .setUnicodeStream(i2, is, i2);
1057: }
1058:
1059: public void setBinaryStream(int i1, InputStream is, int i2)
1060: throws SQLException {
1061: setLogParameter(i1, "InputStream", is);
1062: super .setBinaryStream(i1, is, i2);
1063: }
1064:
1065: public void clearParameters() throws SQLException {
1066: clearLogParameters(false);
1067: super .clearParameters();
1068: }
1069:
1070: public void setObject(int i1, Object o, int i2, int i3)
1071: throws SQLException {
1072: setLogParameter(i1, "Object", o);
1073: super .setObject(i1, o, i2, i3);
1074: }
1075:
1076: public void setObject(int i1, Object o, int i2)
1077: throws SQLException {
1078: setLogParameter(i1, "Object", o);
1079: super .setObject(i1, o, i2);
1080: }
1081:
1082: public void setObject(int i, Object o) throws SQLException {
1083: setLogParameter(i, "Object", o);
1084: super .setObject(i, o);
1085: }
1086:
1087: public void addBatch() throws SQLException {
1088: if (_logs.isSQLEnabled())
1089: _logs.logSQL("batching " + this ,
1090: LoggingConnection.this );
1091: long start = System.currentTimeMillis();
1092: try {
1093: super .addBatch();
1094: if (shouldTrackParameters()) {
1095: // make sure our list is initialized
1096: if (_paramBatch == null)
1097: _paramBatch = new ArrayList();
1098: // copy parameters since they will be re-used
1099: if (_params != null)
1100: _paramBatch.add(new ArrayList(_params));
1101: else
1102: _paramBatch.add(null);
1103: }
1104: } finally {
1105: logTime(start);
1106: }
1107: }
1108:
1109: public void setCharacterStream(int i1, Reader r, int i2)
1110: throws SQLException {
1111: setLogParameter(i1, "Reader", r);
1112: super .setCharacterStream(i1, r, i2);
1113: }
1114:
1115: public void setRef(int i, Ref r) throws SQLException {
1116: setLogParameter(i, "Ref", r);
1117: super .setRef(i, r);
1118: }
1119:
1120: public void setBlob(int i, Blob b) throws SQLException {
1121: setLogParameter(i, "Blob", b);
1122: super .setBlob(i, b);
1123: }
1124:
1125: public void setClob(int i, Clob c) throws SQLException {
1126: setLogParameter(i, "Clob", c);
1127: super .setClob(i, c);
1128: }
1129:
1130: public void setArray(int i, Array a) throws SQLException {
1131: setLogParameter(i, "Array", a);
1132: super .setArray(i, a);
1133: }
1134:
1135: public ResultSetMetaData getMetaData() throws SQLException {
1136: return super .getMetaData();
1137: }
1138:
1139: public void setDate(int i, Date d, Calendar c)
1140: throws SQLException {
1141: setLogParameter(i, "Date", d);
1142: super .setDate(i, d, c);
1143: }
1144:
1145: public void setTime(int i, Time t, Calendar c)
1146: throws SQLException {
1147: setLogParameter(i, "Time", t);
1148: super .setTime(i, t, c);
1149: }
1150:
1151: public void setTimestamp(int i, Timestamp t, Calendar c)
1152: throws SQLException {
1153: setLogParameter(i, "Timestamp", t);
1154: super .setTimestamp(i, t, c);
1155: }
1156:
1157: public void setNull(int i1, int i2, String s)
1158: throws SQLException {
1159: setLogParameter(i1, "null", null);
1160: super .setNull(i1, i2, s);
1161: }
1162:
1163: protected void appendInfo(StringBuffer buf) {
1164: buf.append(" ");
1165: if (_formatter != null) {
1166: buf.append(SEP);
1167: buf.append(_formatter.prettyPrint(_sql));
1168: buf.append(SEP);
1169: } else {
1170: buf.append(_sql);
1171: }
1172:
1173: StringBuffer paramBuf = null;
1174: if (_params != null && !_params.isEmpty()) {
1175: paramBuf = new StringBuffer();
1176: for (Iterator itr = _params.iterator(); itr
1177: .hasNext();) {
1178: paramBuf.append(itr.next());
1179: if (itr.hasNext())
1180: paramBuf.append(", ");
1181: }
1182: }
1183:
1184: if (paramBuf != null) {
1185: if (!_prettyPrint)
1186: buf.append(" ");
1187: buf.append("[params=").append(paramBuf.toString())
1188: .append("]");
1189: }
1190: super .appendInfo(buf);
1191: }
1192:
1193: private void clearLogParameters(boolean batch) {
1194: if (_params != null)
1195: _params.clear();
1196: if (batch && _paramBatch != null)
1197: _paramBatch.clear();
1198: }
1199:
1200: private boolean shouldTrackParameters() {
1201: return _trackParameters || _logs.isSQLEnabled();
1202: }
1203:
1204: private void setLogParameter(int index, boolean val) {
1205: if (shouldTrackParameters())
1206: setLogParameter(index, "(boolean) " + val);
1207: }
1208:
1209: private void setLogParameter(int index, byte val) {
1210: if (shouldTrackParameters())
1211: setLogParameter(index, "(byte) " + val);
1212: }
1213:
1214: private void setLogParameter(int index, double val) {
1215: if (shouldTrackParameters())
1216: setLogParameter(index, "(double) " + val);
1217: }
1218:
1219: private void setLogParameter(int index, float val) {
1220: if (shouldTrackParameters())
1221: setLogParameter(index, "(float) " + val);
1222: }
1223:
1224: private void setLogParameter(int index, int val) {
1225: if (shouldTrackParameters())
1226: setLogParameter(index, "(int) " + val);
1227: }
1228:
1229: private void setLogParameter(int index, long val) {
1230: if (shouldTrackParameters())
1231: setLogParameter(index, "(long) " + val);
1232: }
1233:
1234: private void setLogParameter(int index, short val) {
1235: if (shouldTrackParameters())
1236: setLogParameter(index, "(short) " + val);
1237: }
1238:
1239: private void setLogParameter(int index, String type,
1240: Object val) {
1241: if (shouldTrackParameters())
1242: setLogParameter(index, "(" + type + ") " + val);
1243: }
1244:
1245: private void setLogParameter(int index, String val) {
1246: if (_params == null)
1247: _params = new ArrayList();
1248: while (_params.size() < index)
1249: _params.add(null);
1250: if (val.length() > 80)
1251: val = val.substring(0, 77) + "...";
1252: _params.set(index - 1, val);
1253: }
1254: }
1255:
1256: /**
1257: * Warning-handling result set.
1258: */
1259: private class LoggingResultSet extends DelegatingResultSet {
1260:
1261: public LoggingResultSet(ResultSet rs, Statement stmnt) {
1262: super (rs, stmnt);
1263: }
1264:
1265: public boolean next() throws SQLException {
1266: try {
1267: return super .next();
1268: } finally {
1269: handleSQLWarning(LoggingResultSet.this );
1270: }
1271: }
1272:
1273: public void close() throws SQLException {
1274: try {
1275: super .close();
1276: } finally {
1277: handleSQLWarning(LoggingResultSet.this );
1278: }
1279: }
1280:
1281: public void beforeFirst() throws SQLException {
1282: try {
1283: super .beforeFirst();
1284: } finally {
1285: handleSQLWarning(LoggingResultSet.this );
1286: }
1287: }
1288:
1289: public void afterLast() throws SQLException {
1290: try {
1291: super .afterLast();
1292: } finally {
1293: handleSQLWarning(LoggingResultSet.this );
1294: }
1295: }
1296:
1297: public boolean first() throws SQLException {
1298: try {
1299: return super .first();
1300: } finally {
1301: handleSQLWarning(LoggingResultSet.this );
1302: }
1303: }
1304:
1305: public boolean last() throws SQLException {
1306: try {
1307: return super .last();
1308: } finally {
1309: handleSQLWarning(LoggingResultSet.this );
1310: }
1311: }
1312:
1313: public boolean absolute(int a) throws SQLException {
1314: try {
1315: return super .absolute(a);
1316: } finally {
1317: handleSQLWarning(LoggingResultSet.this );
1318: }
1319: }
1320:
1321: public boolean relative(int a) throws SQLException {
1322: try {
1323: return super .relative(a);
1324: } finally {
1325: handleSQLWarning(LoggingResultSet.this );
1326: }
1327: }
1328:
1329: public boolean previous() throws SQLException {
1330: try {
1331: return super.previous();
1332: } finally {
1333: handleSQLWarning(LoggingResultSet.this);
1334: }
1335: }
1336: }
1337: }
1338: }
|