001package org.itsallcode.jdbc;
002
003import java.sql.*;
004import java.util.Objects;
005
006import org.itsallcode.jdbc.dialect.DbDialect;
007import org.itsallcode.jdbc.resultset.*;
008
009/**
010 * Simple wrapper for a JDBC {@link PreparedStatement}.
011 */
012public class SimplePreparedStatement implements AutoCloseable {
013    private final Context context;
014    private final DbDialect dialect;
015    private final PreparedStatement statement;
016    private final String sql;
017
018    SimplePreparedStatement(final Context context, final DbDialect dialect, final PreparedStatement statement,
019            final String sql) {
020        this.context = Objects.requireNonNull(context, "context");
021        this.dialect = Objects.requireNonNull(dialect, "dialect");
022        this.statement = Objects.requireNonNull(statement, "statement");
023        this.sql = Objects.requireNonNull(sql, "sql");
024    }
025
026    <T> SimpleResultSet<T> executeQuery(final ContextRowMapper<T> rowMapper) {
027        final ResultSet resultSet = doExecuteQuery();
028        final ResultSet convertingResultSet = ConvertingResultSet.create(dialect, resultSet);
029        return new SimpleResultSet<>(context, convertingResultSet, rowMapper, this);
030    }
031
032    private ResultSet doExecuteQuery() {
033        try {
034            return statement.executeQuery();
035        } catch (final SQLException e) {
036            throw new UncheckedSQLException("Error executing query '" + sql + "'", e);
037        }
038    }
039
040    /**
041     * @see PreparedStatement#executeUpdate()
042     */
043    int executeUpdate() {
044        try {
045            return statement.executeUpdate();
046        } catch (final SQLException e) {
047            throw new UncheckedSQLException("Error executing statement '" + sql + "'", e);
048        }
049    }
050
051    @Override
052    public void close() {
053        try {
054            statement.close();
055        } catch (final SQLException e) {
056            throw new UncheckedSQLException("Error closing statement", e);
057        }
058    }
059
060    /**
061     * Set the values for the prepared statement.
062     * 
063     * @param preparedStatementSetter prepared statement setter
064     */
065    public void setValues(final PreparedStatementSetter preparedStatementSetter) {
066        try {
067            preparedStatementSetter.setValues(statement);
068        } catch (final SQLException e) {
069            throw new UncheckedSQLException("Error setting values for prepared statement", e);
070        }
071    }
072
073    /**
074     * Execute the batch statement.
075     * 
076     * @return array of update counts
077     * @see Statement#executeBatch()
078     */
079    public int[] executeBatch() {
080        try {
081            return statement.executeBatch();
082        } catch (final SQLException e) {
083            throw new UncheckedSQLException("Error executing batch sql '" + sql + "'", e);
084        }
085    }
086
087    /**
088     * Add the current set of parameters to the batch.
089     * 
090     * @see PreparedStatement#addBatch()
091     */
092    public void addBatch() {
093        try {
094            this.statement.addBatch();
095        } catch (final SQLException e) {
096            throw new UncheckedSQLException("Error adding batch", e);
097        }
098    }
099
100    SimpleParameterMetaData getParameterMetadata() {
101        try {
102            return SimpleParameterMetaData.create(statement.getParameterMetaData());
103        } catch (final SQLException e) {
104            throw new UncheckedSQLException("Error getting parameter metadata", e);
105        }
106    }
107
108    /**
109     * Get the underlying {@link PreparedStatement}.
110     * 
111     * @return the underlying {@link PreparedStatement}
112     */
113    public PreparedStatement getStatement() {
114        return statement;
115    }
116}