All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.hive.jdbc.HiveQueryResultSet Maven / Gradle / Ivy
/*
* 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.hive.jdbc;
import static org.apache.hive.service.rpc.thrift.TCLIServiceConstants.TYPE_NAMES;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.hadoop.hive.common.type.HiveDecimal;
import org.apache.hive.service.cli.RowSet;
import org.apache.hive.service.cli.RowSetFactory;
import org.apache.hive.service.cli.TableSchema;
import org.apache.hive.service.rpc.thrift.TCLIService;
import org.apache.hive.service.rpc.thrift.TCLIServiceConstants;
import org.apache.hive.service.rpc.thrift.TCloseOperationReq;
import org.apache.hive.service.rpc.thrift.TCloseOperationResp;
import org.apache.hive.service.rpc.thrift.TColumnDesc;
import org.apache.hive.service.rpc.thrift.TFetchOrientation;
import org.apache.hive.service.rpc.thrift.TFetchResultsReq;
import org.apache.hive.service.rpc.thrift.TFetchResultsResp;
import org.apache.hive.service.rpc.thrift.TGetOperationStatusResp;
import org.apache.hive.service.rpc.thrift.TGetResultSetMetadataReq;
import org.apache.hive.service.rpc.thrift.TGetResultSetMetadataResp;
import org.apache.hive.service.rpc.thrift.TOperationHandle;
import org.apache.hive.service.rpc.thrift.TPrimitiveTypeEntry;
import org.apache.hive.service.rpc.thrift.TProtocolVersion;
import org.apache.hive.service.rpc.thrift.TRowSet;
import org.apache.hive.service.rpc.thrift.TTableSchema;
import org.apache.hive.service.rpc.thrift.TTypeQualifierValue;
import org.apache.hive.service.rpc.thrift.TTypeQualifiers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HiveQueryResultSet.
*
*/
public class HiveQueryResultSet extends HiveBaseResultSet {
public static final Logger LOG = LoggerFactory.getLogger(HiveQueryResultSet.class);
private TCLIService.Iface client;
private TOperationHandle stmtHandle;
private int maxRows;
private int fetchSize;
private int rowsFetched = 0;
private RowSet fetchedRows;
private Iterator fetchedRowsItr;
private boolean isClosed = false;
private boolean emptyResultSet = false;
private boolean isScrollable = false;
private boolean fetchFirst = false;
private TGetOperationStatusResp operationStatus = null;
private final TProtocolVersion protocol;
public static class Builder {
private final Connection connection;
private final Statement statement;
private TCLIService.Iface client = null;
private TOperationHandle stmtHandle = null;
/**
* Sets the limit for the maximum number of rows that any ResultSet object produced by this
* Statement can contain to the given number. If the limit is exceeded, the excess rows
* are silently dropped. The value must be >= 0, and 0 means there is not limit.
*/
private int maxRows = 0;
private boolean retrieveSchema = true;
private List colNames;
private List colTypes;
private List colAttributes;
private int fetchSize = 50;
private boolean emptyResultSet = false;
private boolean isScrollable = false;
public Builder(Statement statement) throws SQLException {
this.statement = statement;
this.connection = statement.getConnection();
}
public Builder(Connection connection) {
this.statement = null;
this.connection = connection;
}
public Builder setClient(TCLIService.Iface client) {
this.client = client;
return this;
}
public Builder setStmtHandle(TOperationHandle stmtHandle) {
this.stmtHandle = stmtHandle;
return this;
}
public Builder setMaxRows(int maxRows) {
this.maxRows = maxRows;
return this;
}
public Builder setSchema(List colNames, List colTypes) {
// no column attributes provided - create list of null attributes.
List colAttributes =
Collections.nCopies(colTypes.size(), null);
return setSchema(colNames, colTypes, colAttributes);
}
public Builder setSchema(List colNames, List colTypes,
List colAttributes) {
this.colNames = new ArrayList<>(colNames);
this.colTypes = new ArrayList<>(colTypes);
this.colAttributes = new ArrayList<>(colAttributes);
this.retrieveSchema = false;
return this;
}
public Builder setFetchSize(int fetchSize) {
this.fetchSize = fetchSize;
return this;
}
public Builder setEmptyResultSet(boolean emptyResultSet) {
this.emptyResultSet = emptyResultSet;
return this;
}
public Builder setScrollable(boolean setScrollable) {
this.isScrollable = setScrollable;
return this;
}
public HiveQueryResultSet build() throws SQLException {
return new HiveQueryResultSet(this);
}
public TProtocolVersion getProtocolVersion() throws SQLException {
return ((HiveConnection)connection).getProtocol();
}
}
protected HiveQueryResultSet(Builder builder) throws SQLException {
this.statement = builder.statement;
this.client = builder.client;
this.stmtHandle = builder.stmtHandle;
this.fetchSize = builder.fetchSize;
columnNames = new ArrayList();
normalizedColumnNames = new ArrayList();
columnTypes = new ArrayList();
columnAttributes = new ArrayList();
if (builder.retrieveSchema) {
retrieveSchema();
} else {
this.setSchema(builder.colNames, builder.colTypes, builder.colAttributes);
}
this.emptyResultSet = builder.emptyResultSet;
this.maxRows = builder.maxRows;
if (builder.emptyResultSet) {
this.maxRows = 0;
}
this.isScrollable = builder.isScrollable;
this.protocol = builder.getProtocolVersion();
}
/**
* Generate ColumnAttributes object from a TTypeQualifiers
* @param primitiveTypeEntry primitive type
* @return generated ColumnAttributes, or null
*/
private static JdbcColumnAttributes getColumnAttributes(
TPrimitiveTypeEntry primitiveTypeEntry) {
JdbcColumnAttributes ret = null;
if (primitiveTypeEntry.isSetTypeQualifiers()) {
TTypeQualifiers tq = primitiveTypeEntry.getTypeQualifiers();
switch (primitiveTypeEntry.getType()) {
case CHAR_TYPE:
case VARCHAR_TYPE:
TTypeQualifierValue val =
tq.getQualifiers().get(TCLIServiceConstants.CHARACTER_MAXIMUM_LENGTH);
if (val != null) {
// precision is char length
ret = new JdbcColumnAttributes(val.getI32Value(), 0);
}
break;
case DECIMAL_TYPE:
TTypeQualifierValue prec = tq.getQualifiers().get(TCLIServiceConstants.PRECISION);
TTypeQualifierValue scale = tq.getQualifiers().get(TCLIServiceConstants.SCALE);
ret = new JdbcColumnAttributes(prec == null ? HiveDecimal.USER_DEFAULT_PRECISION : prec.getI32Value(),
scale == null ? HiveDecimal.USER_DEFAULT_SCALE : scale.getI32Value());
break;
default:
break;
}
}
return ret;
}
/**
* Retrieve schema from the server
*/
private void retrieveSchema() throws SQLException {
try {
TGetResultSetMetadataReq metadataReq = new TGetResultSetMetadataReq(stmtHandle);
// TODO need session handle
TGetResultSetMetadataResp metadataResp;
metadataResp = client.GetResultSetMetadata(metadataReq);
Utils.verifySuccess(metadataResp.getStatus());
TTableSchema schema = metadataResp.getSchema();
if (schema == null || !schema.isSetColumns()) {
// TODO: should probably throw an exception here.
return;
}
setSchema(new TableSchema(schema));
for (final TColumnDesc column : schema.getColumns()) {
String columnName = column.getColumnName();
columnNames.add(columnName);
normalizedColumnNames.add(columnName.toLowerCase());
TPrimitiveTypeEntry primitiveTypeEntry =
column.getTypeDesc().getTypes().get(0).getPrimitiveEntry();
String columnTypeName = TYPE_NAMES.get(primitiveTypeEntry.getType());
columnTypes.add(columnTypeName);
columnAttributes.add(getColumnAttributes(primitiveTypeEntry));
}
} catch (SQLException eS) {
throw eS; // rethrow the SQLException as is
} catch (Exception ex) {
throw new SQLException("Could not create ResultSet: " + ex.getMessage(), ex);
}
}
/**
* Set the specified schema to the resultset
* @param colNames
* @param colTypes
*/
private void setSchema(List colNames, List colTypes,
List colAttributes) {
columnNames.addAll(colNames);
columnTypes.addAll(colTypes);
columnAttributes.addAll(colAttributes);
colNames.forEach(i -> normalizedColumnNames.add(i.toLowerCase()));
}
@Override
public void close() throws SQLException {
if (this.statement != null && (this.statement instanceof HiveStatement)) {
/*
* HIVE-25203: Be aware that a ResultSet is not supposed to control its parent Statement's
* lifecycle, so before adding any logic into this branch, make sure if it's really correct.
* One known exception is Statement#closeOnCompletion, which is part of the Statement API.
*/
HiveStatement s = (HiveStatement) this.statement;
s.closeOnResultSetCompletion();
} else {
// for those stmtHandle passed from HiveDatabaseMetaData instead of Statement
closeOperationHandle(stmtHandle);
}
// Need reset during re-open when needed
client = null;
stmtHandle = null;
isClosed = true;
operationStatus = null;
}
private void closeOperationHandle(TOperationHandle stmtHandle) throws SQLException {
try {
if (stmtHandle != null) {
TCloseOperationReq closeReq = new TCloseOperationReq(stmtHandle);
TCloseOperationResp closeResp = client.CloseOperation(closeReq);
Utils.verifySuccessWithInfo(closeResp.getStatus());
}
} catch (SQLException e) {
throw e;
} catch (Exception e) {
throw new SQLException(e.toString(), "08S01", e);
}
}
/**
* Moves the cursor down one row from its current position.
*
* @see java.sql.ResultSet#next()
* @throws SQLException
* if a database access error occurs.
*/
public boolean next() throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
if (emptyResultSet || (maxRows > 0 && rowsFetched >= maxRows)) {
return false;
}
/*
* Poll on the operation status, till the operation is complete.
* We need to wait only for HiveStatement to complete.
* HiveDatabaseMetaData which also uses this ResultSet returns only after the RPC is complete.
*/
// when isHasResultSet is set, the query transitioned from running -> complete and is not expected go back to
// running state when fetching results (implicit state transition)
if ((statement instanceof HiveStatement) && (operationStatus == null || !operationStatus.isHasResultSet())) {
operationStatus = ((HiveStatement) statement).waitForOperationToComplete();
}
try {
TFetchOrientation orientation = TFetchOrientation.FETCH_NEXT;
if (fetchFirst) {
// If we are asked to start from beginning, clear the current fetched resultset
orientation = TFetchOrientation.FETCH_FIRST;
fetchedRows = null;
fetchedRowsItr = null;
fetchFirst = false;
}
if (fetchedRows == null || !fetchedRowsItr.hasNext()) {
TFetchResultsReq fetchReq = new TFetchResultsReq(stmtHandle,
orientation, fetchSize);
LOG.debug("HiveQueryResultsFetchReq: {}", fetchReq);
TFetchResultsResp fetchResp;
fetchResp = client.FetchResults(fetchReq);
Utils.verifySuccessWithInfo(fetchResp.getStatus());
TRowSet results = fetchResp.getResults();
fetchedRows = RowSetFactory.create(results, protocol);
fetchedRowsItr = fetchedRows.iterator();
}
if (!fetchedRowsItr.hasNext()) {
return false;
}
row = fetchedRowsItr.next();
rowsFetched++;
} catch (SQLException eS) {
throw eS;
} catch (Exception ex) {
throw new SQLException("Error retrieving next row", ex);
}
// NOTE: fetchOne doesn't throw new SQLFeatureNotSupportedException("Method not supported").
return true;
}
@Override
public ResultSetMetaData getMetaData() throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
return super.getMetaData();
}
@Override
public void setFetchSize(int rows) throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
fetchSize = rows;
}
@Override
public int getType() throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
if (isScrollable) {
return ResultSet.TYPE_SCROLL_INSENSITIVE;
}
return ResultSet.TYPE_FORWARD_ONLY;
}
@Override
public int getFetchSize() throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
return fetchSize;
}
public T getObject(String columnLabel, Class type) throws SQLException {
//JDK 1.7
throw new SQLFeatureNotSupportedException("Method not supported");
}
public T getObject(int columnIndex, Class type) throws SQLException {
//JDK 1.7
throw new SQLFeatureNotSupportedException("Method not supported");
}
/**
* Moves the cursor before the first row of the resultset.
*
* @see java.sql.ResultSet#next()
* @throws SQLException
* if a database access error occurs.
*/
@Override
public void beforeFirst() throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
if (!isScrollable) {
throw new SQLException("Method not supported for TYPE_FORWARD_ONLY resultset");
}
fetchFirst = true;
rowsFetched = 0;
}
@Override
public boolean isBeforeFirst() throws SQLException {
if (isClosed) {
throw new SQLException("Resultset is closed");
}
return (rowsFetched == 0);
}
@Override
public int getRow() throws SQLException {
return rowsFetched;
}
@Override
public boolean isClosed() {
return isClosed;
}
}