View Javadoc
1   /*
2    * Copyright 2004-2025 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.ibatis.common.jdbc.logging;
17  
18  import com.ibatis.common.beans.ClassInfo;
19  import com.ibatis.common.logging.Log;
20  import com.ibatis.common.logging.LogFactory;
21  
22  import java.lang.reflect.InvocationHandler;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Proxy;
25  import java.sql.CallableStatement;
26  import java.sql.PreparedStatement;
27  import java.sql.ResultSet;
28  
29  /**
30   * PreparedStatement proxy to add logging.
31   */
32  public class PreparedStatementLogProxy extends BaseLogProxy implements InvocationHandler {
33  
34    /** The Constant log. */
35    private static final Log log = LogFactory.getLog(PreparedStatement.class);
36  
37    /** The statement. */
38    private PreparedStatement statement;
39  
40    /** The sql. */
41    private String sql;
42  
43    /**
44     * Instantiates a new prepared statement log proxy.
45     *
46     * @param stmt
47     *          the stmt
48     * @param sql
49     *          the sql
50     */
51    private PreparedStatementLogProxy(PreparedStatement stmt, String sql) {
52      this.statement = stmt;
53      this.sql = sql;
54    }
55  
56    @Override
57    public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
58      try {
59        if (EXECUTE_METHODS.contains(method.getName())) {
60          if (log.isDebugEnabled()) {
61            log.debug("{pstm-" + id + "} Executing Statement: " + removeBreakingWhitespace(sql));
62            log.debug("{pstm-" + id + "} Parameters: " + getValueString());
63            log.debug("{pstm-" + id + "} Types: " + getTypeString());
64          }
65          clearColumnInfo();
66          if ("executeQuery".equals(method.getName())) {
67            ResultSet rs = (ResultSet) method.invoke(statement, params);
68            if (rs != null) {
69              return ResultSetLogProxy.newInstance(rs);
70            }
71            return null;
72          }
73          return method.invoke(statement, params);
74        }
75        if (SET_METHODS.contains(method.getName())) {
76          if ("setNull".equals(method.getName())) {
77            setColumn(params[0], null);
78          } else {
79            setColumn(params[0], params[1]);
80          }
81          return method.invoke(statement, params);
82        }
83        if ("getResultSet".equals(method.getName())) {
84          ResultSet rs = (ResultSet) method.invoke(statement, params);
85          if (rs != null) {
86            return ResultSetLogProxy.newInstance(rs);
87          }
88          return null;
89        }
90        if ("equals".equals(method.getName())) {
91          Object ps = params[0];
92          if (ps instanceof Proxy) {
93            return Boolean.valueOf(proxy == ps);
94          }
95          return Boolean.valueOf(false);
96        }
97        if ("hashCode".equals(method.getName())) {
98          return Integer.valueOf(proxy.hashCode());
99        }
100       return method.invoke(statement, params);
101     } catch (Throwable t) {
102       throw ClassInfo.unwrapThrowable(t);
103     }
104   }
105 
106   /**
107    * Creates a logging version of a PreparedStatement.
108    *
109    * @param stmt
110    *          - the statement
111    * @param sql
112    *          - the sql statement
113    *
114    * @return - the proxy
115    */
116   public static PreparedStatement newInstance(PreparedStatement stmt, String sql) {
117     InvocationHandler handler = new PreparedStatementLogProxy(stmt, sql);
118     ClassLoader cl = PreparedStatement.class.getClassLoader();
119     return (PreparedStatement) Proxy.newProxyInstance(cl,
120         new Class[] { PreparedStatement.class, CallableStatement.class }, handler);
121   }
122 
123   /**
124    * Return the wrapped prepared statement.
125    *
126    * @return the PreparedStatement
127    */
128   public PreparedStatement getPreparedStatement() {
129     return statement;
130   }
131 
132 }