/*
* Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com>
*
* 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.obidea.semantika.queryanswer.internal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.slf4j.Logger;
import com.obidea.semantika.exception.SemantikaException;
import com.obidea.semantika.util.LogUtils;
public class QueryEvaluator implements IQueryEvaluator
{
private ConnectionManager mConnectionManager;
private Set<PreparedStatement> mStatementsToClose = new HashSet<PreparedStatement>();
private Set<ResultSet> mResultSetsToClose = new HashSet<ResultSet>();
private long mTransactionTimeout = -1;
private int mTransactionFetchSize = -1;
private int mTransactionMaxRows = -1;
private boolean mIsTransactionTimeoutSet = false;
private boolean mIsTransactionFetchSizeSet = false;
private boolean mIsTransactionMaxRowsSet = false;
private static final Logger LOG = LogUtils.createLogger("semantika.queryanswer"); //$NON-NLS-1$
public QueryEvaluator(ConnectionManager connectionManager)
{
mConnectionManager = connectionManager;
}
@Override
public PreparedStatement prepareQueryStatement(String sql) throws SQLException, SemantikaException
{
PreparedStatement ps = mConnectionManager.getConnection()
.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
setTimeout(ps);
setFetchSize(ps);
setMaxRows(ps);
mStatementsToClose.add(ps);
return ps;
}
private void setTimeout(PreparedStatement stmt) throws SQLException, QueryEvaluationException
{
if (mIsTransactionTimeoutSet) {
int timeout = (int) (mTransactionTimeout - (System.currentTimeMillis() / 1000));
if (timeout <= 0) {
throw new QueryEvaluationException("Transaction timeout expired"); //$NON-NLS-1$
}
else {
stmt.setQueryTimeout(timeout);
}
}
}
private void setFetchSize(PreparedStatement stmt) throws SQLException, QueryEvaluationException
{
if (mIsTransactionFetchSizeSet) {
if (mTransactionFetchSize <= 0) {
throw new QueryEvaluationException("Invalid fetch size: " + mTransactionFetchSize); //$NON-NLS-1$
}
else if (mTransactionFetchSize == 1) { // streaming
stmt.setFetchSize(Integer.MIN_VALUE);
}
else {
stmt.setFetchSize(mTransactionFetchSize);
}
}
}
private void setMaxRows(PreparedStatement stmt) throws SQLException, QueryEvaluationException
{
if (mIsTransactionMaxRowsSet) {
if (mTransactionMaxRows <= 0) {
throw new QueryEvaluationException("Invalid max rows size: " + mTransactionMaxRows); //$NON-NLS-1$
}
else {
stmt.setMaxRows(mTransactionMaxRows);
}
}
}
@Override
public void closeQueryStatement(PreparedStatement ps, ResultSet rs) throws SQLException
{
mStatementsToClose.remove(ps);
if (rs != null) {
mResultSetsToClose.remove(rs);
}
try {
if (rs != null) {
rs.close();
}
}
finally {
closeQueryStatement(ps);
}
}
private void closeQueryStatement(PreparedStatement ps) throws SQLException
{
try {
if (ps.getMaxRows() != 0) {
ps.setMaxRows(0);
}
if ( ps.getQueryTimeout() != 0 ) ps.setQueryTimeout(0);
}
catch (Exception e) {
LOG.warn("Exception occurred when clearing max rows or query timeout", e); //$NON-NLS-1$
return;
}
finally {
closedPreparedStatement(ps);
}
}
private void closedPreparedStatement(PreparedStatement ps) throws SQLException
{
ps.close();
}
@Override
public ResultSet getResultSet(PreparedStatement ps) throws SQLException
{
ResultSet rs = ps.executeQuery();
mResultSetsToClose.add(rs);
return rs;
}
public void releaseResources()
{
Iterator<ResultSet> iter = mResultSetsToClose.iterator();
while (iter.hasNext()) {
try {
iter.next().close();
}
catch (SQLException e) {
LOG.warn("Could not close a JDBC result set", e); //$NON-NLS-1$
}
}
mResultSetsToClose.clear();
Iterator<PreparedStatement> iter2 = mStatementsToClose.iterator();
while (iter2.hasNext()) {
try {
closeQueryStatement(iter2.next());
}
catch (SQLException e) {
LOG.warn("Could not close a JDBC statement", e); //$NON-NLS-1$
}
}
mStatementsToClose.clear();
}
@Override
public void setTransactionTimeout(int seconds)
{
if (seconds > 0) {
mIsTransactionTimeoutSet = true;
mTransactionTimeout = System.currentTimeMillis() / 1000 + seconds;
}
}
@Override
public void unsetTransactionTimeout()
{
mIsTransactionTimeoutSet = false;
}
@Override
public void setTransactionFetchSize(int fetchSize)
{
if (fetchSize > 0) {
mIsTransactionFetchSizeSet = true;
mTransactionFetchSize = fetchSize;
}
}
@Override
public void unsetTransactionFetchSize()
{
mIsTransactionFetchSizeSet = false;
}
@Override
public void setTransactionMaxRows(int maxRows)
{
if (maxRows > 0) {
mIsTransactionMaxRowsSet = true;
mTransactionMaxRows = maxRows;
}
}
@Override
public void unsetTransactionMaxRows()
{
mIsTransactionMaxRowsSet = false;
}
public boolean hasOpenResources()
{
return mResultSetsToClose.size() > 0 || mStatementsToClose.size() > 0;
}
}