package com.thinkbiganalytics.hive.service;
/*-
* #%L
* thinkbig-thrift-proxy-core
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed 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.
* #L%
*/
import com.thinkbiganalytics.discovery.model.DefaultDatabaseMetadata;
import com.thinkbiganalytics.discovery.model.DefaultField;
import com.thinkbiganalytics.discovery.model.DefaultTableSchema;
import com.thinkbiganalytics.discovery.schema.DatabaseMetadata;
import com.thinkbiganalytics.discovery.schema.Field;
import com.thinkbiganalytics.discovery.schema.TableSchema;
import com.thinkbiganalytics.jdbc.util.DatabaseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.stereotype.Service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.sql.DataSource;
/**
*/
@Service("hiveMetastoreService")
public class HiveMetastoreService {
private static final Logger log = LoggerFactory.getLogger(HiveMetastoreService.class);
@Inject
@Qualifier("hiveMetatoreJdbcTemplate")
private JdbcTemplate hiveMetatoreJdbcTemplate;
private DatabaseType metastoreDatabaseType = null;
public DataSource getDataSource() {
return hiveMetatoreJdbcTemplate.getDataSource();
}
private DatabaseType getMetastoreDatabaseType() {
if (metastoreDatabaseType == null) {
try {
metastoreDatabaseType = DatabaseType.fromMetaData(getDataSource());
return metastoreDatabaseType;
} catch (MetaDataAccessException e) {
log.error("Unable to determine Metastore Database Type. Using default type of " + DatabaseType.MYSQL + ". " + e.getMessage(), e);
}
return DatabaseType.MYSQL;
}
return metastoreDatabaseType;
}
public List<DatabaseMetadata> getTableColumns(List<String> tablesFilter) throws DataAccessException {
String query = "SELECT d.NAME as \"DATABASE_NAME\", t.TBL_NAME, c.COLUMN_NAME "
+ "FROM COLUMNS_V2 c "
+ "JOIN SDS s on s.CD_ID = c.CD_ID "
+ "JOIN TBLS t ON s.SD_ID = t.SD_ID "
+ "JOIN DBS d on d.DB_ID = t.DB_ID "
+ "ORDER BY d.NAME, t.TBL_NAME";
if (DatabaseType.POSTGRES.equals(getMetastoreDatabaseType())) {
query = "SELECT d.\"NAME\" as \"DATABASE_NAME\", t.\"TBL_NAME\", c.\"COLUMN_NAME\" "
+ "FROM \"COLUMNS_V2\" c "
+ "JOIN \"SDS\" s on s.\"CD_ID\" = c.\"CD_ID\" "
+ "JOIN \"TBLS\" t ON s.\"SD_ID\" = t.\"SD_ID\" "
+ "JOIN \"DBS\" d on d.\"DB_ID\" = t.\"DB_ID\" "
+ "ORDER BY d.\"NAME\", t.\"TBL_NAME\"";
}
List<DatabaseMetadata> metadata = hiveMetatoreJdbcTemplate.query(query, new RowMapper<DatabaseMetadata>() {
@Override
public DatabaseMetadata mapRow(ResultSet rs, int i) throws SQLException {
DefaultDatabaseMetadata row = new DefaultDatabaseMetadata();
row.setDatabaseName(rs.getString("DATABASE_NAME"));
row.setColumnName(rs.getString("COLUMN_NAME"));
row.setTableName(rs.getString("TBL_NAME"));
return row;
}
});
return tablesFilter == null ? metadata : filterDatabaseMetadata(metadata, tablesFilter);
}
private List<DatabaseMetadata> filterDatabaseMetadata(List<DatabaseMetadata> allTables, List<String> tablesFilter) {
List<DatabaseMetadata> results = new ArrayList<>();
allTables.forEach(metadata -> {
if (tablesFilter.contains(metadata.getDatabaseName() + "." + metadata.getTableName())) {
results.add(metadata);
}
});
return results;
}
public List<String> getAllTables() throws DataAccessException {
String query = "SELECT d.NAME as \"DATABASE_NAME\", t.TBL_NAME FROM TBLS t JOIN DBS d on d.DB_ID = t.DB_ID ORDER BY d.NAME, t.TBL_NAME";
if (DatabaseType.POSTGRES.equals(getMetastoreDatabaseType())) {
query = "SELECT d.\"NAME\" as \"DATABASE_NAME\", t.\"TBL_NAME\" FROM \"TBLS\" t JOIN \"DBS\" d on d.\"DB_ID\" = t.\"DB_ID\" ORDER BY d.\"NAME\", t.\"TBL_NAME\"";
}
List<String> allTables = hiveMetatoreJdbcTemplate.query(query, new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int i) throws SQLException {
String dbName = rs.getString("DATABASE_NAME");
String tableName = rs.getString("TBL_NAME");
return dbName + "." + tableName;
}
});
return allTables;
}
public List<TableSchema> getTableSchemas() throws DataAccessException {
String query = "SELECT d.NAME as \"DATABASE_NAME\", t.TBL_NAME, c.COLUMN_NAME c.TYPE_NAME "
+ "FROM COLUMNS_V2 c "
+ "JOIN SDS s on s.CD_ID = c.CD_ID "
+ "JOIN TBLS t ON s.SD_ID = t.SD_ID "
+ "JOIN DBS d on d.DB_ID = t.DB_ID "
+ "ORDER BY d.NAME, t.TBL_NAME";
if (DatabaseType.POSTGRES.equals(getMetastoreDatabaseType())) {
query = "SELECT d.\"NAME\" as \"DATABASE_NAME\", t.\"TBL_NAME\", c.\"COLUMN_NAME\",c.\"TYPE_NAME\" "
+ "FROM \"COLUMNS_V2\" c "
+ "JOIN \"SDS\" s on s.\"CD_ID\" = c.\"CD_ID\" "
+ "JOIN \"TBLS\" t ON s.\"SD_ID\" = t.\"SD_ID\" "
+ "JOIN \"DBS\" d on d.\"DB_ID\" = t.\"DB_ID\" ";
}
final List<TableSchema> metadata = new ArrayList<>();
final Map<String, Map<String, TableSchema>> databaseTables = new HashMap<>();
hiveMetatoreJdbcTemplate.query(query, new RowMapper<Object>() {
@Override
public TableSchema mapRow(ResultSet rs, int i) throws SQLException {
String dbName = rs.getString("DATABASE_NAME");
String columnName = rs.getString("COLUMN_NAME");
String tableName = rs.getString("TBL_NAME");
String columnType = rs.getString("TYPE_NAME");
if (!databaseTables.containsKey(dbName)) {
databaseTables.put(dbName, new HashMap<String, TableSchema>());
}
Map<String, TableSchema> tables = databaseTables.get(dbName);
if (!tables.containsKey(tableName)) {
DefaultTableSchema schema = new DefaultTableSchema();
schema.setName(tableName);
schema.setSchemaName(dbName);
schema.setFields(new ArrayList<Field>());
tables.put(tableName, schema);
metadata.add(schema);
}
TableSchema schema = tables.get(tableName);
DefaultField field = new DefaultField();
field.setName(columnName);
field.setNativeDataType(columnType);
field.setDerivedDataType(columnType);
schema.getFields().add(field);
return schema;
}
});
return metadata;
}
}