Skip to content

Commit

Permalink
[GEOT-4061] EPSG HSQL factories cannot recover from connection corrup…
Browse files Browse the repository at this point in the history
…tion

git-svn-id: http://svn.osgeo.org/geotools/trunk@38767 e5c1c795-43da-0310-a71f-fac65c449510
  • Loading branch information
aaime committed May 27, 2012
1 parent d163165 commit 083d0d1
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 33 deletions.
Expand Up @@ -107,12 +107,6 @@ final class AuthorityCodes extends AbstractSet<String> implements Serializable {
*/
private transient PreparedStatement querySingle;

/**
* The connection to the underlying database.
*/
private Connection connection;


/**
* The collection's size, or a negative value if not yet computed. The records will be counted
* only when first needed. The special value -2 if set by {@link #isEmpty} if the size has not
Expand Down Expand Up @@ -164,30 +158,48 @@ public AuthorityCodes(final TableInfo table,
buffer.append(hasWhere ? " AND " : " WHERE ").append(table.codeColumn).append(" = ?");
sqlSingle = factory.adaptSQL(buffer.toString());
}

protected PreparedStatement validateStatement(PreparedStatement stmt, String sql) throws SQLException {
Connection conn = null;
if (stmt != null) {
try {
conn = stmt.getConnection();
} catch (SQLException sqle) {
// mark this invalid
stmt = null;
}
}
if(conn != null && !factory.isConnectionValid(conn)) {
stmt = null;
}
if (stmt == null) {
stmt = factory.getConnection().prepareStatement(sql);
}
return stmt;
}

/**
* Returns all codes.
*/
private ResultSet getAll() throws SQLException {
assert Thread.holdsLock(this);
if (queryAll != null && factory.isConnectionValid(queryAll.getConnection())) {
try {
return queryAll.executeQuery();
} catch (SQLException ignore) {
/*
* Failed to reuse an existing statement. This problem occurs in some occasions
* with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle").
* I'm not sure where the bug come from (didn't noticed it when using HSQL). We
* will try again with a new statement created in the code after this 'catch'
* clause. Note that we set 'queryAll' to null first in case of failure during
* the 'prepareStatement(...)' execution.
*/
queryAll.close();
queryAll = null;
recoverableException("getAll", ignore);
}
queryAll = validateStatement(queryAll, sqlAll);
try {
return queryAll.executeQuery();
} catch (SQLException ignore) {
/*
* Failed to reuse an existing statement. This problem occurs in some occasions
* with the JDBC-ODBC bridge in Java 6 (the error message is "Invalid handle").
* I'm not sure where the bug come from (didn't noticed it when using HSQL). We
* will try again with a new statement created in the code after this 'catch'
* clause. Note that we set 'queryAll' to null first in case of failure during
* the 'prepareStatement(...)' execution.
*/
queryAll.close();
queryAll = null;
recoverableException("getAll", ignore);
}
queryAll = factory.getConnection().prepareStatement(sqlAll);
queryAll = validateStatement(queryAll, sqlAll);
return queryAll.executeQuery();
}

Expand All @@ -196,9 +208,7 @@ private ResultSet getAll() throws SQLException {
*/
private ResultSet getSingle(final Object code) throws SQLException {
assert Thread.holdsLock(this);
if (querySingle == null || !factory.isConnectionValid(querySingle.getConnection())) {
querySingle = factory.getConnection().prepareStatement(sqlSingle);
}
querySingle = validateStatement(querySingle, sqlSingle);
querySingle.setString(1, code.toString());
return querySingle.executeQuery();
}
Expand Down
Expand Up @@ -711,14 +711,21 @@ private PreparedStatement prepareStatement(final String key, final String sql)
{
assert Thread.holdsLock(this);
PreparedStatement stmt = statements.get(key);
if(stmt != null && !isConnectionValid(stmt.getConnection()))
Connection conn = null;
if (stmt != null) {
try {
conn = stmt.getConnection();
} catch (SQLException sqle) {
// mark this invalid
stmt = null;
}
}
if(conn != null && !isConnectionValid(conn))
stmt = null;
if (stmt == null) {
stmt = getConnection().prepareStatement(adaptSQL(sql));
statements.put(key, stmt);
} else {

}
}
return stmt;
}

Expand Down Expand Up @@ -3188,7 +3195,7 @@ protected synchronized Connection getConnection() throws SQLException {
if (connection == null) {
connection = dataSource.getConnection();
} else {
if(!isConnectionValid(connection)) {
if(connection.isClosed() || !isConnectionValid(connection)) {
statements.clear();
try {
// we need to send back the connection to the eventual
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.sql.SQLException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import javax.sql.DataSource;

// Geotools dependencies
import org.geotools.factory.Hints;
Expand Down Expand Up @@ -53,7 +54,11 @@ final class FactoryUsingHSQL extends FactoryUsingAnsiSQL {
public FactoryUsingHSQL(final Hints hints, final Connection connection) {
super(hints, connection);
}


public FactoryUsingHSQL(final Hints hints, final DataSource dataSource) {
super(hints, dataSource);
}

/**
* If the query contains a "FROM (" expression, remove the parenthesis.
*/
Expand Down
Expand Up @@ -326,7 +326,7 @@ protected AbstractAuthorityFactory createBackingStore(final Hints hints) throws
}

}
FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource().getConnection());
FactoryUsingHSQL factory = new FactoryUsingHSQL(hints, getDataSource());
factory.setValidationQuery("CALL NOW()");
return factory;
}
Expand Down
Expand Up @@ -16,6 +16,7 @@
*/
package org.geotools.referencing.factory.epsg;

import java.lang.reflect.Method;
import static org.junit.Assert.*;

import java.util.Set;
Expand Down Expand Up @@ -63,6 +64,31 @@ public void setUp() throws Exception {
if( finder == null ){
finder = factory.getIdentifiedObjectFinder(CoordinateReferenceSystem.class);
}
corruptConnection();
}

@Test
public void testConnectionCorruption() throws Exception {
corruptConnection();
CRS.decode("EPSG:4326");
}

@Test
public void testConnectionCorruptionListAll() throws Exception {
Set<String> original = CRS.getSupportedCodes("EPSG");
assertTrue(original.size() > 4000);
corruptConnection();
Set<String> afterCorruption = CRS.getSupportedCodes("EPSG");
assertEquals(original, afterCorruption);
}

private void corruptConnection() throws Exception {
java.lang.reflect.Field field = org.geotools.referencing.factory.BufferedAuthorityFactory.class.getDeclaredField("backingStore");
field.setAccessible(true);
Object def = field.get(factory);
Method getConnection = DirectEpsgFactory.class.getDeclaredMethod("getConnection");
java.sql.Connection conn = (java.sql.Connection) getConnection.invoke( def );
conn.close();
}

@Test
Expand Down

0 comments on commit 083d0d1

Please sign in to comment.