/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.metamodel.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.metamodel.MetaModelException; import org.apache.metamodel.data.AbstractDataSet; import org.apache.metamodel.data.DefaultRow; import org.apache.metamodel.data.Row; import org.apache.metamodel.jdbc.dialects.DefaultQueryRewriter; import org.apache.metamodel.jdbc.dialects.IQueryRewriter; import org.apache.metamodel.query.Query; import org.apache.metamodel.query.SelectItem; import org.apache.metamodel.schema.Column; import org.apache.metamodel.util.FileHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DataSet implementation that wraps a JDBC resultset. */ final class JdbcDataSet extends AbstractDataSet { private static final Logger logger = LoggerFactory.getLogger(JdbcDataSet.class); private final JdbcCompiledQuery _compiledQuery; private final JdbcCompiledQueryLease _lease; private final Statement _statement; private final ResultSet _resultSet; private final JdbcDataContext _jdbcDataContext; private final Connection _connection; private Row _row; private boolean _closed; /** * Constructor used for regular query execution. * * @param query * @param jdbcDataContext * @param connection * @param statement * @param resultSet */ public JdbcDataSet(Query query, JdbcDataContext jdbcDataContext, Connection connection, Statement statement, ResultSet resultSet) { super(query.getSelectClause().getItems()); if (query == null || statement == null || resultSet == null) { throw new IllegalArgumentException("Arguments cannot be null"); } _jdbcDataContext = jdbcDataContext; _connection = connection; _statement = statement; _resultSet = resultSet; _closed = false; _compiledQuery = null; _lease = null; } /** * Constructor used for compiled query execution * * @param query * @param jdbcDataContext * @param resultSet */ public JdbcDataSet(JdbcCompiledQuery compiledQuery, JdbcCompiledQueryLease lease, ResultSet resultSet) { super(compiledQuery.getSelectItems()); if (compiledQuery == null || lease == null || resultSet == null) { throw new IllegalArgumentException("Arguments cannot be null"); } _compiledQuery = compiledQuery; _lease = lease; _jdbcDataContext = null; _connection = null; _statement = null; _resultSet = resultSet; _closed = false; } /** * {@inheritDoc} */ @Override public Row getRow() { return _row; } /** * {@inheritDoc} */ @Override public boolean next() throws MetaModelException { try { boolean result = _resultSet.next(); if (result) { Object[] values = new Object[getHeader().size()]; for (int i = 0; i < values.length; i++) { values[i] = getValue(_resultSet, i); try { // some drivers return boxed primitive types in stead of // nulls (such as false in stead of null for a Boolean // column) if (_resultSet.wasNull()) { values[i] = null; } } catch (Exception e) { logger.debug("Could not invoke wasNull() method on resultset, error message: {}", e .getMessage()); } } _row = new DefaultRow(getHeader(), values); } else { _row = null; } return result; } catch (SQLException e) { throw JdbcUtils.wrapException(e, "get next record in resultset"); } } private Object getValue(ResultSet resultSet, int i) throws SQLException { final SelectItem selectItem = getHeader().getSelectItem(i); final int columnIndex = i + 1; if (selectItem.getAggregateFunction() == null) { final Column column = selectItem.getColumn(); if (column != null) { final IQueryRewriter queryRewriter; if (_jdbcDataContext == null) { queryRewriter = new DefaultQueryRewriter(null); } else { queryRewriter = _jdbcDataContext.getQueryRewriter(); } return queryRewriter.getResultSetValue(resultSet, columnIndex, column); } } return resultSet.getObject(columnIndex); } /** * {@inheritDoc} */ @Override public void close() { if (_closed) { return; } FileHelper.safeClose(_resultSet); if (_jdbcDataContext != null) { FileHelper.safeClose(_statement); _jdbcDataContext.close(_connection); } if (_compiledQuery != null) { _compiledQuery.returnLease(_lease); } _closed = true; } @Override protected void finalize() throws Throwable { super.finalize(); if (!_closed) { logger.warn("finalize() invoked, but DataSet is not closed. Invoking close() on {}", this); close(); } } }