closed statements * [#1885] Add test to count opening and closing of Statements and ResultSets by jOOQ * [#2523] Statement.close() may be called upon previously closed statements
This commit is contained in:
parent
d583f95e04
commit
e718d81204
@ -33,14 +33,12 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.test._;
|
||||
package org.jooq.test._.listeners;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.impl.DefaultExecuteListener;
|
||||
|
||||
import org.junit.Test;
|
||||
@ -51,38 +49,24 @@ import org.junit.Test;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class LifecycleWatcherListener extends DefaultExecuteListener {
|
||||
public abstract class AbstractLifecycleListener extends DefaultExecuteListener {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -2283264126211556442L;
|
||||
private static final long serialVersionUID = -2283264126211556442L;
|
||||
|
||||
private static Comparator<Method> METHOD_COMPARATOR = new Comparator<Method>() {
|
||||
protected static Comparator<Method> METHOD_COMPARATOR = new Comparator<Method>() {
|
||||
|
||||
@Override
|
||||
public int compare(Method o1, Method o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public int compare(Method o1, Method o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Map<Method, Integer> START_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
public static final Map<Method, Integer> END_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
private static final Object INCREMENT_MONITOR = new Object();
|
||||
private static final Object INCREMENT_MONITOR = new Object();
|
||||
|
||||
@Override
|
||||
public void start(ExecuteContext ctx) {
|
||||
super.start(ctx);
|
||||
increment(START_COUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(ExecuteContext ctx) {
|
||||
super.end(ctx);
|
||||
increment(END_COUNT);
|
||||
}
|
||||
|
||||
private void increment(Map<Method, Integer> map) {
|
||||
protected void increment(Map<Method, Integer> map) {
|
||||
synchronized (INCREMENT_MONITOR) {
|
||||
Method m = testMethod();
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.test._.listeners;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.tools.jdbc.DefaultCallableStatement;
|
||||
import org.jooq.tools.jdbc.DefaultPreparedStatement;
|
||||
|
||||
/**
|
||||
* An <code>ExecuteListener</code> that collects data about the lifecycle of
|
||||
* JDBC objects in all integration tests.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class JDBCLifecycleListener extends AbstractLifecycleListener {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -2283264126211556442L;
|
||||
|
||||
public static final Map<Method, Integer> STMT_START_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
public static final Map<Method, Integer> STMT_CLOSE_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
|
||||
public static final Map<Method, Integer> RS_START_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
public static final Map<Method, Integer> RS_CLOSE_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
|
||||
@Override
|
||||
public void executeStart(ExecuteContext ctx) {
|
||||
super.executeStart(ctx);
|
||||
increment(STMT_START_COUNT);
|
||||
|
||||
if (ctx.statement() instanceof CallableStatement) {
|
||||
ctx.statement(new DefaultCallableStatement((CallableStatement) ctx.statement()) {
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
increment(STMT_CLOSE_COUNT);
|
||||
super.close();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
ctx.statement(new DefaultPreparedStatement(ctx.statement()) {
|
||||
|
||||
@Override
|
||||
public void close() throws SQLException {
|
||||
increment(STMT_CLOSE_COUNT);
|
||||
super.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.test._.listeners;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jooq.ExecuteContext;
|
||||
|
||||
/**
|
||||
* An <code>ExecuteListener</code> that collects data about the lifecycle of
|
||||
* execute listeners in all integration tests.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public class LifecycleWatcherListener extends AbstractLifecycleListener {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -2283264126211556442L;
|
||||
|
||||
public static final Map<Method, Integer> START_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
public static final Map<Method, Integer> END_COUNT = new TreeMap<Method, Integer>(METHOD_COMPARATOR);
|
||||
|
||||
@Override
|
||||
public void start(ExecuteContext ctx) {
|
||||
super.start(ctx);
|
||||
increment(START_COUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(ExecuteContext ctx) {
|
||||
super.end(ctx);
|
||||
increment(END_COUNT);
|
||||
}
|
||||
}
|
||||
@ -33,7 +33,7 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.test._;
|
||||
package org.jooq.test._.listeners;
|
||||
|
||||
import static org.jooq.conf.ParamType.INLINED;
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.test._;
|
||||
package org.jooq.test._.listeners;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -462,14 +462,32 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkStatement(ExecuteContext ctx, boolean patched) {
|
||||
assertNotNull(ctx.statement());
|
||||
checkStatement(ctx, patched, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkStatement(ExecuteContext ctx, boolean patched, boolean isNull) {
|
||||
if (isNull) {
|
||||
assertNull(ctx.statement());
|
||||
}
|
||||
else {
|
||||
assertNotNull(ctx.statement());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkResultSet(ExecuteContext ctx, boolean patched) {
|
||||
assertNotNull(ctx.resultSet());
|
||||
checkResultSet(ctx, patched, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkResultSet(ExecuteContext ctx, boolean patched, boolean isNull) {
|
||||
if (isNull) {
|
||||
assertNull(ctx.resultSet());
|
||||
}
|
||||
else {
|
||||
assertNotNull(ctx.resultSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -651,8 +669,8 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
resultEnd = ++callbackCount;
|
||||
checkBase(ctx);
|
||||
checkSQL(ctx, true);
|
||||
checkStatement(ctx, true);
|
||||
checkResultSet(ctx, true);
|
||||
checkStatement(ctx, true, true);
|
||||
checkResultSet(ctx, true, true);
|
||||
assertNotNull(ctx.record());
|
||||
assertEquals(2, ctx.record().fieldsRow().size());
|
||||
|
||||
@ -665,8 +683,8 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
fetchEnd = ++callbackCount;
|
||||
checkBase(ctx);
|
||||
checkSQL(ctx, true);
|
||||
checkStatement(ctx, true);
|
||||
checkResultSet(ctx, true);
|
||||
checkStatement(ctx, true, true);
|
||||
checkResultSet(ctx, true, true);
|
||||
assertNotNull(ctx.record());
|
||||
assertEquals(2, ctx.record().fieldsRow().size());
|
||||
|
||||
@ -679,8 +697,8 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
end = ++callbackCount;
|
||||
checkBase(ctx);
|
||||
checkSQL(ctx, true);
|
||||
checkStatement(ctx, true);
|
||||
checkResultSet(ctx, true);
|
||||
checkStatement(ctx, true, true);
|
||||
checkResultSet(ctx, true, true);
|
||||
assertNotNull(ctx.record());
|
||||
assertEquals(2, ctx.record().fieldsRow().size());
|
||||
|
||||
@ -791,9 +809,18 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkStatement(ExecuteContext ctx, boolean patched) {
|
||||
assertNotNull(ctx.statement());
|
||||
checkStatement(ctx, patched, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkStatement(ExecuteContext ctx, boolean patched, boolean isNull) {
|
||||
if (isNull) {
|
||||
assertNull(ctx.statement());
|
||||
}
|
||||
else {
|
||||
assertNotNull(ctx.statement());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -915,7 +942,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
end = ++callbackCount;
|
||||
checkBase(ctx);
|
||||
checkSQL(ctx, true);
|
||||
checkStatement(ctx, true);
|
||||
checkStatement(ctx, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1024,9 +1051,18 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkStatement(ExecuteContext ctx, boolean patched) {
|
||||
assertNotNull(ctx.statement());
|
||||
checkStatement(ctx, patched, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void checkStatement(ExecuteContext ctx, boolean patched, boolean isNull) {
|
||||
if (isNull) {
|
||||
assertNull(ctx.statement());
|
||||
}
|
||||
else {
|
||||
assertNotNull(ctx.statement());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1142,7 +1178,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T7
|
||||
end = ++callbackCount;
|
||||
checkBase(ctx);
|
||||
checkSQL(ctx, true);
|
||||
checkStatement(ctx, true);
|
||||
checkStatement(ctx, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -93,9 +93,6 @@ import org.jooq.debug.console.Console;
|
||||
import org.jooq.debug.impl.DebuggerFactory;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.impl.DefaultExecuteListenerProvider;
|
||||
import org.jooq.test._.LifecycleWatcherListener;
|
||||
import org.jooq.test._.PrettyPrinter;
|
||||
import org.jooq.test._.TestStatisticsListener;
|
||||
import org.jooq.test._.converters.Boolean_10;
|
||||
import org.jooq.test._.converters.Boolean_TF_LC;
|
||||
import org.jooq.test._.converters.Boolean_TF_UC;
|
||||
@ -103,6 +100,10 @@ import org.jooq.test._.converters.Boolean_YES_NO_LC;
|
||||
import org.jooq.test._.converters.Boolean_YES_NO_UC;
|
||||
import org.jooq.test._.converters.Boolean_YN_LC;
|
||||
import org.jooq.test._.converters.Boolean_YN_UC;
|
||||
import org.jooq.test._.listeners.JDBCLifecycleListener;
|
||||
import org.jooq.test._.listeners.LifecycleWatcherListener;
|
||||
import org.jooq.test._.listeners.PrettyPrinter;
|
||||
import org.jooq.test._.listeners.TestStatisticsListener;
|
||||
import org.jooq.test._.testcases.AggregateWindowFunctionTests;
|
||||
import org.jooq.test._.testcases.AliasTests;
|
||||
import org.jooq.test._.testcases.BatchTests;
|
||||
@ -463,11 +464,10 @@ public abstract class jOOQAbstractTest<
|
||||
logStat.info("---------------");
|
||||
logStat.info("Total", total);
|
||||
|
||||
logStat.info("");
|
||||
|
||||
JooqLogger logLife = JooqLogger.getLogger(LifecycleWatcherListener.class);
|
||||
logLife.info("EXECUTE LIFECYCLE STATS");
|
||||
logLife.info("-----------------------");
|
||||
logStat.info("");
|
||||
logLife.info("EXECUTE LISTENER LIFECYCLE STATS");
|
||||
logLife.info("--------------------------------");
|
||||
|
||||
int unbalanced = 0;
|
||||
for (Method m : LifecycleWatcherListener.START_COUNT.keySet()) {
|
||||
@ -485,6 +485,25 @@ public abstract class jOOQAbstractTest<
|
||||
}
|
||||
}
|
||||
|
||||
logStat.info("");
|
||||
logLife.info("JDBC OBJECT LIFECYCLE STATS");
|
||||
logLife.info("---------------------------");
|
||||
for (Method m : JDBCLifecycleListener.STMT_START_COUNT.keySet()) {
|
||||
Integer starts = JDBCLifecycleListener.STMT_START_COUNT.get(m);
|
||||
Integer ends = JDBCLifecycleListener.STMT_CLOSE_COUNT.get(m);
|
||||
|
||||
if (!StringUtils.equals(starts, ends)) {
|
||||
unbalanced++;
|
||||
|
||||
logLife.info(
|
||||
"Unbalanced", String.format("(open, close): (%1$3s, %2$3s) at %3$s",
|
||||
starts,
|
||||
ends == null ? 0 : ends,
|
||||
m.toString().replace("public void ", "").replaceAll("( throws.*)?", "")));
|
||||
}
|
||||
}
|
||||
|
||||
logStat.info("");
|
||||
logLife.info("Unbalanced test: ", unbalanced);
|
||||
}
|
||||
|
||||
@ -884,9 +903,10 @@ public abstract class jOOQAbstractTest<
|
||||
|
||||
return DSL.using(create0(settings).configuration().derive(
|
||||
DefaultExecuteListenerProvider.providers(
|
||||
new JDBCLifecycleListener(),
|
||||
new LifecycleWatcherListener(),
|
||||
new TestStatisticsListener(),
|
||||
new PrettyPrinter(),
|
||||
new LifecycleWatcherListener()
|
||||
new PrettyPrinter()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@ -360,8 +360,6 @@ abstract class AbstractQuery extends AbstractQueryPart implements Query, Attacha
|
||||
/**
|
||||
* Default implementation for executable check. Subclasses may override this
|
||||
* method.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isExecutable() {
|
||||
|
||||
@ -1080,11 +1080,15 @@ final class Utils {
|
||||
* Safely close a statement
|
||||
*/
|
||||
static final void safeClose(ExecuteListener listener, ExecuteContext ctx, boolean keepStatement, boolean keepResultSet) {
|
||||
JDBCUtils.safeClose(ctx.resultSet());
|
||||
// [#2523] Set JDBC objects to null, to prevent repeated closing
|
||||
JDBCUtils.safeClose(ctx.resultSet());
|
||||
ctx.resultSet(null);
|
||||
|
||||
// [#385] Close statements only if not requested to keep open
|
||||
if (!keepStatement)
|
||||
if (!keepStatement) {
|
||||
JDBCUtils.safeClose(ctx.statement());
|
||||
ctx.statement(null);
|
||||
}
|
||||
|
||||
// [#1868] [#2373] Terminate ExecuteListener lifecycle, if needed
|
||||
if (keepResultSet)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user