From ecf89bf444bf971c3b31fc2c1b0a76d16d166a92 Mon Sep 17 00:00:00 2001 From: Anna Koskinen Date: Thu, 31 Jan 2013 16:45:21 +0200 Subject: [PATCH] Merge of (#10582) to Vaadin 7. Ensure SQL connections etc. of FreeformQuery are closed. Change-Id: I5488510ef7d752e8e743408e0f60acf483e45fc1 --- .../sqlcontainer/query/FreeformQuery.java | 160 +++++++++++++----- 1 file changed, 114 insertions(+), 46 deletions(-) diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java b/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java index 2b539ecf99..299183f5e6 100644 --- a/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java +++ b/server/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java @@ -117,20 +117,23 @@ public class FreeformQuery implements QueryDelegate { int count = countByDelegate(); if (count < 0) { // Couldn't use the delegate, use the bad way. + Statement statement = null; + ResultSet rs = null; Connection conn = getConnection(); - Statement statement = conn.createStatement( - ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY); + try { + statement = conn.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); - ResultSet rs = statement.executeQuery(queryString); - if (rs.last()) { - count = rs.getRow(); - } else { - count = 0; + rs = statement.executeQuery(queryString); + if (rs.last()) { + count = rs.getRow(); + } else { + count = 0; + } + } finally { + releaseConnection(conn, statement, rs); } - rs.close(); - statement.close(); - releaseConnection(conn); } return count; } @@ -146,17 +149,18 @@ public class FreeformQuery implements QueryDelegate { try { StatementHelper sh = ((FreeformStatementDelegate) delegate) .getCountStatement(); + PreparedStatement pstmt = null; + ResultSet rs = null; Connection c = getConnection(); - PreparedStatement pstmt = c.prepareStatement(sh - .getQueryString()); - sh.setParameterValuesToStatement(pstmt); - ResultSet rs = pstmt.executeQuery(); - rs.next(); - count = rs.getInt(1); - rs.close(); - pstmt.clearParameters(); - pstmt.close(); - releaseConnection(c); + try { + pstmt = c.prepareStatement(sh.getQueryString()); + sh.setParameterValuesToStatement(pstmt); + rs = pstmt.executeQuery(); + rs.next(); + count = rs.getInt(1); + } finally { + releaseConnection(c, pstmt, rs); + } return count; } catch (UnsupportedOperationException e) { // Count statement generation not supported @@ -166,15 +170,18 @@ public class FreeformQuery implements QueryDelegate { try { String countQuery = delegate.getCountQuery(); if (countQuery != null) { + Statement statement = null; + ResultSet rs = null; Connection conn = getConnection(); - Statement statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(countQuery); - rs.next(); - count = rs.getInt(1); - rs.close(); - statement.close(); - releaseConnection(conn); - return count; + try { + statement = conn.createStatement(); + rs = statement.executeQuery(countQuery); + rs.next(); + count = rs.getInt(1); + return count; + } finally { + releaseConnection(conn, statement, rs); + } } } catch (UnsupportedOperationException e) { // Count query generation not supported @@ -201,7 +208,7 @@ public class FreeformQuery implements QueryDelegate { * @see FreeformQueryDelegate#getQueryString(int, int) */ @Override - @SuppressWarnings("deprecation") + @SuppressWarnings({ "deprecation", "finally" }) public ResultSet getResults(int offset, int pagelength) throws SQLException { if (activeConnection == null) { throw new SQLException("No active transaction!"); @@ -228,7 +235,18 @@ public class FreeformQuery implements QueryDelegate { } } Statement statement = activeConnection.createStatement(); - ResultSet rs = statement.executeQuery(query); + ResultSet rs; + try { + rs = statement.executeQuery(query); + } catch (SQLException e) { + try { + statement.close(); + } finally { + // throw the original exception even if closing the statement + // fails + throw e; + } + } return rs; } @@ -436,17 +454,19 @@ public class FreeformQuery implements QueryDelegate { try { StatementHelper sh = ((FreeformStatementDelegate) delegate) .getContainsRowQueryStatement(keys); + + PreparedStatement pstmt = null; + ResultSet rs = null; Connection c = getConnection(); - PreparedStatement pstmt = c.prepareStatement(sh - .getQueryString()); - sh.setParameterValuesToStatement(pstmt); - ResultSet rs = pstmt.executeQuery(); - contains = rs.next(); - rs.close(); - pstmt.clearParameters(); - pstmt.close(); - releaseConnection(c); - return contains; + try { + pstmt = c.prepareStatement(sh.getQueryString()); + sh.setParameterValuesToStatement(pstmt); + rs = pstmt.executeQuery(); + contains = rs.next(); + return contains; + } finally { + releaseConnection(c, pstmt, rs); + } } catch (UnsupportedOperationException e) { // Statement generation not supported, continue... } @@ -459,15 +479,15 @@ public class FreeformQuery implements QueryDelegate { } else { query = modifyWhereClause(keys); } + Statement statement = null; + ResultSet rs = null; Connection conn = getConnection(); try { - Statement statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(query); + statement = conn.createStatement(); + rs = statement.executeQuery(query); contains = rs.next(); - rs.close(); - statement.close(); } finally { - releaseConnection(conn); + releaseConnection(conn, statement, rs); } return contains; } @@ -484,6 +504,54 @@ public class FreeformQuery implements QueryDelegate { } } + /** + * Closes a statement and a resultset, then releases the connection if it is + * not part of an active transaction. A failure in closing one of the + * parameters does not prevent closing the rest. + * + * If the statement is a {@link PreparedStatement}, its parameters are + * cleared prior to closing the statement. + * + * Although JDBC specification does state that closing a statement closes + * its result set and closing a connection closes statements and result + * sets, this method does try to close the result set and statement + * explicitly whenever not null. This can guard against bugs in certain JDBC + * drivers and reduce leaks in case e.g. closing the result set succeeds but + * closing the statement or connection fails. + * + * @param conn + * the connection to release + * @param statement + * the statement to close, may be null to skip closing + * @param rs + * the result set to close, may be null to skip closing + * @throws SQLException + * if closing the result set or the statement fails + */ + private void releaseConnection(Connection conn, Statement statement, + ResultSet rs) throws SQLException { + try { + try { + if (null != rs) { + rs.close(); + } + } finally { + if (null != statement) { + if (statement instanceof PreparedStatement) { + try { + ((PreparedStatement) statement).clearParameters(); + } catch (Exception e) { + // will be closed below anyway + } + } + statement.close(); + } + } + } finally { + releaseConnection(conn); + } + } + private String modifyWhereClause(Object... keys) { // Build the where rules for the provided keys StringBuffer where = new StringBuffer(); -- 2.39.5