3 * Copyright © 2013 František Kučera (frantovo.cz)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 package info.globalcode.sql.dk;
19 import static info.globalcode.sql.dk.jmx.ConnectionManagement.incrementCounter;
20 import static info.globalcode.sql.dk.jmx.ConnectionManagement.resetCounter;
21 import info.globalcode.sql.dk.batch.Batch;
22 import info.globalcode.sql.dk.batch.BatchException;
23 import info.globalcode.sql.dk.configuration.DatabaseDefinition;
24 import info.globalcode.sql.dk.configuration.Loader;
25 import info.globalcode.sql.dk.configuration.Properties;
26 import info.globalcode.sql.dk.formatting.ColumnsHeader;
27 import info.globalcode.sql.dk.formatting.Formatter;
28 import info.globalcode.sql.dk.jmx.ConnectionManagement;
29 import info.globalcode.sql.dk.jmx.ConnectionManagement.COUNTER;
30 import java.sql.Connection;
31 import java.sql.PreparedStatement;
32 import java.sql.ResultSet;
33 import java.sql.SQLException;
34 import java.sql.SQLWarning;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
39 * Represents connected database. Is derived from {@linkplain DatabaseDefinition}.
40 * Wraps {@linkplain Connection}.
42 * Is responsible for executing {@linkplain SQLCommand} and passing results to the
43 * {@linkplain Formatter}.
45 * @author Ing. František Kučera (frantovo.cz)
47 public class DatabaseConnection implements AutoCloseable {
49 private static final Logger log = Logger.getLogger(DatabaseConnection.class.getName());
50 public static final String JDBC_PROPERTY_USER = "user";
51 public static final String JDBC_PROPERTY_PASSWORD = "password";
52 private final DatabaseDefinition databaseDefinition;
53 private final Connection connection;
54 private final Properties properties;
56 * Could be null = JMX is disabled → must check, see functions in
57 * {@linkplain ConnectionManagement}
59 private final ConnectionManagement connectionMBean;
63 * @param databaseDefinition DB url, name, password etc.
64 * @param properties additional properties from CLI
65 * @param connectionMBean JMX management bean | null = disabled JMX reporting
66 * @throws SQLException
68 public DatabaseConnection(DatabaseDefinition databaseDefinition, Properties properties, ConnectionManagement connectionMBean) throws SQLException {
69 this.databaseDefinition = databaseDefinition;
70 this.properties = properties;
71 this.connectionMBean = connectionMBean;
72 this.connection = Loader.jdbcConnect(databaseDefinition, properties);
75 public void executeQuery(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
76 formatter.writeStartBatch();
77 formatter.writeStartDatabase(databaseDefinition);
78 formatter.writeStartStatement();
79 formatter.writeQuery(sqlCommand.getQuery());
80 formatter.writeParameters(sqlCommand.getParameters());
81 processCommand(sqlCommand, formatter);
82 formatter.writeEndStatement();
83 formatter.writeEndDatabase();
84 formatter.writeEndBatch();
87 public void executeBatch(Batch batch, Formatter formatter) throws SQLException, BatchException {
88 formatter.writeStartBatch();
89 formatter.writeStartDatabase(databaseDefinition);
90 while (batch.hasNext()) {
91 SQLCommand sqlCommand = batch.next();
92 formatter.writeStartStatement();
93 formatter.writeQuery(sqlCommand.getQuery());
94 formatter.writeParameters(sqlCommand.getParameters());
95 processCommand(sqlCommand, formatter);
96 formatter.writeEndStatement();
98 formatter.writeEndDatabase();
99 formatter.writeEndBatch();
102 private void processCommand(SQLCommand sqlCommand, Formatter formatter) throws SQLException {
103 incrementCounter(connectionMBean, COUNTER.COMMAND);
104 resetCounter(connectionMBean, COUNTER.RECORD_CURRENT);
106 try (PreparedStatement ps = sqlCommand.prepareStatement(connection)) {
107 log.log(Level.FINE, "Statement prepared");
108 sqlCommand.parametrize(ps);
110 boolean isRS = ps.execute();
111 log.log(Level.FINE, "Statement executed");
113 try (ResultSet rs = ps.getResultSet()) {
114 processResultSet(rs, formatter);
117 processUpdateResult(ps, formatter);
121 while (ps.getMoreResults() || ps.getUpdateCount() > -1) {
122 ResultSet rs = ps.getResultSet();
124 processUpdateResult(ps, formatter);
126 processResultSet(rs, formatter);
134 private void processUpdateResult(PreparedStatement ps, Formatter formatter) throws SQLException {
135 formatter.writeUpdatesResult(ps.getUpdateCount());
138 private void processResultSet(ResultSet rs, Formatter formatter) throws SQLException {
139 formatter.writeStartResultSet(new ColumnsHeader(rs.getMetaData()));
141 int columnCount = rs.getMetaData().getColumnCount();
144 incrementCounter(connectionMBean, COUNTER.RECORD_CURRENT);
145 incrementCounter(connectionMBean, COUNTER.RECORD_TOTAL);
147 formatter.writeStartRow();
149 for (int i = 1; i <= columnCount; i++) {
150 formatter.writeColumnValue(rs.getObject(i));
153 formatter.writeEndRow();
156 formatter.writeEndResultSet();
159 private void logWarnings(PreparedStatement ps) throws SQLException {
160 SQLWarning w = ps.getWarnings();
162 log.log(Level.WARNING, "SQL: {0}", w.getLocalizedMessage());
163 w = w.getNextWarning();
169 * Tests if this connection is live.
171 * @return true if test was successful
172 * @throws SQLException if test fails
174 public boolean test() throws SQLException {
175 connection.getAutoCommit();
179 public String getProductName() throws SQLException {
180 return connection.getMetaData().getDatabaseProductName();
183 public String getProductVersion() throws SQLException {
184 return connection.getMetaData().getDatabaseProductVersion();
188 public void close() throws SQLException {