View Javadoc
1   package com.atlassian.dbexporter.jdbc;
2   
3   import com.atlassian.activeobjects.spi.ConnectionHandler;
4   import com.atlassian.activeobjects.spi.ImportExportException;
5   import com.atlassian.dbexporter.ConnectionProvider;
6   import com.atlassian.dbexporter.ImportExportErrorService;
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   
10  import java.sql.Connection;
11  import java.sql.DatabaseMetaData;
12  import java.sql.PreparedStatement;
13  import java.sql.ResultSet;
14  import java.sql.SQLException;
15  import java.sql.Statement;
16  
17  /**
18   * Convenience methods for dealing with JDBC resources.
19   *
20   * @author Erik van Zijst
21   */
22  public final class JdbcUtils {
23      private static final Logger LOGGER = LoggerFactory.getLogger(JdbcUtils.class);
24  
25      public static <T> T withConnection(ImportExportErrorService errorService, ConnectionProvider provider, JdbcCallable<T> callable) {
26          Connection connection = null;
27          try {
28              connection = provider.getConnection();
29              return callable.call(ConnectionHandler.newInstance(connection, new ConnectionHandler.Closeable() {
30                  @Override
31                  public void close() throws SQLException {
32                      // do nothing
33                  }
34              }));
35          } catch (SQLException e) {
36              throw errorService.newImportExportSqlException(null, "", e);
37          } finally {
38              closeQuietly(connection);
39          }
40      }
41  
42      /**
43       * Executes callable with no autoCommit.
44       * <p>
45       * E.g. PostgreSQL requires autoCommit to be off for batchSize to take effect.
46       */
47      public static <T> T withNoAutoCommit(ImportExportErrorService errorService, Connection connection, JdbcCallable<T> callable) {
48          try {
49              final boolean autoCommit = connection.getAutoCommit();
50              connection.setAutoCommit(false);
51              try {
52                  return callable.call(connection);
53              } finally {
54                  connection.setAutoCommit(autoCommit);
55              }
56          } catch (SQLException e) {
57              throw errorService.newImportExportSqlException(null, "", e);
58          }
59      }
60  
61      /**
62       * Closes the specified {@link java.sql.ResultSet}, swallowing any {@link java.sql.SQLException}.
63       *
64       * @param resultSet
65       */
66      public static void closeQuietly(ResultSet resultSet) {
67          if (resultSet != null) {
68              try {
69                  resultSet.close();
70              } catch (SQLException se) {
71                  LOGGER.warn("ResultSet close threw exception", se);
72              }
73          }
74      }
75  
76      /**
77       * Closes the specified {@link java.sql.Statement}, swallowing any {@link SQLException}.
78       *
79       * @param statements the list of statements to close
80       */
81      public static void closeQuietly(Statement... statements) {
82          for (Statement statement : statements) {
83              closeQuietly(statement);
84          }
85      }
86  
87      private static void closeQuietly(Statement statement) {
88          if (statement != null) {
89              try {
90                  statement.close();
91              } catch (SQLException se) {
92                  LOGGER.warn("Statement close threw exception", se);
93              }
94          }
95      }
96  
97      /**
98       * Closes the specified {@link java.sql.Connection}, swallowing any {@link SQLException}.
99       *
100      * @param connection
101      */
102     public static void closeQuietly(Connection connection) {
103         if (connection != null) {
104             try {
105                 connection.close();
106             } catch (SQLException se) {
107                 LOGGER.warn("Connection close threw exception", se);
108             }
109         }
110     }
111 
112     /**
113      * Closes the specified {@link ResultSet} and {@link Statement}, swallowing any {@link SQLException}.
114      *
115      * @param resultSet
116      * @param statement
117      */
118     public static void closeQuietly(ResultSet resultSet, Statement statement) {
119         closeQuietly(resultSet);
120         closeQuietly(statement);
121     }
122 
123     /**
124      * Quotes the database identifier if needed.
125      *
126      * @param errorService
127      * @param table
128      * @param connection   the current connection being used
129      * @param identifier   the database identifier to quote   @return the quoted database identifier
130      * @throws ImportExportException if anything wrong happens getting information from the database connection.
131      */
132     public static String quote(ImportExportErrorService errorService, String table, Connection connection, String identifier) {
133         final String quoteString = identifierQuoteString(errorService, table, connection).trim();
134         return new StringBuilder(identifier.length() + 2 * quoteString.length())
135                 .append(quoteString).append(identifier).append(quoteString).toString();
136     }
137 
138     private static String identifierQuoteString(ImportExportErrorService errorService, String table, Connection connection) {
139         try {
140             return metadata(errorService, connection).getIdentifierQuoteString();
141         } catch (SQLException e) {
142             throw errorService.newImportExportSqlException(table, "", e);
143         }
144     }
145 
146     public static DatabaseMetaData metadata(ImportExportErrorService errorService, Connection connection) {
147         try {
148             return connection.getMetaData();
149         } catch (SQLException e) {
150             throw errorService.newImportExportSqlException(null, "", e);
151         }
152     }
153 
154     public static Statement createStatement(ImportExportErrorService errorService, String table, Connection connection) {
155         try {
156             return connection.createStatement();
157         } catch (SQLException e) {
158             throw errorService.newImportExportSqlException(table, "Could not create statement from connection", e);
159         }
160     }
161 
162     public static PreparedStatement preparedStatement(ImportExportErrorService errorService, String table, Connection connection, String sql) {
163         try {
164             return connection.prepareStatement(sql);
165         } catch (SQLException e) {
166             throw errorService.newImportExportSqlException(table, "Could not create prepared statement for SQL query, [" + sql + "]", e);
167         }
168     }
169 
170     public interface JdbcCallable<T> {
171         T call(Connection connection);
172     }
173 }