/*
* Copyright (c) 2010-2013 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.repo.sql.util;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.mchange.v2.c3p0.impl.DefaultConnectionTester;
import java.sql.Connection;
import java.sql.SQLException;
/**
*
* When getting serialization-related SQLException (as when getting any exception), c3p0 checks the connection
* whether it is valid. However, in case of PostgreSQL, ANY 'select' command used for testing
* (including 'select 1') fails in this situation with a message "current transaction is aborted,
* commands ignored until end of transaction block". So the connection is released, and new one is
* created, which leads to performance problems.
*
* So it is probably best to roll the transaction back before checking the connection validity. To be safe,
* we currently do this only for PostgreSQL; other databases (H2, MySQL) do not seem to have problems of this kind:
* - MySQL does not even notice any serialization issues (why??? that's a bit suspicious)
* - H2 checks the connection, but it can do that without problems within current transaction.
*
* @author mederly
*/
public class MidPointConnectionTester extends DefaultConnectionTester {
private static final Trace LOGGER = TraceManager.getTrace(MidPointConnectionTester.class);
public static final String POSTGRESQL_PRODUCT_NAME = "PostgreSQL";
private void rollbackChecked(Connection c) {
try {
if (POSTGRESQL_PRODUCT_NAME.equals(c.getMetaData().getDatabaseProductName())) {
c.rollback();
}
} catch (SQLException e) {
LOGGER.debug("An exception got when rolling back current transaction on suspicious DB connection", e);
}
}
@Override
public int activeCheckConnection(Connection c, String query, Throwable[] rootCauseOutParamHolder) {
rollbackChecked(c);
return super.activeCheckConnection(c, query, rootCauseOutParamHolder);
}
@Override
public int statusOnException(Connection c, Throwable t, String query, Throwable[] rootCauseOutParamHolder) {
rollbackChecked(c);
return super.statusOnException(c, t, query, rootCauseOutParamHolder);
}
}