diff --git a/jOOQ/src/main/java/org/jooq/ExecuteContext.java b/jOOQ/src/main/java/org/jooq/ExecuteContext.java index c956037deb..bd8653e59e 100644 --- a/jOOQ/src/main/java/org/jooq/ExecuteContext.java +++ b/jOOQ/src/main/java/org/jooq/ExecuteContext.java @@ -66,11 +66,31 @@ public interface ExecuteContext extends Configuration { /** * The jOOQ {@link Query} that is being executed or null if the * query is unknown or if there was no jOOQ Query + *

+ * If {@link #batchQueries()} returns several Query objects, + * this will always return the currently rendered / prepared + * Query, or null, if no Query is + * currently being rendered / prepared * * @see #routine() + * @see #batchQueries() */ Query query(); + /** + * The jOOQ {@link Query} objects that are being executed in batch mode, or + * null if the query is unknown or if there was no jOOQ + * Query + *

+ * If a single Query is executed in non-batch mode, this will + * return an array of length 1, containing that + * Query + * + * @see #query() + * @see #routine() + */ + Query[] batchQueries(); + /** * The jOOQ {@link Routine} that is being executed or null if * the query is unknown or if there was no jOOQ Routine @@ -94,6 +114,19 @@ public interface ExecuteContext extends Configuration { */ void sql(String sql); + /** + * The generated SQL statements that are being executed in batch mode, or + * null if the query is unknown or if there was no SQL statement + *

+ * If a single Query is executed in non-batch mode, this will + * return an array of length 1, containing that + * Query + * + * @see #query() + * @see #routine() + */ + String[] batchSQL(); + /** * The {@link PreparedStatement} that is being executed or null * if the statement is unknown or if there was no statement. diff --git a/jOOQ/src/main/java/org/jooq/ExecuteListener.java b/jOOQ/src/main/java/org/jooq/ExecuteListener.java index 3c07b0572c..db321b74f6 100644 --- a/jOOQ/src/main/java/org/jooq/ExecuteListener.java +++ b/jOOQ/src/main/java/org/jooq/ExecuteListener.java @@ -73,119 +73,152 @@ import org.jooq.tools.StopWatchListener; * Use case [2] * Use case [3] * Use case [4] + * Use case [5] + * Use case [6] * * * {@link #start(ExecuteContext)} - * Yes - * Yes - * Yes - * Yes + * Yes, 1x + * Yes, 1x + * Yes, 1x + * Yes, 1x + * Yes, 1x + * Yes, 1x * * * {@link #renderStart(ExecuteContext)} - * Yes - * Yes + * Yes, 1x + * Yes, 1x * No - * Yes + * Yes, 1x + * Yes, Nx (for every query) + * Yes, 1x * * * {@link #renderEnd(ExecuteContext)} - * Yes - * Yes + * Yes, 1x + * Yes, 1x * No - * Yes + * Yes, 1x + * Yes, Nx (for every query) + * Yes, 1x * * * {@link #prepareStart(ExecuteContext)} - * Yes - * Yes + * Yes, 1x + * Yes, 1x * No - * Yes + * Yes, 1x + * Yes, Nx (for every query) + * Yes, 1x * * * {@link #prepareEnd(ExecuteContext)} - * Yes - * Yes + * Yes, 1x + * Yes, 1x * No - * Yes + * Yes, 1x + * Yes, Nx (for every query) + * Yes, 1x * * * {@link #bindStart(ExecuteContext)} - * Yes + * Yes, 1x * No * No - * Yes + * Yes, Nx (for every value set) + * Yes, 1x + * Yes, 1x * * * {@link #bindEnd(ExecuteContext)} - * Yes + * Yes, 1x * No * No - * Yes - * + * Yes, Nx (for every value set) + * Yes, 1x + * Yes, 1 * * {@link #executeStart(ExecuteContext)} - * Yes - * Yes + * Yes, 1x + * Yes, 1x * No - * Yes + * Yes, 1x + * Yes, 1x + * Yes, 1x * * * {@link #executeEnd(ExecuteContext)} - * Yes - * Yes + * Yes, 1x + * Yes, 1x * No - * Yes + * Yes, 1x + * Yes, 1x + * Yes, 1x * * * {@link #fetchStart(ExecuteContext)} - * Yes - * Yes - * Yes + * Yes, 1x (Nx for {@link ResultQuery#fetchMany()} + * Yes, 1x (Nx for {@link ResultQuery#fetchMany()} + * Yes, 1x + * No + * No * No * * * {@link #resultStart(ExecuteContext)} - * Yes - * Yes - * Yes + * Yes, 1x (Nx for {@link Cursor#fetch(int)} + * Yes, 1x (Nx for {@link Cursor#fetch(int)} + * Yes, 1x + * No + * No * No * * * {@link #recordStart(ExecuteContext)}
* - * Yes - * Yes - * Yes + * Yes, Nx + * Yes, Nx + * Yes, Nx + * No + * No * No * * * {@link #recordEnd(ExecuteContext)} - * Yes - * Yes - * Yes + * Yes, Nx + * Yes, Nx + * Yes, Nx + * No + * No * No * * * {@link #resultEnd(ExecuteContext)} - * Yes - * Yes - * Yes + * Yes, 1x (Nx for {@link Cursor#fetch(int)} + * Yes, 1x (Nx for {@link Cursor#fetch(int)} + * Yes, 1x + * No + * No * No * * * {@link #fetchEnd(ExecuteContext)} - * Yes - * Yes - * Yes + * Yes, 1x (Nx for {@link ResultQuery#fetchMany()} + * Yes, 1x (Nx for {@link ResultQuery#fetchMany()} + * Yes, 1x + * No + * No * No * * * {@link #end(ExecuteContext)} - * Yes - * Yes - * Yes - * No + * Yes, 1x + * Yes, 1x + * Yes, 1x + * Yes, 1x + * Yes, 1x + * Yes, 1x * * *
@@ -197,6 +230,8 @@ import org.jooq.tools.StopWatchListener; * {@link StatementType#STATIC_STATEMENT} *

  • Used with {@link Factory#fetch(ResultSet)} or with * {@link InsertResultStep#fetch()}
  • + *
  • Used with {@link Factory#batch(Query)}
  • + *
  • Used with {@link Factory#batch(Query[])}
  • *
  • Used with a {@link Routine} standalone call
  • * *

    diff --git a/jOOQ/src/main/java/org/jooq/impl/BatchMultiple.java b/jOOQ/src/main/java/org/jooq/impl/BatchMultiple.java index 4dc2d75d1a..7db8ef92bd 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BatchMultiple.java +++ b/jOOQ/src/main/java/org/jooq/impl/BatchMultiple.java @@ -37,23 +37,17 @@ package org.jooq.impl; import java.sql.Connection; import java.sql.SQLException; -import java.sql.Statement; import org.jooq.Batch; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Query; -import org.jooq.tools.JooqLogger; -import org.jooq.tools.StopWatch; /** * @author Lukas Eder */ class BatchMultiple implements Batch { - /** - * Generated UID - */ - private static final JooqLogger log = JooqLogger.getLogger(BatchMultiple.class); - private final Factory create; private final Query[] queries; @@ -64,35 +58,40 @@ class BatchMultiple implements Batch { @Override public final int[] execute() { - StopWatch watch = new StopWatch(); Connection connection = create.getConnection(); - Statement statement = null; - String sql = null; + + ExecuteContext ctx = new DefaultExecuteContext(create, queries); + ExecuteListener listener = new ExecuteListeners(ctx); try { - statement = connection.createStatement(); + ctx.statement(new PreparedStatementProxy(connection)); - for (Query query : queries) { - sql = create.renderInlined(query); - watch.splitTrace("SQL rendered"); - - if (log.isDebugEnabled()) - log.debug("Adding batch", sql); - - statement.addBatch(sql); + String[] batchSQL = ctx.batchSQL(); + for (int i = 0; i < queries.length; i++) { + listener.renderStart(ctx); + batchSQL[i] = create.renderInlined(queries[i]); + listener.renderEnd(ctx); } - int[] result = statement.executeBatch(); - watch.splitTrace("Statement executed"); + for (String sql : batchSQL) { + ctx.sql(sql); + listener.prepareStart(ctx); + ctx.statement().addBatch(sql); + listener.prepareEnd(ctx); + ctx.sql(null); + } + + listener.executeStart(ctx); + int[] result = ctx.statement().executeBatch(); + listener.executeEnd(ctx); return result; } catch (SQLException e) { - throw Util.translate("BatchMultiple.execute", sql, e); + throw Util.translate("BatchMultiple.execute", ctx.sql(), e); } finally { - Util.safeClose(statement); - watch.splitDebug("Statement executed"); + Util.safeClose(listener, ctx); } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java b/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java index bad699bca7..70f790a1a5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java +++ b/jOOQ/src/main/java/org/jooq/impl/BatchSingle.java @@ -36,26 +36,20 @@ package org.jooq.impl; import java.sql.Connection; -import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.jooq.BatchBindStep; +import org.jooq.ExecuteContext; +import org.jooq.ExecuteListener; import org.jooq.Query; -import org.jooq.tools.JooqLogger; -import org.jooq.tools.StopWatch; /** * @author Lukas Eder */ class BatchSingle implements BatchBindStep { - /** - * Generated UID - */ - private static final JooqLogger log = JooqLogger.getLogger(BatchSingle.class); - private final Factory create; private final Query query; private final List allBindValues; @@ -74,41 +68,39 @@ class BatchSingle implements BatchBindStep { @Override public final int[] execute() { - StopWatch watch = new StopWatch(); Connection connection = create.getConnection(); - PreparedStatement statement = null; - String sql = null; + + ExecuteContext ctx = new DefaultExecuteContext(create, query); + ExecuteListener listener = new ExecuteListeners(ctx); try { + listener.renderStart(ctx); + ctx.sql(create.render(query)); + listener.renderEnd(ctx); - sql = create.render(query); - watch.splitTrace("SQL rendered"); - - if (log.isDebugEnabled()) - log.debug("Executing query", create.renderInlined(query)); - if (log.isTraceEnabled()) - log.trace("Preparing statement", sql); - - statement = connection.prepareStatement(sql); - watch.splitTrace("Statement prepared"); + listener.prepareStart(ctx); + ctx.statement(connection.prepareStatement(ctx.sql())); + listener.prepareEnd(ctx); for (Object[] bindValues : allBindValues) { - new DefaultBindContext(create, statement).bindValues(bindValues); - statement.addBatch(); + listener.bindStart(ctx); + new DefaultBindContext(create, ctx.statement()).bindValues(bindValues); + listener.bindEnd(ctx); + + ctx.statement().addBatch(); } - watch.splitTrace("Variables bound"); - int[] result = statement.executeBatch(); - watch.splitTrace("Statement executed"); + listener.executeStart(ctx); + int[] result = ctx.statement().executeBatch(); + listener.executeEnd(ctx); return result; } catch (SQLException e) { - throw Util.translate("BatchSingle.execute", sql, e); + throw Util.translate("BatchSingle.execute", ctx.sql(), e); } finally { - Util.safeClose(statement); - watch.splitDebug("Statement executed"); + Util.safeClose(listener, ctx); } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java index 5d43b0e129..e044402edb 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultExecuteContext.java @@ -68,6 +68,9 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont private final Routine routine; private String sql; + private final Query[] batchQueries; + private final String[] batchSQL; + // Transient attributes private transient PreparedStatement statement; private transient ResultSet resultSet; @@ -75,22 +78,28 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont private transient Result result; DefaultExecuteContext(Configuration configuration) { - this(configuration, null, null); + this(configuration, null, null, null); + } + + DefaultExecuteContext(Configuration configuration, Query[] batchQueries) { + this(configuration, null, batchQueries, null); } DefaultExecuteContext(Configuration configuration, Query query) { - this(configuration, query, null); + this(configuration, query, new Query[] { query }, null); } DefaultExecuteContext(Configuration configuration, Routine routine) { - this(configuration, null, routine); + this(configuration, null, null, routine); } - private DefaultExecuteContext(Configuration configuration, Query query, Routine routine) { + private DefaultExecuteContext(Configuration configuration, Query query, Query[] batchQueries, Routine routine) { super(configuration); this.query = query; + this.batchQueries = batchQueries; this.routine = routine; + this.batchSQL = (batchQueries == null ? null : new String[batchQueries.length]); } @Override @@ -122,6 +131,11 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont return query; } + @Override + public final Query[] batchQueries() { + return batchQueries; + } + @Override public final Routine routine() { return routine; @@ -137,6 +151,11 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont return sql; } + @Override + public final String[] batchSQL() { + return batchSQL; + } + @Override public final void statement(PreparedStatement s) { this.statement = s; diff --git a/jOOQ/src/main/java/org/jooq/impl/PreparedStatementProxy.java b/jOOQ/src/main/java/org/jooq/impl/PreparedStatementProxy.java index ae2c8e2d4f..511b8a75df 100644 --- a/jOOQ/src/main/java/org/jooq/impl/PreparedStatementProxy.java +++ b/jOOQ/src/main/java/org/jooq/impl/PreparedStatementProxy.java @@ -87,7 +87,11 @@ class PreparedStatementProxy implements PreparedStatement { } private PreparedStatementProxy(Connection connection, String sql, MethodType type) throws SQLException { - this(connection, sql, type, connection.createStatement()); + this(connection, sql, type, connection.createStatement()); + } + + PreparedStatementProxy(Connection connection) throws SQLException { + this(connection, null, MethodType.BATCH); } PreparedStatementProxy(Connection connection, String sql) throws SQLException { @@ -161,7 +165,13 @@ class PreparedStatementProxy implements PreparedStatement { * Corresponds to * {@link Connection#prepareStatement(String, String[]) */ - SQL_CN + SQL_CN, + + /** + * Corresponds to {@link Connection#createStatement()} and + * {@link Statement#executeBatch()} + */ + BATCH } // ------------------------------------------------------------------------ @@ -364,7 +374,7 @@ class PreparedStatementProxy implements PreparedStatement { } // ------------------------------------------------------------------------ - // XXX: Unsupported batch methods + // XXX: Supported and unsupported batch methods // ------------------------------------------------------------------------ @Override @@ -374,17 +384,17 @@ class PreparedStatementProxy implements PreparedStatement { @Override public final void clearBatch() throws SQLException { - throw new UnsupportedOperationException("Cannot batch execute statements on PreparedStatementProxy"); + delegate.clearBatch(); } @Override public final int[] executeBatch() throws SQLException { - throw new UnsupportedOperationException("Cannot batch execute statements on PreparedStatementProxy"); + return delegate.executeBatch(); } @Override public final void addBatch(String query) throws SQLException { - throw new UnsupportedOperationException("Cannot batch execute statements on PreparedStatementProxy"); + delegate.addBatch(query); } // ------------------------------------------------------------------------