[#1157] Add extended SQL / JDBC tracing capabilities in addition to logging - added Javadoc

This commit is contained in:
Lukas Eder 2012-02-22 20:38:54 +00:00
parent 61c893a0ea
commit dc0e2943de
13 changed files with 859 additions and 86 deletions

View File

@ -38,6 +38,8 @@ package org.jooq;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.jooq.conf.StatementType;
/**
* A context object for {@link Query} execution passed to registered
* {@link ExecuteListener}'s.
@ -45,43 +47,109 @@ import java.sql.ResultSet;
* Expect most of this context's objects to be <code>nullable</code>!
*
* @author Lukas Eder
* @see ExecuteListener
*/
public interface ExecuteContext extends Configuration {
/**
* The configuration wrapped by this context
*/
Configuration configuration();
// TODO Routines?
// Nullable!
/**
* The jOOQ {@link Query} that is being executed or <code>null</code> if the
* query is unknown or if there was no jOOQ <code>Query</code>
*
* @see #routine()
*/
Query query();
// Nullable!
void sql(String sql);
/**
* The jOOQ {@link Routine} that is being executed or <code>null</code> if
* the query is unknown or if there was no jOOQ <code>Routine</code>
*
* @see #routine()
*/
Routine<?> routine();
/**
* The SQL that is being executed or <code>null</code> if the SQL statement
* is unknown or if there was no SQL statement
*/
String sql();
/**
* Override the context's {@link PreparedStatement}
* Override the SQL statement that is being executed. This may have no
* effect, if called at the wrong moment.
*
* @see ExecuteListener#renderEnd(ExecuteContext)
* @see ExecuteListener#prepareStart(ExecuteContext)
*/
void sql(String sql);
/**
* The {@link PreparedStatement} that is being executed or <code>null</code>
* if the statement is unknown or if there was no statement.
* <p>
* Use this to wrap the <code>PreparedStatement</code> executed by jOOQ with
* your custom wrapper statement, logging bind variables and query
* execution. Beware
* This can be any of the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
*/
PreparedStatement statement();
/**
* Override the {@link PreparedStatement} that is being executed. This may
* have no effect, if called at the wrong moment.
*
* @see ExecuteListener#prepareEnd(ExecuteContext)
* @see ExecuteListener#bindStart(ExecuteContext)
*/
void statement(PreparedStatement statement);
PreparedStatement statement();
// Nullable!
void resultSet(ResultSet resultSet);
/**
* The {@link ResultSet} that is being fetched or <code>null</code> if the
* result set is unknown or if no result set is being fetched.
*/
ResultSet resultSet();
// Nullable
void record(Record record);
/**
* Override the {@link ResultSet} that is being fetched. This may have no
* effect, if called at the wrong moment.
*
* @see ExecuteListener#executeEnd(ExecuteContext)
* @see ExecuteListener#fetchStart(ExecuteContext)
*/
void resultSet(ResultSet resultSet);
/**
* The last record that was fetched from the result set, or
* <code>null</code> if no record has been fetched.
*/
Record record();
void result(Result<?> result);
/**
* Calling this has no effect. It is being used by jOOQ internally.
*/
void record(Record record);
/**
* The last result that was fetched from the result set, or
* <code>null</code> if no result has been fetched.
*/
Result<?> result();
/**
* Calling this has no effect. It is being used by jOOQ internally.
*/
void result(Result<?> result);
}

View File

@ -40,62 +40,735 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.jooq.conf.Settings;
import org.jooq.conf.StatementType;
import org.jooq.impl.DefaultExecuteListener;
import org.jooq.impl.Factory;
import org.jooq.tools.LoggerListener;
import org.jooq.tools.StopWatchListener;
/**
* An event listener for {@link Query} render, prepare, bind, execute, fetch
* steps.
* An event listener for {@link Query}, {@link Routine}, or {@link ResultSet}
* render, prepare, bind, execute, fetch steps.
* <p>
* <code>EventListener</code> is a base type for loggers, debuggers, profilers,
* data collectors that can be hooked into a jOOQ {@link Factory} using the
* {@link Settings#getEventListeners()} property, passing <code>Settings</code>
* to {@link Factory#Factory(java.sql.Connection, SQLDialect, Settings)}
* <code>ExecuteListener</code> is a base type for loggers, debuggers,
* profilers, data collectors that can be hooked into a jOOQ {@link Factory}
* using the {@link Settings#getExecuteListeners()} property, passing
* <code>Settings</code> to
* {@link Factory#Factory(java.sql.Connection, SQLDialect, Settings)}. Advanced
* <code>ExecuteListeners</code> can also provide custom implementations of
* {@link Connection}, {@link PreparedStatement} and {@link ResultSet} to jOOQ
* in apropriate methods. For convenience, consider extending
* {@link DefaultExecuteListener} instead of implementing this interface. This
* will prevent compilation errors in future versions of jOOQ, when this
* interface might get new methods.
* <p>
* Advanced <code>EventListeners</code> can also provide custom implementations
* of {@link Connection}, {@link PreparedStatement} and {@link ResultSet} to
* jOOQ in apropriate methods.
* The following table explains how every type of statement / operation invokes
* callback methods in the correct order for all registered
* <code>ExecuteListeners</code>. Find a legend below the table for the various
* use cases.
* <table border="1">
* <tr>
* <th>Callback method</th>
* <th>Use case [1]</th>
* <th>Use case [2]</th>
* <th>Use case [3]</th>
* <th>Use case [4]</th>
* </tr>
* <tr>
* <td> {@link #start(ExecuteContext)}</code></td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #renderStart(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #renderEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #prepareStart(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #prepareEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #bindStart(ExecuteContext)}</td>
* <td>Yes</td>
* <td>No</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #bindEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>No</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #executeStart(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #executeEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* <td>Yes</td>
* </tr>
* <tr>
* <td> {@link #fetchStart(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* <tr>
* <td> {@link #resultStart(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* <tr>
* <td> {@link #recordStart(ExecuteContext)}<br/>
* </td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* <tr>
* <td> {@link #recordEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* <tr>
* <td> {@link #resultEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* <tr>
* <td> {@link #fetchEnd(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* <tr>
* <td> {@link #end(ExecuteContext)}</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>Yes</td>
* <td>No</td>
* </tr>
* </table>
* <br/>
* <h3>Legend:</h3>
* <ol>
* <li>Used with {@link ResultQuery} of statement type
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>Used with {@link ResultQuery} of statement type
* {@link StatementType#STATIC_STATEMENT}</li>
* <li>Used with {@link Factory#fetch(ResultSet)} or with
* {@link InsertResultStep#fetch()}</li>
* <li>Used with a {@link Routine} standalone call</li>
* </ol>
* <p>
* If nothing is specified, the default is to use {@link LoggerListener} and
* {@link StopWatchListener} as the only event listeners.
* <p>
* For convenience, consider extending {@link DefaultExecuteListener} instead of
* implementing this interface. This will prevent compilation errors in future
* versions of jOOQ, when this interface might get new methods.
*
* @author Lukas Eder
*/
public interface ExecuteListener {
void init(ExecuteContext ctx);
/**
* Called to initialise an <code>ExecuteListener</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* </ul>
*/
void start(ExecuteContext ctx);
/**
* Called before rendering SQL from a <code>QueryPart</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* </ul>
*/
void renderStart(ExecuteContext ctx);
/**
* Called after rendering SQL from a <code>QueryPart</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* </ul>
* <p>
* Overridable attributes in <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#sql(String)}: The rendered <code>SQL</code>
* statement that is about to be executed. You can modify this statement
* freely.</li>
* </ul>
*/
void renderEnd(ExecuteContext ctx);
/**
* Called before preparing / creating the SQL statement
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* </ul>
* <p>
* Overridable attributes in <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#sql(String)}: The rendered <code>SQL</code>
* statement that is about to be executed. You can modify this statement
* freely.</li>
* </ul>
*/
void prepareStart(ExecuteContext ctx);
/**
* Called after preparing / creating the SQL statement
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* </ul>
* <p>
* Overridable attributes in <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#statement(PreparedStatement)}: The
* <code>Statement</code>, <code>PreparedStatement</code>, or
* <code>CallableStatement</code> that is about to be executed. You can
* modify this statement freely, or wrap {@link ExecuteContext#statement()}
* with your enriched statement wrapper</li>
* </ul>
*/
void prepareEnd(ExecuteContext ctx);
/**
* Called before binding variables to the <code>PreparedStatement</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* </ul>
* <p>
* Overridable attributes in <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#statement(PreparedStatement)}: The
* <code>PreparedStatement</code>, or <code>CallableStatement</code> that is
* about to be executed. You can modify this statement freely, or wrap
* {@link ExecuteContext#statement()} with your enriched statement wrapper</li>
* </ul>
* <p>
* Note that this method is not called when executing queries of type
* {@link StatementType#STATIC_STATEMENT}
*/
void bindStart(ExecuteContext ctx);
/**
* Called after binding variables to the <code>PreparedStatement</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* </ul>
* <p>
* Note that this method is not called when executing queries of type
* {@link StatementType#STATIC_STATEMENT}
*/
void bindEnd(ExecuteContext ctx);
/**
* Called before executing a statement
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* </ul>
*/
void executeStart(ExecuteContext ctx);
/**
* Called after executing a statement
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* is about to be fetched or <code>null</code>, if the <code>Query</code>
* returns no result set, or if a <code>Routine</code> is being executed.</li>
* </ul>
* <p>
* Overridable attributes in <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#resultSet(ResultSet)}: The
* <code>ResultSet</code> that is about to be fetched. You can modify this
* result set freely, or wrap {@link ExecuteContext#resultSet()} with your
* enriched result set wrapper</li>
* </ul>
*/
void executeEnd(ExecuteContext ctx);
void recordStart(ExecuteContext ctx);
void recordEnd(ExecuteContext ctx);
void resultStart(ExecuteContext ctx);
void resultEnd(ExecuteContext ctx);
/**
* Called before fetching data from a <code>ResultSet</code>.
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* is about to be fetched.</li>
* </ul>
* <p>
* Overridable attributes in <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#resultSet(ResultSet)}: The
* <code>ResultSet</code> that is about to be fetched. You can modify this
* result set freely, or wrap {@link ExecuteContext#resultSet()} with your
* enriched result set wrapper</li>
* </ul>
* <p>
* In case of multiple <code>ResultSets</code> with
* {@link ResultQuery#fetchMany()}, this is called several times, once per
* <code>ResultSet</code>
* <p>
* Note that this method is not called when executing queries that do not
* return a result, or when executing routines.
*/
void fetchStart(ExecuteContext ctx);
/**
* Called before fetching a set of records from a <code>ResultSet</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* is about to be fetched.</li>
* </ul>
* <p>
* Note that this method is not called when executing queries that do not
* return a result, or when executing routines. This is also not called when
* fetching single records, with {@link Cursor#fetchOne()} for instance.
*/
void resultStart(ExecuteContext ctx);
/**
* Called before fetching a record from a <code>ResultSet</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* is about to be fetched.</li>
* </ul>
* <p>
* Note that this method is not called when executing queries that do not
* return a result, or when executing routines.
*/
void recordStart(ExecuteContext ctx);
/**
* Called after fetching a record from a <code>ResultSet</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* is about to be fetched.</li>
* <li> {@link ExecuteContext#record()}: The last <code>Record</code> that
* was fetched.</li>
* </ul>
* <p>
* Note that this method is not called when executing queries that do not
* return a result, or when executing routines.
*/
void recordEnd(ExecuteContext ctx);
/**
* Called after fetching a set of records from a <code>ResultSet</code>
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* </li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* is about to be fetched.</li>
* <li> {@link ExecuteContext#record()}: The last <code>Record</code> that
* was fetched.</li>
* <li> {@link ExecuteContext#result()}: The set of records that were
* fetched.</li>
* </ul>
* <p>
* Note that this method is not called when executing queries that do not
* return a result, or when executing routines. This is also not called when
* fetching single records, with {@link Cursor#fetchOne()} for instance.
*/
void resultEnd(ExecuteContext ctx);
/**
* Called after fetching data from a <code>ResultSet</code>.
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* Note that the <code>Statement</code> is already closed!</li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* was fetched. Note that the <code>ResultSet</code> is already closed!</li>
* <li> {@link ExecuteContext#record()}: The last <code>Record</code> that
* was fetched.</li>
* <li> {@link ExecuteContext#result()}: The last set of records that were
* fetched.</li>
* </ul>
* <p>
* In case of multiple <code>ResultSets</code> with
* {@link ResultQuery#fetchMany()}, this is called several times, once per
* <code>ResultSet</code>
* <p>
* Note that this method is not called when executing queries that do not
* return a result, or when executing routines.
*/
void fetchEnd(ExecuteContext ctx);
/**
* Called at the end of the execution lifecycle..
* <p>
* Available attributes from <code>ExecuteContext</code>:
* <ul>
* <li> {@link ExecuteContext#configuration()}: The execution configuration</li>
* <li> {@link ExecuteContext#query()}: The <code>Query</code> object, if a
* jOOQ query is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#routine()}: The <code>Routine</code> object, if
* a jOOQ routine is being executed or <code>null</code> otherwise</li>
* <li> {@link ExecuteContext#sql()}: The rendered <code>SQL</code> statement
* that is about to be executed, or <code>null</code> if the
* <code>SQL</code> statement is unknown..</li>
* <li> {@link ExecuteContext#statement()}: The
* <code>PreparedStatement</code> that is about to be executed, or
* <code>null</code> if no statement is known to jOOQ. This can be any of
* the following: <br/>
* <br/>
* <ul>
* <li>A <code>java.sql.PreparedStatement</code> from your JDBC driver when
* a jOOQ <code>Query</code> is being executed as
* {@link StatementType#PREPARED_STATEMENT}</li>
* <li>A <code>java.sql.Statement</code> from your JDBC driver wrapped in a
* <code>java.sql.PreparedStatement</code> when your jOOQ <code>Query</code>
* is being executed as {@link StatementType#STATIC_STATEMENT}</li>
* <li>A <code>java.sql.CallableStatement</code> when you are executing a
* jOOQ <code>Routine</code></li>
* </ul>
* Note that the <code>Statement</code> is already closed!</li>
* <li> {@link ExecuteContext#resultSet()}: The <code>ResultSet</code> that
* was fetched or <code>null</code>, if no result set was fetched. Note that
* if any <code>ResultSet</code> is already closed!</li>
* <li> {@link ExecuteContext#record()}: The last <code>Record</code> that
* was fetched or null if no records were fetched.</li>
* <li> {@link ExecuteContext#result()}: The last set of records that were
* fetched or null if no records were fetched.</li>
* </ul>
*/
void end(ExecuteContext ctx);
}

View File

@ -117,12 +117,12 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query {
throw new DetachedException("Cannot execute query. No Connection configured");
}
ExecuteListener listener = new ExecuteListeners(configuration);
ExecuteContext ctx = new DefaultExecuteContext(configuration, this);
// Ensure that all depending Attachables are attached
attach(configuration);
ExecuteContext ctx = new DefaultExecuteContext(configuration, this);
ExecuteListener listener = new ExecuteListeners(ctx);
int result = 0;
try {
listener.renderStart(ctx);
@ -148,7 +148,7 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query {
}
finally {
if (!keepStatementOpen()) {
Util.safeClose(ctx);
Util.safeClose(listener, ctx);
}
}
}

View File

@ -148,7 +148,6 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
// Fetch a single result set
if (!many) {
listener.fetchStart(ctx);
FieldList fields = new FieldList(getFields(ctx.resultSet().getMetaData()));
cursor = new CursorImpl<R>(ctx, listener, fields, getRecordType());
@ -163,7 +162,6 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
results = new ArrayList<Result<Record>>();
for (;;) {
listener.fetchStart(ctx);
FieldProvider fields = new MetaDataFieldProvider(ctx, ctx.resultSet().getMetaData());
Cursor<Record> c = new CursorImpl<Record>(ctx, listener, fields);
results.add(c.fetch());

View File

@ -242,8 +242,8 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
private final int executeCallableStatement() {
Configuration configuration = attachable.getConfiguration();
ExecuteListener listener = new ExecuteListeners(configuration);
ExecuteContext ctx = new DefaultExecuteContext(configuration, null);
ExecuteContext ctx = new DefaultExecuteContext(configuration, this);
ExecuteListener listener = new ExecuteListeners(ctx);
try {
Connection connection = configuration.getConnection();
@ -283,7 +283,7 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
throw translate("AbstractRoutine.executeCallableStatement", ctx.sql(), e);
}
finally {
Util.safeClose(ctx);
Util.safeClose(listener, ctx);
}
}

View File

@ -125,6 +125,7 @@ class CursorImpl<R extends Record> implements Cursor<R> {
public final Iterator<R> iterator() {
if (iterator == null) {
iterator = new CursorIterator();
listener.fetchStart(ctx);
}
return iterator;
@ -236,9 +237,9 @@ class CursorImpl<R extends Record> implements Cursor<R> {
@Override
public final void close() throws SQLException {
listener.fetchEnd(ctx);
ctx.resultSet().close();
ctx.statement().close();
listener.fetchEnd(ctx);
}
@Override

View File

@ -43,6 +43,7 @@ import org.jooq.ExecuteContext;
import org.jooq.Query;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.Routine;
/**
* A default iplementation for the {@link ExecuteContext}
@ -58,6 +59,7 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
// Persistent attributes
private final Query query;
private final Routine<?> routine;
private String sql;
// Transient attributes
@ -67,13 +69,22 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
private transient Result<?> result;
DefaultExecuteContext(Configuration configuration) {
this(configuration, null);
this(configuration, null, null);
}
DefaultExecuteContext(Configuration configuration, Query query) {
this(configuration, query, null);
}
DefaultExecuteContext(Configuration configuration, Routine<?> routine) {
this(configuration, null, routine);
}
private DefaultExecuteContext(Configuration configuration, Query query, Routine<?> routine) {
super(configuration);
this.query = query;
this.routine = routine;
}
@Override
@ -81,6 +92,11 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
return query;
}
@Override
public final Routine routine() {
return routine;
}
@Override
public final void sql(String s) {
this.sql = s;

View File

@ -49,7 +49,7 @@ import org.jooq.ExecuteListener;
public class DefaultExecuteListener implements ExecuteListener {
@Override
public void init(ExecuteContext ctx) {}
public void start(ExecuteContext ctx) {}
@Override
public void renderStart(ExecuteContext ctx) {}
@ -75,22 +75,25 @@ public class DefaultExecuteListener implements ExecuteListener {
@Override
public void executeEnd(ExecuteContext ctx) {}
@Override
public void fetchStart(ExecuteContext ctx) {}
@Override
public void resultStart(ExecuteContext ctx) {}
@Override
public void recordStart(ExecuteContext ctx) {}
@Override
public void recordEnd(ExecuteContext ctx) {}
@Override
public void resultStart(ExecuteContext ctx) {}
@Override
public void resultEnd(ExecuteContext ctx) {}
@Override
public void fetchStart(ExecuteContext ctx) {}
@Override
public void fetchEnd(ExecuteContext ctx) {}
@Override
public void end(ExecuteContext ctx) {}
}

View File

@ -37,7 +37,6 @@ package org.jooq.impl;
import java.util.List;
import org.jooq.Configuration;
import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.conf.Settings;
@ -52,13 +51,17 @@ class ExecuteListeners implements ExecuteListener {
private final List<ExecuteListener> listeners;
ExecuteListeners(Configuration configuration) {
listeners = Util.getListeners(configuration);
ExecuteListeners(ExecuteContext ctx) {
listeners = Util.getListeners(ctx);
start(ctx);
}
@Override
public final void init(ExecuteContext ctx) {
throw new UnsupportedOperationException();
public final void start(ExecuteContext ctx) {
for (ExecuteListener listener : listeners) {
listener.start(ctx);
}
}
@Override
@ -125,9 +128,9 @@ class ExecuteListeners implements ExecuteListener {
}
@Override
public final void fetchEnd(ExecuteContext ctx) {
public final void resultStart(ExecuteContext ctx) {
for (ExecuteListener listener : listeners) {
listener.fetchEnd(ctx);
listener.resultStart(ctx);
}
}
@ -146,16 +149,23 @@ class ExecuteListeners implements ExecuteListener {
}
@Override
public void resultStart(ExecuteContext ctx) {
for (ExecuteListener listener : listeners) {
listener.resultStart(ctx);
}
}
@Override
public void resultEnd(ExecuteContext ctx) {
public final void resultEnd(ExecuteContext ctx) {
for (ExecuteListener listener : listeners) {
listener.resultEnd(ctx);
}
}
@Override
public final void fetchEnd(ExecuteContext ctx) {
for (ExecuteListener listener : listeners) {
listener.fetchEnd(ctx);
}
}
@Override
public final void end(ExecuteContext ctx) {
for (ExecuteListener listener : listeners) {
listener.end(ctx);
}
}
}

View File

@ -966,14 +966,13 @@ public class Factory implements FactoryOperations {
*/
@Override
public final Result<Record> fetch(ResultSet rs) {
ExecuteListener listener = new ExecuteListeners(this);
ExecuteContext ctx = new DefaultExecuteContext(this, null);
ExecuteContext ctx = new DefaultExecuteContext(this);
ExecuteListener listener = new ExecuteListeners(ctx);
try {
FieldProvider fields = new MetaDataFieldProvider(this, rs.getMetaData());
ctx.resultSet(rs);
listener.fetchStart(ctx);
return new CursorImpl<Record>(ctx, listener, fields).fetch();
}
catch (SQLException e) {

View File

@ -440,11 +440,10 @@ class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> implements
}
}
ExecuteListener listener2 = new ExecuteListeners(ctx.configuration());
ExecuteContext ctx2 = new DefaultExecuteContext(ctx.configuration(), null);
ExecuteContext ctx2 = new DefaultExecuteContext(ctx.configuration());
ExecuteListener listener2 = new ExecuteListeners(ctx2);
ctx2.resultSet(rs);
listener2.fetchStart(ctx2);
returned = new CursorImpl<R>(ctx2, listener2, returning, getInto().getRecordType()).fetch();
return result;
}

View File

@ -459,9 +459,10 @@ final class Util {
/**
* Safely close a statement
*/
static final void safeClose(ExecuteContext ctx) {
static final void safeClose(ExecuteListener listener, ExecuteContext ctx) {
safeClose(ctx.resultSet());
safeClose(ctx.statement());
listener.end(ctx);
}
/**

View File

@ -49,7 +49,7 @@ public class StopWatchListener implements ExecuteListener {
private final StopWatch watch = new StopWatch();
@Override
public void init(ExecuteContext ctx) {
public void start(ExecuteContext ctx) {
watch.splitTrace("Initialising");
}
@ -99,8 +99,8 @@ public class StopWatchListener implements ExecuteListener {
}
@Override
public void fetchEnd(ExecuteContext ctx) {
watch.splitDebug("Results fetched");
public void resultStart(ExecuteContext ctx) {
watch.splitTrace("Fetching result");
}
@Override
@ -113,13 +113,18 @@ public class StopWatchListener implements ExecuteListener {
watch.splitTrace("Record fetched");
}
@Override
public void resultStart(ExecuteContext ctx) {
watch.splitTrace("Fetching result");
}
@Override
public void resultEnd(ExecuteContext ctx) {
watch.splitTrace("Result fetched");
}
@Override
public void fetchEnd(ExecuteContext ctx) {
watch.splitTrace("Results fetched");
}
@Override
public void end(ExecuteContext ctx) {
watch.splitDebug("Finishing");
}
}