blob: 63a88fedef361f7cdcaf7ad0a51990a808658f14 [file] [log] [blame]
/*
* Copyright (c) 2013, 2015 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.net4j.internal.db;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBUtil;
import org.eclipse.net4j.db.IDBConnection;
import org.eclipse.net4j.db.IDBPreparedStatement;
import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability;
import org.eclipse.net4j.db.IDBSchemaTransaction;
import org.eclipse.net4j.db.jdbc.DelegatingConnection;
import org.eclipse.net4j.util.CheckUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeMap;
/**
* @author Eike Stepper
*/
public final class DBConnection extends DelegatingConnection implements IDBConnection
{
private final TreeMap<String, DBPreparedStatement> cache = new TreeMap<String, DBPreparedStatement>();
private final Set<DBPreparedStatement> checkOuts = new HashSet<DBPreparedStatement>();
private final DBDatabase database;
private int lastTouch;
private boolean closed;
public DBConnection(DBDatabase database, Connection delegate)
{
super(delegate);
this.database = database;
try
{
delegate.setAutoCommit(false);
}
catch (SQLException ex)
{
throw new DBException(ex, "SET AUTO COMMIT = false");
}
}
public DBDatabase getDatabase()
{
return database;
}
public String getUserID()
{
return database.getUserID();
}
@Override
public void close()
{
DBUtil.close(getDelegate());
// System.out.println("-- Open connections: " + --COUNT);
closed = true;
database.closeConnection(this);
}
@Override
public boolean isClosed()
{
return closed;
}
public IDBSchemaTransaction openSchemaTransaction()
{
DBSchemaTransaction schemaTransaction = database.openSchemaTransaction();
schemaTransaction.setConnection(this);
return schemaTransaction;
}
@Override
@Deprecated
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException
{
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
{
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{
throw new UnsupportedOperationException();
}
public IDBPreparedStatement prepareStatement(String sql, ReuseProbability reuseProbability)
{
return prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, reuseProbability);
}
public IDBPreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
ReuseProbability reuseProbability)
{
database.beginSchemaAccess(false);
DBPreparedStatement preparedStatement;
synchronized (this)
{
preparedStatement = cache.remove(sql);
if (preparedStatement == null)
{
try
{
PreparedStatement delegate = getDelegate().prepareStatement(sql, resultSetType, resultSetConcurrency);
preparedStatement = new DBPreparedStatement(this, sql, reuseProbability, delegate);
}
catch (SQLException ex)
{
throw new DBException(ex);
}
}
checkOuts.add(preparedStatement);
}
return preparedStatement;
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException
{
return prepareStatement(sql, ReuseProbability.LOW);
}
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
{
return prepareStatement(sql, resultSetType, resultSetConcurrency, ReuseProbability.LOW);
}
public void releasePreparedStatement(DBPreparedStatement preparedStatement)
{
try
{
if (preparedStatement == null)
{
// Bug 276926: Silently accept preparedStatement == null and do nothing.
return;
}
synchronized (this)
{
checkOuts.remove(preparedStatement);
preparedStatement.setTouch(++lastTouch);
String sql = preparedStatement.getSQL();
if (cache.put(sql, preparedStatement) != null)
{
throw new IllegalStateException(sql + " already in cache"); //$NON-NLS-1$
}
if (cache.size() > database.getStatementCacheCapacity())
{
DBPreparedStatement old = cache.remove(cache.firstKey());
DBUtil.close(old.getDelegate());
}
}
}
finally
{
database.endSchemaAccess();
}
}
public void invalidateStatementCache()
{
synchronized (this)
{
CheckUtil.checkState(checkOuts.isEmpty(), "Statements are checked out: " + checkOuts);
// Close all statements in the cache, then clear the cache.
for (DBPreparedStatement preparedStatement : cache.values())
{
PreparedStatement delegate = preparedStatement.getDelegate();
DBUtil.close(delegate);
}
cache.clear();
}
}
public String convertString(DBPreparedStatement preparedStatement, int parameterIndex, String value)
{
return getDatabase().convertString(preparedStatement, parameterIndex, value);
}
public String convertString(DBResultSet resultSet, int columnIndex, String value)
{
return getDatabase().convertString(resultSet, columnIndex, value);
}
public String convertString(DBResultSet resultSet, String columnLabel, String value)
{
return getDatabase().convertString(resultSet, columnLabel, value);
}
}