Search in sources :

Example 6 with InvalidInputException

use of org.apache.hadoop.hive.metastore.api.InvalidInputException in project hive by apache.

the class HiveAlterHandler method alterPartition.

@Override
public Partition alterPartition(RawStore msdb, Warehouse wh, String catName, String dbname, String name, List<String> part_vals, final Partition new_part, EnvironmentContext environmentContext, IHMSHandler handler, String validWriteIds) throws InvalidOperationException, InvalidObjectException, AlreadyExistsException, MetaException {
    boolean success = false;
    Partition oldPart;
    List<TransactionalMetaStoreEventListener> transactionalListeners = null;
    if (handler != null) {
        transactionalListeners = handler.getTransactionalListeners();
    }
    // Set DDL time to now if not specified
    if (new_part.getParameters() == null || new_part.getParameters().get(hive_metastoreConstants.DDL_TIME) == null || Integer.parseInt(new_part.getParameters().get(hive_metastoreConstants.DDL_TIME)) == 0) {
        new_part.putToParameters(hive_metastoreConstants.DDL_TIME, Long.toString(System.currentTimeMillis() / 1000));
    }
    // alter partition
    if (part_vals == null || part_vals.size() == 0) {
        try {
            msdb.openTransaction();
            Table tbl = msdb.getTable(catName, dbname, name, null);
            if (tbl == null) {
                throw new InvalidObjectException("Unable to alter partition because table or database does not exist.");
            }
            oldPart = msdb.getPartition(catName, dbname, name, new_part.getValues());
            if (MetaStoreServerUtils.requireCalStats(oldPart, new_part, tbl, environmentContext)) {
                // if stats are same, no need to update
                if (MetaStoreServerUtils.isFastStatsSame(oldPart, new_part)) {
                    MetaStoreServerUtils.updateBasicState(environmentContext, new_part.getParameters());
                } else {
                    MetaStoreServerUtils.updatePartitionStatsFast(new_part, tbl, wh, false, true, environmentContext, false);
                }
            }
            // PartitionView does not have SD. We do not need update its column stats
            if (oldPart.getSd() != null) {
                updateOrGetPartitionColumnStats(msdb, catName, dbname, name, new_part.getValues(), oldPart.getSd().getCols(), tbl, new_part, null, null);
            }
            Deadline.checkTimeout();
            msdb.alterPartition(catName, dbname, name, new_part.getValues(), new_part, validWriteIds);
            if (transactionalListeners != null && !transactionalListeners.isEmpty()) {
                MetaStoreListenerNotifier.notifyEvent(transactionalListeners, EventMessage.EventType.ALTER_PARTITION, new AlterPartitionEvent(oldPart, new_part, tbl, false, true, new_part.getWriteId(), handler), environmentContext);
            }
            success = msdb.commitTransaction();
        } catch (InvalidObjectException e) {
            LOG.warn("Alter failed", e);
            throw new InvalidOperationException("alter is not possible: " + e.getMessage());
        } catch (NoSuchObjectException e) {
            // old partition does not exist
            throw new InvalidOperationException("alter is not possible: " + e.getMessage());
        } finally {
            if (!success) {
                msdb.rollbackTransaction();
            }
        }
        return oldPart;
    }
    // rename partition
    String oldPartLoc;
    String newPartLoc;
    Path srcPath = null;
    Path destPath = null;
    FileSystem srcFs;
    FileSystem destFs = null;
    boolean dataWasMoved = false;
    Database db;
    try {
        msdb.openTransaction();
        Table tbl = msdb.getTable(DEFAULT_CATALOG_NAME, dbname, name, null);
        if (tbl == null) {
            throw new InvalidObjectException("Unable to alter partition because table or database does not exist.");
        }
        try {
            oldPart = msdb.getPartition(catName, dbname, name, part_vals);
        } catch (NoSuchObjectException e) {
            // this means there is no existing partition
            throw new InvalidObjectException("Unable to rename partition because old partition does not exist");
        }
        Partition check_part;
        try {
            check_part = msdb.getPartition(catName, dbname, name, new_part.getValues());
        } catch (NoSuchObjectException e) {
            // this means there is no existing partition
            check_part = null;
        }
        if (check_part != null) {
            throw new AlreadyExistsException("Partition already exists:" + dbname + "." + name + "." + new_part.getValues());
        }
        // 3) rename the partition directory if it is not an external table
        if (!tbl.getTableType().equals(TableType.EXTERNAL_TABLE.toString())) {
            // TODO: refactor this into a separate method after master merge, this one is too big.
            try {
                db = msdb.getDatabase(catName, dbname);
                // if tbl location is available use it
                // else derive the tbl location from database location
                destPath = wh.getPartitionPath(db, tbl, new_part.getValues());
                destPath = constructRenamedPath(destPath, new Path(new_part.getSd().getLocation()));
            } catch (NoSuchObjectException e) {
                LOG.debug("Didn't find object in metastore ", e);
                throw new InvalidOperationException("Unable to change partition or table. Database " + dbname + " does not exist" + " Check metastore logs for detailed stack." + e.getMessage());
            }
            if (destPath != null) {
                newPartLoc = destPath.toString();
                oldPartLoc = oldPart.getSd().getLocation();
                LOG.info("srcPath:" + oldPartLoc);
                LOG.info("descPath:" + newPartLoc);
                srcPath = new Path(oldPartLoc);
                srcFs = wh.getFs(srcPath);
                destFs = wh.getFs(destPath);
                // check that src and dest are on the same file system
                if (!FileUtils.equalsFileSystem(srcFs, destFs)) {
                    throw new InvalidOperationException("New table location " + destPath + " is on a different file system than the old location " + srcPath + ". This operation is not supported.");
                }
                try {
                    if (srcFs.exists(srcPath)) {
                        if (newPartLoc.compareTo(oldPartLoc) != 0 && destFs.exists(destPath)) {
                            throw new InvalidOperationException("New location for this table " + tbl.getDbName() + "." + tbl.getTableName() + " already exists : " + destPath);
                        }
                        // if destPath's parent path doesn't exist, we should mkdir it
                        Path destParentPath = destPath.getParent();
                        if (!wh.mkdirs(destParentPath)) {
                            throw new MetaException("Unable to create path " + destParentPath);
                        }
                        // rename the data directory
                        wh.renameDir(srcPath, destPath, ReplChangeManager.shouldEnableCm(db, tbl));
                        LOG.info("Partition directory rename from " + srcPath + " to " + destPath + " done.");
                        dataWasMoved = true;
                    }
                } catch (IOException e) {
                    LOG.error("Cannot rename partition directory from " + srcPath + " to " + destPath, e);
                    throw new InvalidOperationException("Unable to access src or dest location for partition " + tbl.getDbName() + "." + tbl.getTableName() + " " + new_part.getValues());
                } catch (MetaException me) {
                    LOG.error("Cannot rename partition directory from " + srcPath + " to " + destPath, me);
                    throw me;
                }
                new_part.getSd().setLocation(newPartLoc);
            }
        } else {
            new_part.getSd().setLocation(oldPart.getSd().getLocation());
        }
        if (MetaStoreServerUtils.requireCalStats(oldPart, new_part, tbl, environmentContext)) {
            MetaStoreServerUtils.updatePartitionStatsFast(new_part, tbl, wh, false, true, environmentContext, false);
        }
        String newPartName = Warehouse.makePartName(tbl.getPartitionKeys(), new_part.getValues());
        List<ColumnStatistics> multiColumnStats = updateOrGetPartitionColumnStats(msdb, catName, dbname, name, oldPart.getValues(), oldPart.getSd().getCols(), tbl, new_part, null, null);
        msdb.alterPartition(catName, dbname, name, part_vals, new_part, validWriteIds);
        if (!multiColumnStats.isEmpty()) {
            for (ColumnStatistics cs : multiColumnStats) {
                cs.getStatsDesc().setPartName(newPartName);
                try {
                    msdb.updatePartitionColumnStatistics(cs, new_part.getValues(), validWriteIds, new_part.getWriteId());
                } catch (InvalidInputException iie) {
                    throw new InvalidOperationException("Unable to update partition stats in table rename." + iie);
                } catch (NoSuchObjectException nsoe) {
                // It is ok, ignore
                }
            }
        }
        if (transactionalListeners != null && !transactionalListeners.isEmpty()) {
            MetaStoreListenerNotifier.notifyEvent(transactionalListeners, EventMessage.EventType.ALTER_PARTITION, new AlterPartitionEvent(oldPart, new_part, tbl, false, true, new_part.getWriteId(), handler), environmentContext);
        }
        success = msdb.commitTransaction();
    } finally {
        if (!success) {
            LOG.error("Failed to rename a partition. Rollback transaction");
            msdb.rollbackTransaction();
            if (dataWasMoved) {
                LOG.error("Revert the data move in renaming a partition.");
                try {
                    if (destFs.exists(destPath)) {
                        wh.renameDir(destPath, srcPath, false);
                    }
                } catch (MetaException me) {
                    LOG.error("Failed to restore partition data from " + destPath + " to " + srcPath + " in alter partition failure. Manual restore is needed.");
                } catch (IOException ioe) {
                    LOG.error("Failed to restore partition data from " + destPath + " to " + srcPath + " in alter partition failure. Manual restore is needed.");
                }
            }
        }
    }
    return oldPart;
}
Also used : Path(org.apache.hadoop.fs.Path) ColumnStatistics(org.apache.hadoop.hive.metastore.api.ColumnStatistics) Partition(org.apache.hadoop.hive.metastore.api.Partition) InvalidInputException(org.apache.hadoop.hive.metastore.api.InvalidInputException) Table(org.apache.hadoop.hive.metastore.api.Table) AlreadyExistsException(org.apache.hadoop.hive.metastore.api.AlreadyExistsException) AlterPartitionEvent(org.apache.hadoop.hive.metastore.events.AlterPartitionEvent) IOException(java.io.IOException) FileSystem(org.apache.hadoop.fs.FileSystem) InvalidOperationException(org.apache.hadoop.hive.metastore.api.InvalidOperationException) Database(org.apache.hadoop.hive.metastore.api.Database) InvalidObjectException(org.apache.hadoop.hive.metastore.api.InvalidObjectException) NoSuchObjectException(org.apache.hadoop.hive.metastore.api.NoSuchObjectException) MetaException(org.apache.hadoop.hive.metastore.api.MetaException)

Example 7 with InvalidInputException

use of org.apache.hadoop.hive.metastore.api.InvalidInputException in project hive by apache.

the class ObjectStore method processScheduledQueryPolicies.

private void processScheduledQueryPolicies(ScheduledQueryProgressInfo info) throws MetaException {
    if (info.getState() != QueryState.FAILED && info.getState() != QueryState.TIMED_OUT) {
        return;
    }
    int autoDisableCount = MetastoreConf.getIntVar(conf, ConfVars.SCHEDULED_QUERIES_AUTODISABLE_COUNT);
    int skipCount = MetastoreConf.getIntVar(conf, ConfVars.SCHEDULED_QUERIES_SKIP_OPPORTUNITIES_AFTER_FAILURES);
    int lastN = Math.max(autoDisableCount, skipCount);
    if (lastN <= 0) {
        // disabled
        return;
    }
    boolean commited = false;
    Query query = null;
    try {
        openTransaction();
        MScheduledExecution lastExecution = pm.getObjectById(MScheduledExecution.class, info.getScheduledExecutionId());
        MScheduledQuery schq = lastExecution.getScheduledQuery();
        query = pm.newQuery(MScheduledExecution.class);
        query.setFilter("scheduledQuery == currentSchedule");
        query.setOrdering("scheduledExecutionId descending");
        query.declareParameters("MScheduledQuery currentSchedule");
        query.setRange(0, lastN);
        List<MScheduledExecution> list = (List<MScheduledExecution>) query.execute(schq);
        int failureCount = 0;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getState() != QueryState.FAILED && list.get(i).getState() != QueryState.TIMED_OUT) {
                break;
            }
            failureCount++;
        }
        if (autoDisableCount > 0 && autoDisableCount <= failureCount) {
            LOG.info("Disabling {} after {} consequtive failures", schq.getScheduleKey(), autoDisableCount);
            schq.setEnabled(false);
            int now = (int) (System.currentTimeMillis() / 1000);
            MScheduledExecution execution = new MScheduledExecution();
            execution.setScheduledQuery(schq);
            execution.setState(QueryState.AUTO_DISABLED);
            execution.setStartTime(now);
            execution.setEndTime(now);
            execution.setLastUpdateTime(now);
            execution.setErrorMessage(String.format("Disabling query after {} consequtive failures", autoDisableCount));
            pm.makePersistent(execution);
        }
        if (skipCount > 0) {
            int n = Math.min(skipCount, failureCount) - 1;
            Integer scheduledTime = schq.getNextExecution();
            for (int i = 0; i < n; i++) {
                if (scheduledTime != null) {
                    scheduledTime = computeNextExecutionTime(schq.getSchedule(), scheduledTime);
                }
            }
            if (scheduledTime != null) {
                schq.setNextExecution(scheduledTime);
            }
        }
        commited = commitTransaction();
    } catch (InvalidInputException e) {
        throw new MetaException("Unexpected InvalidInputException: " + e.getMessage());
    } finally {
        rollbackAndCleanup(commited, query);
    }
}
Also used : InvalidInputException(org.apache.hadoop.hive.metastore.api.InvalidInputException) ScheduledQuery(org.apache.hadoop.hive.metastore.api.ScheduledQuery) Query(javax.jdo.Query) MScheduledQuery(org.apache.hadoop.hive.metastore.model.MScheduledQuery) MScheduledExecution(org.apache.hadoop.hive.metastore.model.MScheduledExecution) ValidWriteIdList(org.apache.hadoop.hive.common.ValidWriteIdList) ReplicationMetricList(org.apache.hadoop.hive.metastore.api.ReplicationMetricList) LinkedList(java.util.LinkedList) MStringList(org.apache.hadoop.hive.metastore.model.MStringList) ArrayList(java.util.ArrayList) ValidReaderWriteIdList(org.apache.hadoop.hive.common.ValidReaderWriteIdList) List(java.util.List) MScheduledQuery(org.apache.hadoop.hive.metastore.model.MScheduledQuery) MConstraint(org.apache.hadoop.hive.metastore.model.MConstraint) SQLUniqueConstraint(org.apache.hadoop.hive.metastore.api.SQLUniqueConstraint) SQLCheckConstraint(org.apache.hadoop.hive.metastore.api.SQLCheckConstraint) SQLDefaultConstraint(org.apache.hadoop.hive.metastore.api.SQLDefaultConstraint) SQLNotNullConstraint(org.apache.hadoop.hive.metastore.api.SQLNotNullConstraint) MetaException(org.apache.hadoop.hive.metastore.api.MetaException)

Example 8 with InvalidInputException

use of org.apache.hadoop.hive.metastore.api.InvalidInputException in project hive by apache.

the class ObjectStore method deletePartitionColumnStatistics.

@Override
public boolean deletePartitionColumnStatistics(String catName, String dbName, String tableName, String partName, List<String> partVals, String colName, String engine) throws NoSuchObjectException, MetaException, InvalidObjectException, InvalidInputException {
    boolean ret = false;
    Query query = null;
    dbName = org.apache.commons.lang3.StringUtils.defaultString(dbName, Warehouse.DEFAULT_DATABASE_NAME);
    catName = normalizeIdentifier(catName);
    if (tableName == null) {
        throw new InvalidInputException("Table name is null.");
    }
    try {
        openTransaction();
        MTable mTable = getMTable(catName, dbName, tableName);
        MPartitionColumnStatistics mStatsObj;
        List<MPartitionColumnStatistics> mStatsObjColl;
        if (mTable == null) {
            throw new NoSuchObjectException("Table " + tableName + "  for which stats deletion is requested doesn't exist");
        }
        // Note: this does not verify ACID state; called internally when removing cols/etc.
        // Also called via an unused metastore API that checks for ACID tables.
        MPartition mPartition = getMPartition(catName, dbName, tableName, partVals, mTable);
        if (mPartition == null) {
            throw new NoSuchObjectException("Partition " + partName + " for which stats deletion is requested doesn't exist");
        }
        query = pm.newQuery(MPartitionColumnStatistics.class);
        String filter;
        String parameters;
        if (colName != null) {
            filter = "partition.partitionName == t1 && dbName == t2 && tableName == t3 && " + "colName == t4 && catName == t5" + (engine != null ? " && engine == t6" : "");
            parameters = "java.lang.String t1, java.lang.String t2, " + "java.lang.String t3, java.lang.String t4, java.lang.String t5" + (engine != null ? ", java.lang.String t6" : "");
        } else {
            filter = "partition.partitionName == t1 && dbName == t2 && tableName == t3 && catName == t4" + (engine != null ? " && engine == t5" : "");
            parameters = "java.lang.String t1, java.lang.String t2, java.lang.String t3, java.lang.String t4" + (engine != null ? ", java.lang.String t5" : "");
        }
        query.setFilter(filter);
        query.declareParameters(parameters);
        if (colName != null) {
            query.setUnique(true);
            if (engine != null) {
                mStatsObj = (MPartitionColumnStatistics) query.executeWithArray(partName.trim(), normalizeIdentifier(dbName), normalizeIdentifier(tableName), normalizeIdentifier(colName), normalizeIdentifier(catName), engine);
            } else {
                mStatsObj = (MPartitionColumnStatistics) query.executeWithArray(partName.trim(), normalizeIdentifier(dbName), normalizeIdentifier(tableName), normalizeIdentifier(colName), normalizeIdentifier(catName));
            }
            pm.retrieve(mStatsObj);
            if (mStatsObj != null) {
                pm.deletePersistent(mStatsObj);
            } else {
                throw new NoSuchObjectException("Column stats doesn't exist for table=" + TableName.getQualified(catName, dbName, tableName) + " partition=" + partName + " col=" + colName);
            }
        } else {
            if (engine != null) {
                mStatsObjColl = (List<MPartitionColumnStatistics>) query.executeWithArray(partName.trim(), normalizeIdentifier(dbName), normalizeIdentifier(tableName), normalizeIdentifier(catName), engine);
            } else {
                mStatsObjColl = (List<MPartitionColumnStatistics>) query.executeWithArray(partName.trim(), normalizeIdentifier(dbName), normalizeIdentifier(tableName), normalizeIdentifier(catName));
            }
            pm.retrieveAll(mStatsObjColl);
            if (mStatsObjColl != null) {
                pm.deletePersistentAll(mStatsObjColl);
            } else {
                throw new NoSuchObjectException("Column stats don't exist for table=" + TableName.getQualified(catName, dbName, tableName) + " partition" + partName);
            }
        }
        ret = commitTransaction();
    } finally {
        rollbackAndCleanup(ret, query);
    }
    return ret;
}
Also used : InvalidInputException(org.apache.hadoop.hive.metastore.api.InvalidInputException) MTable(org.apache.hadoop.hive.metastore.model.MTable) ScheduledQuery(org.apache.hadoop.hive.metastore.api.ScheduledQuery) Query(javax.jdo.Query) MScheduledQuery(org.apache.hadoop.hive.metastore.model.MScheduledQuery) NoSuchObjectException(org.apache.hadoop.hive.metastore.api.NoSuchObjectException) MPartitionColumnStatistics(org.apache.hadoop.hive.metastore.model.MPartitionColumnStatistics) MPartition(org.apache.hadoop.hive.metastore.model.MPartition)

Example 9 with InvalidInputException

use of org.apache.hadoop.hive.metastore.api.InvalidInputException in project hive by apache.

the class ObjectStore method deleteTableColumnStatistics.

@Override
public boolean deleteTableColumnStatistics(String catName, String dbName, String tableName, String colName, String engine) throws NoSuchObjectException, MetaException, InvalidObjectException, InvalidInputException {
    boolean ret = false;
    Query query = null;
    dbName = org.apache.commons.lang3.StringUtils.defaultString(dbName, Warehouse.DEFAULT_DATABASE_NAME);
    if (tableName == null) {
        throw new InvalidInputException("Table name is null.");
    }
    try {
        openTransaction();
        MTable mTable = getMTable(catName, dbName, tableName);
        MTableColumnStatistics mStatsObj;
        List<MTableColumnStatistics> mStatsObjColl;
        if (mTable == null) {
            throw new NoSuchObjectException("Table " + TableName.getQualified(catName, dbName, tableName) + "  for which stats deletion is requested doesn't exist");
        }
        // Note: this does not verify ACID state; called internally when removing cols/etc.
        // Also called via an unused metastore API that checks for ACID tables.
        query = pm.newQuery(MTableColumnStatistics.class);
        String filter;
        String parameters;
        if (colName != null) {
            filter = "table.tableName == t1 && dbName == t2 && catName == t3 && colName == t4" + (engine != null ? " && engine == t5" : "");
            parameters = "java.lang.String t1, java.lang.String t2, java.lang.String t3, java.lang.String t4" + (engine != null ? ", java.lang.String t5" : "");
        } else {
            filter = "table.tableName == t1 && dbName == t2 && catName == t3" + (engine != null ? " && engine == t4" : "");
            parameters = "java.lang.String t1, java.lang.String t2, java.lang.String t3" + (engine != null ? ", java.lang.String t4" : "");
        }
        query.setFilter(filter);
        query.declareParameters(parameters);
        if (colName != null) {
            query.setUnique(true);
            if (engine != null) {
                mStatsObj = (MTableColumnStatistics) query.executeWithArray(normalizeIdentifier(tableName), normalizeIdentifier(dbName), normalizeIdentifier(catName), normalizeIdentifier(colName), engine);
            } else {
                mStatsObj = (MTableColumnStatistics) query.executeWithArray(normalizeIdentifier(tableName), normalizeIdentifier(dbName), normalizeIdentifier(catName), normalizeIdentifier(colName));
            }
            pm.retrieve(mStatsObj);
            if (mStatsObj != null) {
                pm.deletePersistent(mStatsObj);
            } else {
                throw new NoSuchObjectException("Column stats doesn't exist for db=" + dbName + " table=" + tableName + " col=" + colName);
            }
        } else {
            if (engine != null) {
                mStatsObjColl = (List<MTableColumnStatistics>) query.executeWithArray(normalizeIdentifier(tableName), normalizeIdentifier(dbName), normalizeIdentifier(catName), engine);
            } else {
                mStatsObjColl = (List<MTableColumnStatistics>) query.executeWithArray(normalizeIdentifier(tableName), normalizeIdentifier(dbName), normalizeIdentifier(catName));
            }
            pm.retrieveAll(mStatsObjColl);
            if (mStatsObjColl != null) {
                pm.deletePersistentAll(mStatsObjColl);
            } else {
                throw new NoSuchObjectException("Column stats doesn't exist for db=" + dbName + " table=" + tableName);
            }
        }
        ret = commitTransaction();
    } finally {
        rollbackAndCleanup(ret, query);
    }
    return ret;
}
Also used : InvalidInputException(org.apache.hadoop.hive.metastore.api.InvalidInputException) MTable(org.apache.hadoop.hive.metastore.model.MTable) ScheduledQuery(org.apache.hadoop.hive.metastore.api.ScheduledQuery) Query(javax.jdo.Query) MScheduledQuery(org.apache.hadoop.hive.metastore.model.MScheduledQuery) MTableColumnStatistics(org.apache.hadoop.hive.metastore.model.MTableColumnStatistics) NoSuchObjectException(org.apache.hadoop.hive.metastore.api.NoSuchObjectException)

Example 10 with InvalidInputException

use of org.apache.hadoop.hive.metastore.api.InvalidInputException in project hive by apache.

the class HiveAlterHandler method alterTable.

@Override
public void alterTable(RawStore msdb, Warehouse wh, String catName, String dbname, String name, Table newt, EnvironmentContext environmentContext, IHMSHandler handler, String writeIdList) throws InvalidOperationException, MetaException {
    catName = normalizeIdentifier(catName);
    name = name.toLowerCase();
    dbname = dbname.toLowerCase();
    final boolean cascade;
    final boolean replDataLocationChanged;
    final boolean isReplicated;
    if ((environmentContext != null) && environmentContext.isSetProperties()) {
        cascade = StatsSetupConst.TRUE.equals(environmentContext.getProperties().get(StatsSetupConst.CASCADE));
        replDataLocationChanged = ReplConst.TRUE.equals(environmentContext.getProperties().get(ReplConst.REPL_DATA_LOCATION_CHANGED));
    } else {
        cascade = false;
        replDataLocationChanged = false;
    }
    if (newt == null) {
        throw new InvalidOperationException("New table is null");
    }
    String newTblName = newt.getTableName().toLowerCase();
    String newDbName = newt.getDbName().toLowerCase();
    if (!MetaStoreUtils.validateName(newTblName, handler.getConf())) {
        throw new InvalidOperationException(newTblName + " is not a valid object name");
    }
    String validate = MetaStoreServerUtils.validateTblColumns(newt.getSd().getCols());
    if (validate != null) {
        throw new InvalidOperationException("Invalid column " + validate);
    }
    // Validate bucketedColumns in new table
    List<String> bucketColumns = MetaStoreServerUtils.validateBucketColumns(newt.getSd());
    if (CollectionUtils.isNotEmpty(bucketColumns)) {
        String errMsg = "Bucket columns - " + bucketColumns.toString() + " doesn't match with any table columns";
        LOG.error(errMsg);
        throw new InvalidOperationException(errMsg);
    }
    Path srcPath = null;
    FileSystem srcFs;
    Path destPath = null;
    FileSystem destFs = null;
    boolean success = false;
    boolean dataWasMoved = false;
    boolean isPartitionedTable = false;
    Database olddb = null;
    Table oldt = null;
    List<TransactionalMetaStoreEventListener> transactionalListeners = handler.getTransactionalListeners();
    List<MetaStoreEventListener> listeners = handler.getListeners();
    Map<String, String> txnAlterTableEventResponses = Collections.emptyMap();
    try {
        boolean rename = false;
        List<Partition> parts;
        // Switching tables between catalogs is not allowed.
        if (!catName.equalsIgnoreCase(newt.getCatName())) {
            throw new InvalidOperationException("Tables cannot be moved between catalogs, old catalog" + catName + ", new catalog " + newt.getCatName());
        }
        // check if table with the new name already exists
        if (!newTblName.equals(name) || !newDbName.equals(dbname)) {
            if (msdb.getTable(catName, newDbName, newTblName, null) != null) {
                throw new InvalidOperationException("new table " + newDbName + "." + newTblName + " already exists");
            }
            rename = true;
        }
        msdb.openTransaction();
        // get old table
        // Note: we don't verify stats here; it's done below in alterTableUpdateTableColumnStats.
        olddb = msdb.getDatabase(catName, dbname);
        oldt = msdb.getTable(catName, dbname, name, null);
        if (oldt == null) {
            throw new InvalidOperationException("table " + TableName.getQualified(catName, dbname, name) + " doesn't exist");
        }
        validateTableChangesOnReplSource(olddb, oldt, newt, environmentContext);
        // On a replica this alter table will be executed only if old and new both the databases are
        // available and being replicated into. Otherwise, it will be either create or drop of table.
        isReplicated = HMSHandler.isDbReplicationTarget(olddb);
        if (oldt.getPartitionKeysSize() != 0) {
            isPartitionedTable = true;
        }
        // Throws InvalidOperationException if the new column types are not
        // compatible with the current column types.
        DefaultIncompatibleTableChangeHandler.get().allowChange(handler.getConf(), oldt, newt);
        // check that partition keys have not changed, except for virtual views
        // however, allow the partition comments to change
        boolean partKeysPartiallyEqual = checkPartialPartKeysEqual(oldt.getPartitionKeys(), newt.getPartitionKeys());
        if (!oldt.getTableType().equals(TableType.VIRTUAL_VIEW.toString())) {
            Map<String, String> properties = environmentContext.getProperties();
            if (properties == null || (properties != null && !Boolean.parseBoolean(properties.getOrDefault(HiveMetaHook.ALLOW_PARTITION_KEY_CHANGE, "false")))) {
                if (!partKeysPartiallyEqual) {
                    throw new InvalidOperationException("partition keys can not be changed.");
                }
            }
        }
        // 4) the table was not initially created with a specified location
        if (replDataLocationChanged || (rename && !oldt.getTableType().equals(TableType.VIRTUAL_VIEW.toString()) && (oldt.getSd().getLocation().compareTo(newt.getSd().getLocation()) == 0 || StringUtils.isEmpty(newt.getSd().getLocation())) && !MetaStoreUtils.isExternalTable(oldt))) {
            srcPath = new Path(oldt.getSd().getLocation());
            if (replDataLocationChanged) {
                // If data location is changed in replication flow, then new path was already set in
                // the newt. Also, it is as good as the data is moved and set dataWasMoved=true so that
                // location in partitions are also updated accordingly.
                // No need to validate if the destPath exists as in replication flow, data gets replicated
                // separately.
                destPath = new Path(newt.getSd().getLocation());
                dataWasMoved = true;
            } else {
                // Rename flow.
                // If a table was created in a user specified location using the DDL like
                // create table tbl ... location ...., it should be treated like an external table
                // in the table rename, its data location should not be changed. We can check
                // if the table directory was created directly under its database directory to tell
                // if it is such a table
                String oldtRelativePath = wh.getDatabaseManagedPath(olddb).toUri().relativize(srcPath.toUri()).toString();
                boolean tableInSpecifiedLoc = !oldtRelativePath.equalsIgnoreCase(name) && !oldtRelativePath.equalsIgnoreCase(name + Path.SEPARATOR);
                if (!tableInSpecifiedLoc) {
                    srcFs = wh.getFs(srcPath);
                    // get new location
                    Database db = msdb.getDatabase(catName, newDbName);
                    assert (isReplicated == HMSHandler.isDbReplicationTarget(db));
                    Path databasePath = constructRenamedPath(wh.getDatabaseManagedPath(db), srcPath);
                    destPath = new Path(databasePath, newTblName);
                    destFs = wh.getFs(destPath);
                    newt.getSd().setLocation(destPath.toString());
                    // check that src and dest are on the same file system
                    if (!FileUtils.equalsFileSystem(srcFs, destFs)) {
                        throw new InvalidOperationException("table new location " + destPath + " is on a different file system than the old location " + srcPath + ". This operation is not supported");
                    }
                    try {
                        if (destFs.exists(destPath)) {
                            throw new InvalidOperationException("New location for this table " + TableName.getQualified(catName, newDbName, newTblName) + " already exists : " + destPath);
                        }
                        // check that src exists and also checks permissions necessary, rename src to dest
                        if (srcFs.exists(srcPath) && wh.renameDir(srcPath, destPath, ReplChangeManager.shouldEnableCm(olddb, oldt))) {
                            dataWasMoved = true;
                        }
                    } catch (IOException | MetaException e) {
                        LOG.error("Alter Table operation for " + dbname + "." + name + " failed.", e);
                        throw new InvalidOperationException("Alter Table operation for " + dbname + "." + name + " failed to move data due to: '" + getSimpleMessage(e) + "' See hive log file for details.");
                    }
                    if (!HiveMetaStore.isRenameAllowed(olddb, db)) {
                        LOG.error("Alter Table operation for " + TableName.getQualified(catName, dbname, name) + "to new table = " + TableName.getQualified(catName, newDbName, newTblName) + " failed ");
                        throw new MetaException("Alter table not allowed for table " + TableName.getQualified(catName, dbname, name) + "to new table = " + TableName.getQualified(catName, newDbName, newTblName));
                    }
                }
            }
            if (isPartitionedTable) {
                String oldTblLocPath = srcPath.toUri().getPath();
                String newTblLocPath = dataWasMoved ? destPath.toUri().getPath() : null;
                // also the location field in partition
                parts = msdb.getPartitions(catName, dbname, name, -1);
                Multimap<Partition, ColumnStatistics> columnStatsNeedUpdated = ArrayListMultimap.create();
                for (Partition part : parts) {
                    String oldPartLoc = part.getSd().getLocation();
                    if (dataWasMoved && oldPartLoc.contains(oldTblLocPath)) {
                        URI oldUri = new Path(oldPartLoc).toUri();
                        String newPath = oldUri.getPath().replace(oldTblLocPath, newTblLocPath);
                        Path newPartLocPath = new Path(oldUri.getScheme(), oldUri.getAuthority(), newPath);
                        part.getSd().setLocation(newPartLocPath.toString());
                    }
                    part.setDbName(newDbName);
                    part.setTableName(newTblName);
                    List<ColumnStatistics> multiColStats = updateOrGetPartitionColumnStats(msdb, catName, dbname, name, part.getValues(), part.getSd().getCols(), oldt, part, null, null);
                    for (ColumnStatistics colStats : multiColStats) {
                        columnStatsNeedUpdated.put(part, colStats);
                    }
                }
                // Do not verify stats parameters on a partitioned table.
                msdb.alterTable(catName, dbname, name, newt, null);
                // alterPartition is only for changing the partition location in the table rename
                if (dataWasMoved) {
                    int partsToProcess = parts.size();
                    int partitionBatchSize = MetastoreConf.getIntVar(handler.getConf(), MetastoreConf.ConfVars.BATCH_RETRIEVE_MAX);
                    int batchStart = 0;
                    while (partsToProcess > 0) {
                        int batchEnd = Math.min(batchStart + partitionBatchSize, parts.size());
                        List<Partition> partBatch = parts.subList(batchStart, batchEnd);
                        int partBatchSize = partBatch.size();
                        partsToProcess -= partBatchSize;
                        batchStart += partBatchSize;
                        List<List<String>> partValues = new ArrayList<>(partBatchSize);
                        for (Partition part : partBatch) {
                            partValues.add(part.getValues());
                        }
                        msdb.alterPartitions(catName, newDbName, newTblName, partValues, partBatch, newt.getWriteId(), writeIdList);
                    }
                }
                Deadline.checkTimeout();
                for (Entry<Partition, ColumnStatistics> partColStats : columnStatsNeedUpdated.entries()) {
                    ColumnStatistics newPartColStats = partColStats.getValue();
                    newPartColStats.getStatsDesc().setDbName(newDbName);
                    newPartColStats.getStatsDesc().setTableName(newTblName);
                    msdb.updatePartitionColumnStatistics(newPartColStats, partColStats.getKey().getValues(), writeIdList, newt.getWriteId());
                }
            } else {
                alterTableUpdateTableColumnStats(msdb, oldt, newt, environmentContext, writeIdList, conf, null);
            }
        } else {
            // operations other than table rename
            if (MetaStoreServerUtils.requireCalStats(null, null, newt, environmentContext) && !isPartitionedTable) {
                Database db = msdb.getDatabase(catName, newDbName);
                assert (isReplicated == HMSHandler.isDbReplicationTarget(db));
                // Update table stats. For partitioned table, we update stats in alterPartition()
                MetaStoreServerUtils.updateTableStatsSlow(db, newt, wh, false, true, environmentContext);
            }
            if (isPartitionedTable) {
                // Currently only column related changes can be cascaded in alter table
                boolean runPartitionMetadataUpdate = (cascade && !MetaStoreServerUtils.areSameColumns(oldt.getSd().getCols(), newt.getSd().getCols()));
                // we may skip the update entirely if there are only new columns added
                runPartitionMetadataUpdate |= !cascade && !MetaStoreServerUtils.arePrefixColumns(oldt.getSd().getCols(), newt.getSd().getCols());
                boolean retainOnColRemoval = MetastoreConf.getBoolVar(handler.getConf(), MetastoreConf.ConfVars.COLSTATS_RETAIN_ON_COLUMN_REMOVAL);
                if (runPartitionMetadataUpdate) {
                    if (cascade || retainOnColRemoval) {
                        parts = msdb.getPartitions(catName, dbname, name, -1);
                        for (Partition part : parts) {
                            Partition oldPart = new Partition(part);
                            List<FieldSchema> oldCols = part.getSd().getCols();
                            part.getSd().setCols(newt.getSd().getCols());
                            List<ColumnStatistics> colStats = updateOrGetPartitionColumnStats(msdb, catName, dbname, name, part.getValues(), oldCols, oldt, part, null, null);
                            assert (colStats.isEmpty());
                            Deadline.checkTimeout();
                            if (cascade) {
                                msdb.alterPartition(catName, dbname, name, part.getValues(), part, writeIdList);
                            } else {
                                // update changed properties (stats)
                                oldPart.setParameters(part.getParameters());
                                msdb.alterPartition(catName, dbname, name, part.getValues(), oldPart, writeIdList);
                            }
                        }
                    } else {
                        // clear all column stats to prevent incorract behaviour in case same column is reintroduced
                        TableName tableName = new TableName(catName, dbname, name);
                        msdb.deleteAllPartitionColumnStatistics(tableName, writeIdList);
                    }
                    // Don't validate table-level stats for a partitoned table.
                    msdb.alterTable(catName, dbname, name, newt, null);
                } else {
                    LOG.warn("Alter table not cascaded to partitions.");
                    alterTableUpdateTableColumnStats(msdb, oldt, newt, environmentContext, writeIdList, conf, null);
                }
            } else {
                alterTableUpdateTableColumnStats(msdb, oldt, newt, environmentContext, writeIdList, conf, null);
            }
        }
        if (transactionalListeners != null && !transactionalListeners.isEmpty()) {
            txnAlterTableEventResponses = MetaStoreListenerNotifier.notifyEvent(transactionalListeners, EventMessage.EventType.ALTER_TABLE, new AlterTableEvent(oldt, newt, false, true, newt.getWriteId(), handler, isReplicated), environmentContext);
        }
        // commit the changes
        success = msdb.commitTransaction();
    } catch (InvalidObjectException e) {
        LOG.debug("Failed to get object from Metastore ", e);
        throw new InvalidOperationException("Unable to change partition or table." + " Check metastore logs for detailed stack." + e.getMessage());
    } catch (InvalidInputException e) {
        LOG.debug("Accessing Metastore failed due to invalid input ", e);
        throw new InvalidOperationException("Unable to change partition or table." + " Check metastore logs for detailed stack." + e.getMessage());
    } catch (NoSuchObjectException e) {
        LOG.debug("Object not found in metastore ", e);
        throw new InvalidOperationException("Unable to change partition or table. Object " + e.getMessage() + " does not exist." + " Check metastore logs for detailed stack.");
    } finally {
        if (success) {
            // If data location is changed in replication flow, then need to delete the old path.
            if (replDataLocationChanged) {
                assert (olddb != null);
                assert (oldt != null);
                Path deleteOldDataLoc = new Path(oldt.getSd().getLocation());
                boolean isSkipTrash = MetaStoreUtils.isSkipTrash(oldt.getParameters());
                try {
                    wh.deleteDir(deleteOldDataLoc, true, isSkipTrash, ReplChangeManager.shouldEnableCm(olddb, oldt));
                    LOG.info("Deleted the old data location: {} for the table: {}", deleteOldDataLoc, dbname + "." + name);
                } catch (MetaException ex) {
                    // Eat the exception as it doesn't affect the state of existing tables.
                    // Expect, user to manually drop this path when exception and so logging a warning.
                    LOG.warn("Unable to delete the old data location: {} for the table: {}", deleteOldDataLoc, dbname + "." + name);
                }
            }
        } else {
            LOG.error("Failed to alter table " + TableName.getQualified(catName, dbname, name));
            msdb.rollbackTransaction();
            if (!replDataLocationChanged && dataWasMoved) {
                try {
                    if (destFs.exists(destPath)) {
                        if (!destFs.rename(destPath, srcPath)) {
                            LOG.error("Failed to restore data from " + destPath + " to " + srcPath + " in alter table failure. Manual restore is needed.");
                        }
                    }
                } catch (IOException e) {
                    LOG.error("Failed to restore data from " + destPath + " to " + srcPath + " in alter table failure. Manual restore is needed.");
                }
            }
        }
    }
    if (!listeners.isEmpty()) {
        // I don't think event notifications in case of failures are necessary, but other HMS operations
        // make this call whether the event failed or succeeded. To make this behavior consistent,
        // this call is made for failed events also.
        MetaStoreListenerNotifier.notifyEvent(listeners, EventMessage.EventType.ALTER_TABLE, new AlterTableEvent(oldt, newt, false, success, newt.getWriteId(), handler, isReplicated), environmentContext, txnAlterTableEventResponses, msdb);
    }
}
Also used : FieldSchema(org.apache.hadoop.hive.metastore.api.FieldSchema) ArrayList(java.util.ArrayList) URI(java.net.URI) AlterTableEvent(org.apache.hadoop.hive.metastore.events.AlterTableEvent) FileSystem(org.apache.hadoop.fs.FileSystem) InvalidOperationException(org.apache.hadoop.hive.metastore.api.InvalidOperationException) Database(org.apache.hadoop.hive.metastore.api.Database) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) InvalidObjectException(org.apache.hadoop.hive.metastore.api.InvalidObjectException) MetaException(org.apache.hadoop.hive.metastore.api.MetaException) Path(org.apache.hadoop.fs.Path) ColumnStatistics(org.apache.hadoop.hive.metastore.api.ColumnStatistics) Partition(org.apache.hadoop.hive.metastore.api.Partition) InvalidInputException(org.apache.hadoop.hive.metastore.api.InvalidInputException) Table(org.apache.hadoop.hive.metastore.api.Table) IOException(java.io.IOException) TableName(org.apache.hadoop.hive.common.TableName) NoSuchObjectException(org.apache.hadoop.hive.metastore.api.NoSuchObjectException)

Aggregations

InvalidInputException (org.apache.hadoop.hive.metastore.api.InvalidInputException)13 NoSuchObjectException (org.apache.hadoop.hive.metastore.api.NoSuchObjectException)11 InvalidObjectException (org.apache.hadoop.hive.metastore.api.InvalidObjectException)9 FieldSchema (org.apache.hadoop.hive.metastore.api.FieldSchema)7 ArrayList (java.util.ArrayList)6 ColumnStatistics (org.apache.hadoop.hive.metastore.api.ColumnStatistics)6 Partition (org.apache.hadoop.hive.metastore.api.Partition)5 Table (org.apache.hadoop.hive.metastore.api.Table)5 IOException (java.io.IOException)4 FileSystem (org.apache.hadoop.fs.FileSystem)4 Path (org.apache.hadoop.fs.Path)4 ColumnStatisticsObj (org.apache.hadoop.hive.metastore.api.ColumnStatisticsObj)4 InvalidOperationException (org.apache.hadoop.hive.metastore.api.InvalidOperationException)4 MetaException (org.apache.hadoop.hive.metastore.api.MetaException)4 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Query (javax.jdo.Query)3 Database (org.apache.hadoop.hive.metastore.api.Database)3 ScheduledQuery (org.apache.hadoop.hive.metastore.api.ScheduledQuery)3 MScheduledQuery (org.apache.hadoop.hive.metastore.model.MScheduledQuery)3