/** * 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.tajo.catalog.store; import com.google.protobuf.InvalidProtocolBufferException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.tajo.catalog.CatalogConstants; import org.apache.tajo.catalog.CatalogUtil; import org.apache.tajo.catalog.FunctionDesc; import org.apache.tajo.catalog.exception.CatalogException; import org.apache.tajo.catalog.proto.CatalogProtos; import org.apache.tajo.catalog.proto.CatalogProtos.*; import org.apache.tajo.common.TajoDataTypes.Type; import org.apache.tajo.exception.InternalException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public abstract class AbstractDBStore extends CatalogConstants implements CatalogStore { protected final Log LOG = LogFactory.getLog(getClass()); protected Configuration conf; protected String connectionId; protected String connectionPassword; protected String catalogUri; private Connection conn; protected Map<String, Boolean> baseTableMaps = new HashMap<String, Boolean>(); protected static final int VERSION = 1; protected abstract String getCatalogDriverName(); protected abstract Connection createConnection(final Configuration conf) throws SQLException; protected abstract boolean isInitialized() throws CatalogException; protected abstract void createBaseTable() throws CatalogException; protected abstract void dropBaseTable() throws CatalogException; public AbstractDBStore(Configuration conf) throws InternalException { this.conf = conf; if(conf.get(CatalogConstants.DEPRECATED_CATALOG_URI) != null) { LOG.warn("Configuration parameter " + CatalogConstants.DEPRECATED_CATALOG_URI + " " + "is deprecated. Use " + CatalogConstants.CATALOG_URI + " instead."); this.catalogUri = conf.get(CatalogConstants.DEPRECATED_CATALOG_URI); } else { this.catalogUri = conf.get(CatalogConstants.CATALOG_URI); } if(conf.get(CatalogConstants.DEPRECATED_CONNECTION_ID) != null) { LOG.warn("Configuration parameter " + CatalogConstants.DEPRECATED_CONNECTION_ID + " " + "is deprecated. Use " + CatalogConstants.CONNECTION_ID + " instead."); this.connectionId = conf.get(CatalogConstants.DEPRECATED_CONNECTION_ID); } else { this.connectionId = conf.get(CatalogConstants.CONNECTION_ID); } if(conf.get(CatalogConstants.DEPRECATED_CONNECTION_PASSWORD) != null) { LOG.warn("Configuration parameter " + CatalogConstants.DEPRECATED_CONNECTION_PASSWORD + " " + "is deprecated. Use " + CatalogConstants.CONNECTION_PASSWORD + " instead."); this.connectionPassword = conf.get(CatalogConstants.DEPRECATED_CONNECTION_PASSWORD); } else { this.connectionPassword = conf.get(CatalogConstants.CONNECTION_PASSWORD); } String catalogDriver = getCatalogDriverName(); try { Class.forName(getCatalogDriverName()).newInstance(); LOG.info("Loaded the Catalog driver (" + catalogDriver + ")"); } catch (Exception e) { throw new CatalogException("Cannot load Catalog driver " + catalogDriver, e); } try { LOG.info("Trying to connect database (" + catalogUri + ")"); conn = createConnection(conf); LOG.info("Connected to database (" + catalogUri + ")"); } catch (SQLException e) { throw new CatalogException("Cannot connect to database (" + catalogUri + ")", e); } try { if (!isInitialized()) { try { createBaseTable(); LOG.info("The base tables of CatalogServer are created."); } catch (CatalogException ce) { dropBaseTable(); throw ce; } } else { LOG.info("The base tables of CatalogServer already is initialized."); } } catch (Exception se) { throw new CatalogException( "Cannot initialize the persistent storage of Catalog", se); } // int dbVersion = 0; try { // dbVersion = needUpgrade(); needUpgrade(); } catch (Exception e) { throw new CatalogException( "Cannot check if the DB need to be upgraded.", e); } // if (dbVersion < VERSION) { // LOG.info("DB Upgrade is needed"); // try { // upgrade(dbVersion, VERSION); // } catch (SQLException e) { // LOG.error(e.getMessage()); // throw new InternalException("DB upgrade is failed.", e); // } // } } protected String getCatalogUri(){ return catalogUri; } public Connection getConnection() { try { boolean isValid = conn.isValid(100); if (!isValid) { CatalogUtil.closeQuietly(conn); conn = createConnection(conf); } } catch (SQLException e) { e.printStackTrace(); } return conn; } private int needUpgrade() throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; ResultSet res = null; int retValue = -1; try { StringBuilder sql = new StringBuilder(); sql.delete(0, sql.length()); sql.append("SELECT VERSION FROM "); sql.append(TB_META); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); res = pstmt.executeQuery(); if (!res.next()) { // if this db version is 0 insertVersion(); retValue = 0; } else { retValue = res.getInt(1); } } catch (SQLException e) { throw new CatalogException(e); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return retValue; } private void insertVersion() throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO "); sql.append(TB_META); sql.append(" values (0)"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.executeUpdate(); } catch (SQLException e) { throw new CatalogException(e); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } private void upgrade(int from, int to) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { if (from == 0) { if (to == 1) { StringBuilder sql = new StringBuilder(); sql.append(" DROP INDEX idx_options_key"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.executeUpdate(); pstmt.close(); sql.delete(0, sql.length()); sql.append(" CREATE INDEX idx_options_key on ").append(TB_OPTIONS); sql.append(" (").append(C_TABLE_ID).append(")"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.executeUpdate(); LOG.info("DB Upgraded from " + from + " to " + to); } else { LOG.info("DB Upgraded from " + from + " to " + to); } } } catch (SQLException e) { throw new CatalogException(e); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public void addTable(final CatalogProtos.TableDescProto table) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; ResultSet res = null; try { conn = getConnection(); conn.setAutoCommit(false); String tableName = table.getId().toLowerCase(); String sql = String.format("INSERT INTO %s (%s, path, store_type) VALUES(?, ?, ?) ", TB_TABLES, C_TABLE_ID); if (LOG.isDebugEnabled()) { LOG.debug(sql); } pstmt = conn.prepareStatement(sql); pstmt.setString(1, tableName); pstmt.setString(2, table.getPath()); pstmt.setString(3, table.getMeta().getStoreType().name()); pstmt.executeUpdate(); pstmt.close(); String tidSql = String.format("SELECT TID from %s WHERE %s = ?", TB_TABLES, C_TABLE_ID); pstmt = conn.prepareStatement(tidSql); pstmt.setString(1, tableName); res = pstmt.executeQuery(); if (!res.next()) { throw new CatalogException("ERROR: there is no tid matched to " + table.getId()); } int tid = res.getInt("TID"); res.close(); pstmt.close(); String colSql = String.format("INSERT INTO %s (TID, %s, column_id, column_name, data_type, type_length)" + " VALUES(?, ?, ?, ?, ?, ?) ", TB_COLUMNS, C_TABLE_ID); if (LOG.isDebugEnabled()) { LOG.debug(sql); } pstmt = conn.prepareStatement(colSql); for(int i = 0; i < table.getSchema().getFieldsCount(); i++) { ColumnProto col = table.getSchema().getFields(i); pstmt.setInt(1, tid); pstmt.setString(2, tableName); pstmt.setInt(3, i); pstmt.setString(4, CatalogUtil.extractSimpleName(col.getName())); pstmt.setString(5, col.getDataType().getType().name()); pstmt.setInt(6, (col.getDataType().hasLength() ? col.getDataType().getLength() : 0)); pstmt.addBatch(); pstmt.clearParameters(); } pstmt.executeBatch(); pstmt.close(); if(table.getMeta().hasParams()) { String optSql = String.format("INSERT INTO %s (%s, key_, value_) VALUES(?, ?, ?)", TB_OPTIONS, C_TABLE_ID); if (LOG.isDebugEnabled()) { LOG.debug(optSql); } pstmt = conn.prepareStatement(optSql); for (CatalogProtos.KeyValueProto entry : table.getMeta().getParams().getKeyvalList()) { pstmt.setString(1, tableName); pstmt.setString(2, entry.getKey()); pstmt.setString(3, entry.getValue()); pstmt.addBatch(); pstmt.clearParameters(); } pstmt.executeBatch(); pstmt.close(); } if (table.hasStats()) { String statSql = String.format("INSERT INTO %s (%s, num_rows, num_bytes) VALUES(?, ?, ?)", TB_STATISTICS, C_TABLE_ID); if (LOG.isDebugEnabled()) { LOG.debug(statSql); } pstmt = conn.prepareStatement(statSql); pstmt.setString(1, tableName); pstmt.setLong(2, table.getStats().getNumRows()); pstmt.setLong(3, table.getStats().getNumBytes()); pstmt.executeUpdate(); pstmt.close(); } if(table.hasPartition()) { String partSql = String.format("INSERT INTO %s (%s, partition_type, expression, expression_schema) VALUES(?, ?, ?, ?)", TB_PARTITION_METHODS, C_TABLE_ID); if (LOG.isDebugEnabled()) { LOG.debug(partSql); } pstmt = conn.prepareStatement(partSql); pstmt.setString(1, tableName); pstmt.setString(2, table.getPartition().getPartitionType().name()); pstmt.setString(3, table.getPartition().getExpression()); pstmt.setBytes(4, table.getPartition().getExpressionSchema().toByteArray()); pstmt.executeUpdate(); } // If there is no error, commit the changes. conn.commit(); } catch (SQLException se) { try { // If there is any error, rollback the changes. conn.rollback(); } catch (SQLException se2) { } throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } } @Override public boolean existTable(final String name) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; ResultSet res = null; boolean exist = false; try { StringBuilder sql = new StringBuilder(); sql.append(" SELECT ").append(C_TABLE_ID); sql.append(" FROM ").append(TB_TABLES); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); res = pstmt.executeQuery(); exist = res.next(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return exist; } @Override public void deleteTable(final String name) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { conn = getConnection(); conn.setAutoCommit(false); StringBuilder sql = new StringBuilder(); sql.append("DELETE FROM ").append(TB_COLUMNS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); pstmt.executeUpdate(); pstmt.close(); sql.delete(0, sql.length()); sql.append("DELETE FROM ").append(TB_OPTIONS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); pstmt.executeUpdate(); pstmt.close(); sql.delete(0, sql.length()); sql.append("DELETE FROM ").append(TB_STATISTICS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); pstmt.executeUpdate(); pstmt.close(); sql.delete(0, sql.length()); sql.append("DELETE FROM ").append(TB_PARTTIONS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); pstmt.executeUpdate(); pstmt.close(); sql.delete(0, sql.length()); sql.append("DELETE FROM ").append(TB_TABLES); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); pstmt.executeUpdate(); // If there is no error, commit the changes. conn.commit(); } catch (SQLException se) { try { // If there is any error, rollback the changes. conn.rollback(); } catch (SQLException se2) { } throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public CatalogProtos.TableDescProto getTable(final String name) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; CatalogProtos.TableDescProto.Builder tableBuilder = null; StoreType storeType = null; try { tableBuilder = CatalogProtos.TableDescProto.newBuilder(); StringBuilder sql = new StringBuilder(); sql.append(" SELECT ").append(C_TABLE_ID).append(", path, store_type"); sql.append(" from ").append(TB_TABLES); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); res = pstmt.executeQuery(); if (!res.next()) { // there is no table of the given name. return null; } tableBuilder.setId(res.getString(C_TABLE_ID).trim()); tableBuilder.setPath(res.getString("path").trim()); storeType = CatalogUtil.getStoreType(res.getString("store_type").trim()); res.close(); pstmt.close(); CatalogProtos.SchemaProto.Builder schemaBuilder = CatalogProtos.SchemaProto.newBuilder(); sql.delete(0, sql.length()); sql.append(" SELECT column_name, data_type, type_length "); sql.append(" from ").append(TB_COLUMNS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); sql.append("ORDER by column_id asc"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); res = pstmt.executeQuery(); while (res.next()) { schemaBuilder.addFields(resultToColumnProto(res)); } tableBuilder.setSchema(CatalogUtil.getQualfiedSchema(name, schemaBuilder.build())); res.close(); pstmt.close(); CatalogProtos.TableProto.Builder metaBuilder = CatalogProtos.TableProto.newBuilder(); metaBuilder.setStoreType(storeType); sql.delete(0, sql.length()); sql.append(" SELECT key_, value_ "); sql.append(" from ").append(TB_OPTIONS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); res = pstmt.executeQuery(); metaBuilder.setParams(resultToKeyValueSetProto(res)); tableBuilder.setMeta(metaBuilder); res.close(); pstmt.close(); sql.delete(0, sql.length()); sql.append(" SELECT num_rows, num_bytes "); sql.append(" from ").append(TB_STATISTICS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); res = pstmt.executeQuery(); if (res.next()) { TableStatsProto.Builder statBuilder = TableStatsProto.newBuilder(); statBuilder.setNumRows(res.getLong("num_rows")); statBuilder.setNumBytes(res.getLong("num_bytes")); tableBuilder.setStats(statBuilder); } res.close(); pstmt.close(); sql.delete(0, sql.length()); sql.append(" SELECT partition_type, expression, expression_schema "); sql.append(" from ").append(TB_PARTITION_METHODS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, name); res = pstmt.executeQuery(); if (res.next()) { tableBuilder.setPartition(resultToPartitionMethodProto(name, res)); } } catch (InvalidProtocolBufferException e) { throw new CatalogException(e); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return tableBuilder.build(); } private ColumnProto getColumn(String tableName, int tid, String columnId) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append(" SELECT column_name, data_type, type_length"); sql.append(" FROM ").append(TB_COLUMNS); sql.append(" WHERE TID = ? "); sql.append(" AND column_id = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setInt(1, tid); pstmt.setInt(2, Integer.parseInt(columnId)); res = pstmt.executeQuery(); if (res.next()) { return resultToColumnProto(res); } } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return null; } private Type getDataType(final String typeStr) { try { return Enum.valueOf(Type.class, typeStr); } catch (IllegalArgumentException iae) { LOG.error("Cannot find a matched type aginst from '" + typeStr + "'"); return null; } } @Override public List<String> getAllTableNames() throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; ResultSet res = null; List<String> tables = new ArrayList<String>(); try { StringBuilder sql = new StringBuilder(); sql.append("SELECT "); sql.append(C_TABLE_ID); sql.append(" from "); sql.append(TB_TABLES); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); res = pstmt.executeQuery(); while (res.next()) { tables.add(res.getString(C_TABLE_ID).trim()); } } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return tables; } @Override public void addPartitions(CatalogProtos.PartitionsProto partitionsProto) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO "); sql.append(TB_PARTTIONS); sql.append(" ("); sql.append(C_TABLE_ID); sql.append(", partition_name, ordinal_position, path, cache_nodes) "); sql.append("VALUES (?, ?, ?, ?, ?, ?) "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); for (CatalogProtos.PartitionDescProto proto : partitionsProto.getPartitionList()) { pstmt.setString(1, proto.getTableId()); pstmt.setString(2, proto.getPartitionName()); pstmt.setInt(3, proto.getOrdinalPosition()); pstmt.setString(4, proto.getPartitionValue()); pstmt.setString(5, proto.getPath()); pstmt.addBatch(); pstmt.clearParameters(); } pstmt.executeBatch(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public void addPartitionMethod(CatalogProtos.PartitionMethodProto proto) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO "); sql.append(TB_PARTITION_METHODS); sql.append( " ("); sql.append(C_TABLE_ID); sql.append(", partition_type, expression, expression_schema) "); sql.append("VALUES (?, ?, ?, ?) "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, proto.getTableId().toLowerCase()); pstmt.setString(2, proto.getPartitionType().name()); pstmt.setString(3, proto.getExpression()); pstmt.setBytes(4, proto.getExpressionSchema().toByteArray()); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public void delPartitionMethod(String tableName) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append(" DELETE FROM ").append(TB_PARTITION_METHODS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public CatalogProtos.PartitionMethodProto getPartitionMethod(String tableName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append(" SELECT partition_type, expression, expression_schema"); sql.append(" FROM ").append(TB_PARTITION_METHODS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); res = pstmt.executeQuery(); if (res.next()) { return resultToPartitionMethodProto(tableName, res); } } catch (InvalidProtocolBufferException e) { throw new CatalogException(e); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return null; } @Override public boolean existPartitionMethod(String tableName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; boolean exist = false; try { StringBuilder sql = new StringBuilder(); sql.append(" SELECT partition_type, expression, expression_schema"); sql.append(" FROM ").append(TB_PARTITION_METHODS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); res = pstmt.executeQuery(); exist = res.next(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return exist; } @Override public void addPartition(CatalogProtos.PartitionDescProto proto) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO "); sql.append(TB_PARTTIONS); sql.append(" ("); sql.append(C_TABLE_ID); sql.append(", partition_method_id, partition_name, ordinal_position, path, cache_nodes) "); sql.append("VALUES (?, ?, ?, ?, ?, ?, ?) "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, proto.getTableId().toLowerCase()); pstmt.setString(2, proto.getPartitionName().toLowerCase()); pstmt.setInt(3, proto.getOrdinalPosition()); pstmt.setString(4, proto.getPartitionValue()); pstmt.setString(5, proto.getPath()); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public CatalogProtos.PartitionDescProto getPartition(String partitionName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; CatalogProtos.PartitionDescProto proto = null; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT "); sql.append(C_TABLE_ID); sql.append(", partition_name, ordinal_position, partition_value, path, cache_nodes FROM "); sql.append(TB_PARTTIONS); sql.append("where partition_name = ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, partitionName); res = pstmt.executeQuery(); if (!res.next()) { throw new CatalogException("ERROR: there is no index matched to " + partitionName); } proto = resultToPartitionDescProto(res); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return proto; } @Override public CatalogProtos.PartitionsProto getPartitions(String tableName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; CatalogProtos.PartitionsProto proto = null; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT "); sql.append(C_TABLE_ID); sql.append(", partition_name, ordinal_position, partition_value, path, cache_nodes FROM "); sql.append(TB_PARTTIONS); sql.append("where "); sql.append(C_TABLE_ID); sql.append(" = ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } // PARTITIONS conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); res = pstmt.executeQuery(); CatalogProtos.PartitionsProto.Builder builder = CatalogProtos.PartitionsProto.newBuilder(); while(res.next()) { builder.addPartition(resultToPartitionDescProto(res)); } proto = builder.build(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return proto; } @Override public void delPartition(String partitionName) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append(" DELETE FROM ").append(TB_PARTTIONS); sql.append(" WHERE partition_name = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, partitionName); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public void delPartitions(String tableName) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append(" DELETE FROM ").append(TB_PARTTIONS); sql.append(" WHERE ").append(C_TABLE_ID).append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public void addIndex(final IndexDescProto proto) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append("INSERT INTO indexes (index_name, "); sql.append(C_TABLE_ID); sql.append(", column_name, "); sql.append("data_type, index_type, is_unique, is_clustered, is_ascending) VALUES "); sql.append("(?,?,?,?,?,?,?,?)"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, proto.getName()); pstmt.setString(2, proto.getTableId()); pstmt.setString(3, CatalogUtil.extractSimpleName(proto.getColumn().getName())); pstmt.setString(4, proto.getColumn().getDataType().getType().name()); pstmt.setString(5, proto.getIndexMethod().toString()); pstmt.setBoolean(6, proto.hasIsUnique() && proto.getIsUnique()); pstmt.setBoolean(7, proto.hasIsClustered() && proto.getIsClustered()); pstmt.setBoolean(8, proto.hasIsAscending() && proto.getIsAscending()); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public void delIndex(final String indexName) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; try { StringBuilder sql = new StringBuilder(); sql.append(" DELETE FROM ").append(TB_INDEXES); sql.append(" WHERE index_name ").append(" = ? "); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, indexName); pstmt.executeUpdate(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt); } } @Override public IndexDescProto getIndex(final String indexName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; IndexDescProto proto = null; try { StringBuilder sql = new StringBuilder(); sql.append( "SELECT index_name, "); sql.append(C_TABLE_ID); sql.append(", column_name, data_type, "); sql.append("index_type, is_unique, is_clustered, is_ascending FROM indexes "); sql.append("where index_name = ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, indexName); res = pstmt.executeQuery(); if (!res.next()) { throw new CatalogException("ERROR: there is no index matched to " + indexName); } proto = resultToIndexDescProto(res); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return proto; } @Override public IndexDescProto getIndex(final String tableName, final String columnName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; IndexDescProto proto = null; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT index_name, "); sql.append(C_TABLE_ID); sql.append(", column_name, data_type, "); sql.append("index_type, is_unique, is_clustered, is_ascending FROM indexes "); sql.append("where "); sql.append(C_TABLE_ID); sql.append(" = ? AND column_name = ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); pstmt.setString(2, columnName); res = pstmt.executeQuery(); if (!res.next()) { throw new CatalogException("ERROR: there is no index matched to " + tableName + "." + columnName); } proto = resultToIndexDescProto(res); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return proto; } @Override public boolean existIndex(final String indexName) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; ResultSet res = null; boolean exist = false; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT index_name from "); sql.append(TB_INDEXES); sql.append(" WHERE index_name = ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, indexName); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } res = pstmt.executeQuery(); exist = res.next(); } catch (SQLException se) { } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return exist; } @Override public boolean existIndex(String tableName, String columnName) throws CatalogException { Connection conn = null; PreparedStatement pstmt = null; boolean exist = false; ResultSet res = null; try { StringBuilder sql = new StringBuilder(); sql.append("SELECT index_name from "); sql.append(TB_INDEXES); sql.append(" WHERE "); sql.append(C_TABLE_ID); sql.append(" = ? AND COLUMN_NAME = ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); pstmt.setString(2, columnName); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } res = pstmt.executeQuery(); exist = res.next(); } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return exist; } @Override public IndexDescProto[] getIndexes(final String tableName) throws CatalogException { Connection conn = null; ResultSet res = null; PreparedStatement pstmt = null; List<IndexDescProto> protos = null; try { protos = new ArrayList<IndexDescProto>(); StringBuilder sql = new StringBuilder(); sql.append("SELECT index_name, "); sql.append(C_TABLE_ID); sql.append(", column_name, data_type, "); sql.append("index_type, is_unique, is_clustered, is_ascending FROM indexes "); sql.append("where "); sql.append(C_TABLE_ID); sql.append("= ?"); if (LOG.isDebugEnabled()) { LOG.debug(sql.toString()); } conn = getConnection(); pstmt = conn.prepareStatement(sql.toString()); pstmt.setString(1, tableName); res = pstmt.executeQuery(); while (res.next()) { protos.add(resultToIndexDescProto(res)); } } catch (SQLException se) { throw new CatalogException(se); } finally { CatalogUtil.closeQuietly(conn, pstmt, res); } return protos.toArray(new IndexDescProto[protos.size()]); } private IndexDescProto resultToIndexDescProto(final ResultSet res) throws SQLException { IndexDescProto.Builder builder = IndexDescProto.newBuilder(); builder.setName(res.getString("index_name")); builder.setTableId(res.getString(C_TABLE_ID)); builder.setColumn(indexResultToColumnProto(res)); builder.setIndexMethod(getIndexMethod(res.getString("index_type").trim())); builder.setIsUnique(res.getBoolean("is_unique")); builder.setIsClustered(res.getBoolean("is_clustered")); builder.setIsAscending(res.getBoolean("is_ascending")); return builder.build(); } /** * INDEXS table doesn't store type_length, so we need another resultToColumnProto method */ private ColumnProto indexResultToColumnProto(final ResultSet res) throws SQLException { ColumnProto.Builder builder = ColumnProto.newBuilder(); builder.setName(res.getString("column_name").trim()); Type type = getDataType(res.getString("data_type").trim()); builder.setDataType(CatalogUtil.newSimpleDataType(type)); return builder.build(); } private ColumnProto resultToColumnProto(final ResultSet res) throws SQLException { ColumnProto.Builder builder = ColumnProto.newBuilder(); builder.setName(res.getString("column_name").trim()); Type type = getDataType(res.getString("data_type").trim()); int typeLength = res.getInt("type_length"); if(typeLength > 0 ) { builder.setDataType(CatalogUtil.newDataTypeWithLen(type, typeLength)); } else { builder.setDataType(CatalogUtil.newSimpleDataType(type)); } return builder.build(); } private CatalogProtos.KeyValueSetProto resultToKeyValueSetProto(final ResultSet res) throws SQLException { CatalogProtos.KeyValueSetProto.Builder setBuilder = CatalogProtos.KeyValueSetProto.newBuilder(); CatalogProtos.KeyValueProto.Builder builder = CatalogProtos.KeyValueProto.newBuilder(); while (res.next()) { builder.setKey(res.getString("key_")); builder.setValue(res.getString("value_")); setBuilder.addKeyval(builder.build()); } return setBuilder.build(); } private IndexMethod getIndexMethod(final String typeStr) { if (typeStr.equals(IndexMethod.TWO_LEVEL_BIN_TREE.toString())) { return IndexMethod.TWO_LEVEL_BIN_TREE; } else { LOG.error("Cannot find a matched type aginst from '" + typeStr + "'"); // TODO - needs exception handling return null; } } private CatalogProtos.PartitionMethodProto resultToPartitionMethodProto(final String tableName, final ResultSet res) throws SQLException, InvalidProtocolBufferException { CatalogProtos.PartitionMethodProto.Builder partBuilder = CatalogProtos.PartitionMethodProto.newBuilder(); partBuilder.setTableId(tableName); partBuilder.setPartitionType(CatalogProtos.PartitionType.valueOf(res.getString("partition_type"))); partBuilder.setExpression(res.getString("expression")); partBuilder.setExpressionSchema(SchemaProto.parseFrom(res.getBytes("expression_schema"))); return partBuilder.build(); } private CatalogProtos.PartitionDescProto resultToPartitionDescProto(ResultSet res) throws SQLException { CatalogProtos.PartitionDescProto.Builder builder = CatalogProtos.PartitionDescProto.newBuilder(); builder.setTableId(res.getString(1)); builder.setPartitionName(res.getString(2)); builder.setOrdinalPosition(res.getInt(3)); builder.setPartitionValue(res.getString(4)); builder.setPath(res.getString(5)); return builder.build(); } @Override public void close() { CatalogUtil.closeQuietly(conn); LOG.info("Shutdown database (" + catalogUri + ")"); } @Override public final void addFunction(final FunctionDesc func) throws CatalogException { // TODO - not implemented yet } @Override public final void deleteFunction(final FunctionDesc func) throws CatalogException { // TODO - not implemented yet } @Override public final void existFunction(final FunctionDesc func) throws CatalogException { // TODO - not implemented yet } @Override public final List<String> getAllFunctionNames() throws CatalogException { // TODO - not implemented yet return null; } }