[#1855] Add Query.cancel() to support for interrupting statements
prematurely
This commit is contained in:
parent
675adc205f
commit
dfb0ae8717
@ -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) {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user