[#1855] Add Query.cancel() to support for interrupting statements

prematurely
This commit is contained in:
Lukas Eder 2012-10-19 16:38:55 +02:00
parent 675adc205f
commit dfb0ae8717
10 changed files with 118 additions and 35 deletions

View File

@ -38,6 +38,7 @@ package org.jooq.test._.testcases;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.jooq.impl.Factory.val;
import java.lang.reflect.InvocationHandler;
@ -51,9 +52,11 @@ import org.jooq.Cursor;
import org.jooq.ExecuteContext;
import org.jooq.Record;
import org.jooq.ResultQuery;
import org.jooq.Select;
import org.jooq.TableRecord;
import org.jooq.UpdatableRecord;
import org.jooq.conf.Settings;
import org.jooq.exception.DataAccessException;
import org.jooq.impl.DefaultExecuteListener;
import org.jooq.test.BaseTest;
import org.jooq.test.jOOQAbstractTest;
@ -111,8 +114,9 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658,
Cursor<Record> cursor = query.fetchLazy();
assertEquals(3, cursor.fetchOne().getValue(0));
assertEquals(3, query.fetchOne(0));
assertEquals(3, KeepStatementListener.statements.size());
assertEquals(4, KeepStatementListener.statements.size());
assertEquals(0, KeepStatementListener.closed);
assertTrue(
KeepStatementListener.statements.get(0) ==
@ -154,8 +158,46 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658,
}
});
ctx.statement(s);
if (!delegate.getClass().getName().toLowerCase().contains("proxy")) {
ctx.statement(s);
}
statements.add(delegate);
}
}
@Test
public void testCancelStatement() throws Exception {
// [#1855] The below query is *likely* to run for a long time, and can
// thus be cancelled
final Select<?> select =
create().selectOne()
.from(
TBook(), TBook(), TBook(), TBook(),
TBook(), TBook(), TBook(), TBook(),
TBook(), TBook(), TBook(), TBook(),
TBook(), TBook(), TBook(), TBook(),
TBook(), TBook(), TBook(), TBook(),
TBook(), TBook(), TBook(), TBook(),
TBook(), TBook(), TBook(), TBook());
try {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
}
catch (InterruptedException ignore) {}
select.cancel();
}
}).start();
// The fetch should never terminate, as the above thread should cancel it
select.fetch();
fail();
}
catch (DataAccessException expected) {}
}
}

View File

@ -1781,6 +1781,11 @@ public abstract class jOOQAbstractTest<
new StatementTests(this).testKeepStatement();
}
@Test
public void testCancelStatement() throws Exception {
new StatementTests(this).testCancelStatement();
}
@Test
public void testVoid() {
// A final test case to clean up the test database

View File

@ -226,6 +226,19 @@ public interface Query extends QueryPart, Attachable {
* @throws DataAccessException If something went wrong closing the statement
* @see Statement#close()
*/
Query close() throws DataAccessException;
void close() throws DataAccessException;
/**
* Cancel the underlying statement
* <p>
* This cancels the query's underlying {@link Statement} or
* {@link PreparedStatement}. If there is no underlying open and running
* statement, this call is simply ignored.
*
* @throws DataAccessException If something went wrong cancelling the
* statement
* @see Statement#cancel()
*/
void cancel() throws DataAccessException;
}

View File

@ -934,12 +934,6 @@ public interface ResultQuery<R extends Record> extends Query {
@Override
ResultQuery<R> keepStatement(boolean keepStatement);
/**
* {@inheritDoc}
*/
@Override
ResultQuery<R> close() throws DataAccessException;
/**
* Specify the maximum number of rows returned by the underlying
* {@link Statement}

View File

@ -95,8 +95,13 @@ abstract class AbstractDelegatingSelect<R extends Record>
}
@Override
public final ResultQuery<R> close() {
return getDelegate().close();
public final void close() {
getDelegate().close();
}
@Override
public final void cancel() {
getDelegate().cancel();
}
@Override

View File

@ -52,7 +52,6 @@ import org.jooq.ExecuteContext;
import org.jooq.ExecuteListener;
import org.jooq.Param;
import org.jooq.Query;
import org.jooq.exception.DataAccessException;
import org.jooq.exception.DetachedException;
import org.jooq.tools.JooqLogger;
@ -169,18 +168,33 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha
* {@inheritDoc}
*/
@Override
public Query close() throws DataAccessException {
public final void close() {
if (statement != null) {
try {
statement.close();
statement = null;
}
catch (SQLException e) {
throw Util.translate(null, e);
throw Util.translate(sql, e);
}
}
}
return this;
/**
* Subclasses may override this for covariant result types
* <p>
* {@inheritDoc}
*/
@Override
public final void cancel() {
if (statement != null) {
try {
statement.cancel();
}
catch (SQLException e) {
throw Util.translate(sql, e);
}
}
}
@SuppressWarnings("deprecation")
@ -209,7 +223,7 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha
try {
// [#385] If a statement was previously kept open
if (statement != null) {
if (keepStatement() && statement != null) {
ctx.sql(sql);
ctx.statement(statement);
}
@ -220,17 +234,13 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha
ctx.sql(getSQL());
listener.renderEnd(ctx);
if (keepStatement) {
sql = ctx.sql();
}
sql = ctx.sql();
listener.prepareStart(ctx);
prepare(ctx);
listener.prepareEnd(ctx);
if (keepStatement) {
statement = ctx.statement();
}
statement = ctx.statement();
}
// [#1856] Set the query timeout onto the Statement
@ -257,7 +267,12 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha
// ResultQuery.fetchLazy() needs to keep open resources
if (!keepResult()) {
Util.safeClose(listener, ctx, keepStatement);
Util.safeClose(listener, ctx, keepStatement());
}
if (!keepStatement()) {
statement = null;
sql = null;
}
}
}

View File

@ -129,12 +129,6 @@ abstract class AbstractResultQuery<R extends Record> extends AbstractQuery imple
return (ResultQuery<R>) super.keepStatement(k);
}
@SuppressWarnings("unchecked")
@Override
public final ResultQuery<R> close() {
return (ResultQuery<R>) super.close();
}
@Override
public final ResultQuery<R> maxRows(int rows) {
this.maxRows = rows;

View File

@ -103,8 +103,13 @@ class DeleteImpl<R extends Record>
}
@Override
public final Query close() {
return getDelegate().close();
public final void close() {
getDelegate().close();
}
@Override
public final void cancel() {
getDelegate().cancel();
}
@Override

View File

@ -121,8 +121,13 @@ class InsertImpl<R extends Record>
}
@Override
public final Query close() {
return getDelegate().close();
public final void close() {
getDelegate().close();
}
@Override
public final void cancel() {
getDelegate().cancel();
}
// -------------------------------------------------------------------------

View File

@ -108,8 +108,13 @@ final class UpdateImpl<R extends Record>
}
@Override
public final Query close() {
return getDelegate().close();
public final void close() {
getDelegate().close();
}
@Override
public final void cancel() {
getDelegate().cancel();
}
@Override