Package org.apache.hcatalog.cli.SemanticAnalysis

Source Code of org.apache.hcatalog.cli.SemanticAnalysis.HCatSemanticAnalyzer

/**
* 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.hcatalog.cli.SemanticAnalysis;

import java.io.Serializable;
import java.util.List;

import org.apache.hadoop.hive.metastore.api.Database;
import org.apache.hadoop.hive.ql.exec.Task;
import org.apache.hadoop.hive.ql.metadata.Hive;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.metadata.Partition;
import org.apache.hadoop.hive.ql.metadata.Table;
import org.apache.hadoop.hive.ql.parse.ASTNode;
import org.apache.hadoop.hive.ql.parse.AbstractSemanticAnalyzerHook;
import org.apache.hadoop.hive.ql.parse.HiveParser;
import org.apache.hadoop.hive.ql.parse.HiveSemanticAnalyzerHookContext;
import org.apache.hadoop.hive.ql.parse.SemanticException;
import org.apache.hadoop.hive.ql.plan.AlterTableDesc;
import org.apache.hadoop.hive.ql.plan.DDLWork;
import org.apache.hadoop.hive.ql.plan.DescDatabaseDesc;
import org.apache.hadoop.hive.ql.plan.DescTableDesc;
import org.apache.hadoop.hive.ql.plan.DropDatabaseDesc;
import org.apache.hadoop.hive.ql.plan.DropTableDesc;
import org.apache.hadoop.hive.ql.plan.HiveOperation;
import org.apache.hadoop.hive.ql.plan.PartitionSpec;
import org.apache.hadoop.hive.ql.plan.ShowDatabasesDesc;
import org.apache.hadoop.hive.ql.plan.ShowPartitionsDesc;
import org.apache.hadoop.hive.ql.plan.ShowTableStatusDesc;
import org.apache.hadoop.hive.ql.plan.ShowTablesDesc;
import org.apache.hadoop.hive.ql.plan.SwitchDatabaseDesc;
import org.apache.hadoop.hive.ql.security.authorization.Privilege;
import org.apache.hcatalog.common.ErrorType;
import org.apache.hcatalog.common.HCatException;

public class HCatSemanticAnalyzer extends HCatSemanticAnalyzerBase {

    private AbstractSemanticAnalyzerHook hook;
    private ASTNode ast;


    @Override
    public ASTNode preAnalyze(HiveSemanticAnalyzerHookContext context, ASTNode ast)
        throws SemanticException {

        this.ast = ast;
        switch (ast.getToken().getType()) {

        // HCat wants to intercept following tokens and special-handle them.
        case HiveParser.TOK_CREATETABLE:
            hook = new CreateTableHook();
            return hook.preAnalyze(context, ast);

        case HiveParser.TOK_CREATEDATABASE:
            hook = new CreateDatabaseHook();
            return hook.preAnalyze(context, ast);

        case HiveParser.TOK_ALTERTABLE_PARTITION:
            if (((ASTNode) ast.getChild(1)).getToken().getType() == HiveParser.TOK_ALTERTABLE_FILEFORMAT) {
                return ast;
            } else if (((ASTNode) ast.getChild(1)).getToken().getType() == HiveParser.TOK_ALTERTABLE_ALTERPARTS_MERGEFILES) {
                // unsupported
                throw new SemanticException("Operation not supported.");
            } else {
                return ast;
            }

            // HCat will allow these operations to be performed.
            // Database DDL
        case HiveParser.TOK_SHOWDATABASES:
        case HiveParser.TOK_DROPDATABASE:
        case HiveParser.TOK_SWITCHDATABASE:
        case HiveParser.TOK_DESCDATABASE:
        case HiveParser.TOK_ALTERDATABASE_PROPERTIES:

            // Index DDL
        case HiveParser.TOK_ALTERINDEX_PROPERTIES:
        case HiveParser.TOK_CREATEINDEX:
        case HiveParser.TOK_DROPINDEX:
        case HiveParser.TOK_SHOWINDEXES:

            // View DDL
            // "alter view add partition" does not work because of the nature of implementation
            // of the DDL in hive. Hive will internally invoke another Driver on the select statement,
            // and HCat does not let "select" statement through. I cannot find a way to get around it
            // without modifying hive code. So just leave it unsupported.
            //case HiveParser.TOK_ALTERVIEW_ADDPARTS:
        case HiveParser.TOK_ALTERVIEW_DROPPARTS:
        case HiveParser.TOK_ALTERVIEW_PROPERTIES:
        case HiveParser.TOK_ALTERVIEW_RENAME:
        case HiveParser.TOK_CREATEVIEW:
        case HiveParser.TOK_DROPVIEW:

            // Authorization DDL
        case HiveParser.TOK_CREATEROLE:
        case HiveParser.TOK_DROPROLE:
        case HiveParser.TOK_GRANT_ROLE:
        case HiveParser.TOK_GRANT_WITH_OPTION:
        case HiveParser.TOK_GRANT:
        case HiveParser.TOK_REVOKE_ROLE:
        case HiveParser.TOK_REVOKE:
        case HiveParser.TOK_SHOW_GRANT:
        case HiveParser.TOK_SHOW_ROLE_GRANT:

            // Misc DDL
        case HiveParser.TOK_LOCKTABLE:
        case HiveParser.TOK_UNLOCKTABLE:
        case HiveParser.TOK_SHOWLOCKS:
        case HiveParser.TOK_DESCFUNCTION:
        case HiveParser.TOK_SHOWFUNCTIONS:
        case HiveParser.TOK_EXPLAIN:

            // Table DDL
        case HiveParser.TOK_ALTERTABLE_ADDPARTS:
        case HiveParser.TOK_ALTERTABLE_ADDCOLS:
        case HiveParser.TOK_ALTERTABLE_CHANGECOL_AFTER_POSITION:
        case HiveParser.TOK_ALTERTABLE_SERDEPROPERTIES:
        case HiveParser.TOK_ALTERTABLE_CLUSTER_SORT:
        case HiveParser.TOK_ALTERTABLE_DROPPARTS:
        case HiveParser.TOK_ALTERTABLE_PROPERTIES:
        case HiveParser.TOK_ALTERTABLE_RENAME:
        case HiveParser.TOK_ALTERTABLE_RENAMECOL:
        case HiveParser.TOK_ALTERTABLE_REPLACECOLS:
        case HiveParser.TOK_ALTERTABLE_SERIALIZER:
        case HiveParser.TOK_ALTERTABLE_TOUCH:
        case HiveParser.TOK_DESCTABLE:
        case HiveParser.TOK_DROPTABLE:
        case HiveParser.TOK_SHOW_TABLESTATUS:
        case HiveParser.TOK_SHOWPARTITIONS:
        case HiveParser.TOK_SHOWTABLES:
            return ast;

        // In all other cases, throw an exception. Its a white-list of allowed operations.
        default:
            throw new SemanticException("Operation not supported.");

        }
    }

    @Override
    public void postAnalyze(HiveSemanticAnalyzerHookContext context,
                            List<Task<? extends Serializable>> rootTasks) throws SemanticException {

        try {

            switch (ast.getToken().getType()) {

            case HiveParser.TOK_CREATETABLE:
            case HiveParser.TOK_CREATEDATABASE:
            case HiveParser.TOK_ALTERTABLE_PARTITION:

                // HCat will allow these operations to be performed.
                // Database DDL
            case HiveParser.TOK_SHOWDATABASES:
            case HiveParser.TOK_DROPDATABASE:
            case HiveParser.TOK_SWITCHDATABASE:
            case HiveParser.TOK_DESCDATABASE:
            case HiveParser.TOK_ALTERDATABASE_PROPERTIES:

                // Index DDL
            case HiveParser.TOK_ALTERINDEX_PROPERTIES:
            case HiveParser.TOK_CREATEINDEX:
            case HiveParser.TOK_DROPINDEX:
            case HiveParser.TOK_SHOWINDEXES:

                // View DDL
                //case HiveParser.TOK_ALTERVIEW_ADDPARTS:
            case HiveParser.TOK_ALTERVIEW_DROPPARTS:
            case HiveParser.TOK_ALTERVIEW_PROPERTIES:
            case HiveParser.TOK_ALTERVIEW_RENAME:
            case HiveParser.TOK_CREATEVIEW:
            case HiveParser.TOK_DROPVIEW:

                // Authorization DDL
            case HiveParser.TOK_CREATEROLE:
            case HiveParser.TOK_DROPROLE:
            case HiveParser.TOK_GRANT_ROLE:
            case HiveParser.TOK_GRANT_WITH_OPTION:
            case HiveParser.TOK_GRANT:
            case HiveParser.TOK_REVOKE_ROLE:
            case HiveParser.TOK_REVOKE:
            case HiveParser.TOK_SHOW_GRANT:
            case HiveParser.TOK_SHOW_ROLE_GRANT:

                // Misc DDL
            case HiveParser.TOK_LOCKTABLE:
            case HiveParser.TOK_UNLOCKTABLE:
            case HiveParser.TOK_SHOWLOCKS:
            case HiveParser.TOK_DESCFUNCTION:
            case HiveParser.TOK_SHOWFUNCTIONS:
            case HiveParser.TOK_EXPLAIN:

                // Table DDL
            case HiveParser.TOK_ALTERTABLE_ADDPARTS:
            case HiveParser.TOK_ALTERTABLE_ADDCOLS:
            case HiveParser.TOK_ALTERTABLE_CHANGECOL_AFTER_POSITION:
            case HiveParser.TOK_ALTERTABLE_SERDEPROPERTIES:
            case HiveParser.TOK_ALTERTABLE_CLUSTER_SORT:
            case HiveParser.TOK_ALTERTABLE_DROPPARTS:
            case HiveParser.TOK_ALTERTABLE_PROPERTIES:
            case HiveParser.TOK_ALTERTABLE_RENAME:
            case HiveParser.TOK_ALTERTABLE_RENAMECOL:
            case HiveParser.TOK_ALTERTABLE_REPLACECOLS:
            case HiveParser.TOK_ALTERTABLE_SERIALIZER:
            case HiveParser.TOK_ALTERTABLE_TOUCH:
            case HiveParser.TOK_DESCTABLE:
            case HiveParser.TOK_DROPTABLE:
            case HiveParser.TOK_SHOW_TABLESTATUS:
            case HiveParser.TOK_SHOWPARTITIONS:
            case HiveParser.TOK_SHOWTABLES:
                break;

            default:
                throw new HCatException(ErrorType.ERROR_INTERNAL_EXCEPTION, "Unexpected token: " + ast.getToken());
            }

            authorizeDDL(context, rootTasks);

        } catch (HCatException e) {
            throw new SemanticException(e);
        } catch (HiveException e) {
            throw new SemanticException(e);
        }

        if (hook != null) {
            hook.postAnalyze(context, rootTasks);
        }
    }

    private String extractTableName(String compoundName) {
        /*
        * the table name can potentially be a dot-format one with column names
        * specified as part of the table name. e.g. a.b.c where b is a column in
        * a and c is a field of the object/column b etc. For authorization
        * purposes, we should use only the first part of the dotted name format.
        *
        */

        String[] words = compoundName.split("\\.");
        return words[0];
    }

    @Override
    protected void authorizeDDLWork(HiveSemanticAnalyzerHookContext cntxt, Hive hive, DDLWork work)
        throws HiveException {
        // DB opereations, none of them are enforced by Hive right now.

        ShowDatabasesDesc showDatabases = work.getShowDatabasesDesc();
        if (showDatabases != null) {
            authorize(HiveOperation.SHOWDATABASES.getInputRequiredPrivileges(),
                HiveOperation.SHOWDATABASES.getOutputRequiredPrivileges());
        }

        DropDatabaseDesc dropDb = work.getDropDatabaseDesc();
        if (dropDb != null) {
            Database db = cntxt.getHive().getDatabase(dropDb.getDatabaseName());
            authorize(db, Privilege.DROP);
        }

        DescDatabaseDesc descDb = work.getDescDatabaseDesc();
        if (descDb != null) {
            Database db = cntxt.getHive().getDatabase(descDb.getDatabaseName());
            authorize(db, Privilege.SELECT);
        }

        SwitchDatabaseDesc switchDb = work.getSwitchDatabaseDesc();
        if (switchDb != null) {
            Database db = cntxt.getHive().getDatabase(switchDb.getDatabaseName());
            authorize(db, Privilege.SELECT);
        }

        ShowTablesDesc showTables = work.getShowTblsDesc();
        if (showTables != null) {
            String dbName = showTables.getDbName() == null ? cntxt.getHive().getCurrentDatabase()
                : showTables.getDbName();
            authorize(cntxt.getHive().getDatabase(dbName), Privilege.SELECT);
        }

        ShowTableStatusDesc showTableStatus = work.getShowTblStatusDesc();
        if (showTableStatus != null) {
            String dbName = showTableStatus.getDbName() == null ? cntxt.getHive().getCurrentDatabase()
                : showTableStatus.getDbName();
            authorize(cntxt.getHive().getDatabase(dbName), Privilege.SELECT);
        }

        // TODO: add alter database support in HCat

        // Table operations.

        DropTableDesc dropTable = work.getDropTblDesc();
        if (dropTable != null) {
            if (dropTable.getPartSpecs() == null) {
                // drop table is already enforced by Hive. We only check for table level location even if the
                // table is partitioned.
            } else {
                //this is actually a ALTER TABLE DROP PARITITION statement
                for (PartitionSpec partSpec : dropTable.getPartSpecs()) {
                    // partitions are not added as write entries in drop partitions in Hive
                    Table table = hive.getTable(hive.getCurrentDatabase(), dropTable.getTableName());
                    List<Partition> partitions = null;
                    try {
                        partitions = hive.getPartitionsByFilter(table, partSpec.toString());
                    } catch (Exception e) {
                        throw new HiveException(e);
                    }

                    for (Partition part : partitions) {
                        authorize(part, Privilege.DROP);
                    }
                }
            }
        }

        AlterTableDesc alterTable = work.getAlterTblDesc();
        if (alterTable != null) {
            Table table = hive.getTable(hive.getCurrentDatabase(), alterTable.getOldName(), false);

            Partition part = null;
            if (alterTable.getPartSpec() != null) {
                part = hive.getPartition(table, alterTable.getPartSpec(), false);
            }

            String newLocation = alterTable.getNewLocation();

            /* Hcat requires ALTER_DATA privileges for ALTER TABLE LOCATION statements
            * for the old table/partition location and the new location.
            */
            if (alterTable.getOp() == AlterTableDesc.AlterTableTypes.ALTERLOCATION) {
                if (part != null) {
                    authorize(part, Privilege.ALTER_DATA); // authorize for the old
                    // location, and new location
                    part.setLocation(newLocation);
                    authorize(part, Privilege.ALTER_DATA);
                } else {
                    authorize(table, Privilege.ALTER_DATA); // authorize for the old
                    // location, and new location
                    table.getTTable().getSd().setLocation(newLocation);
                    authorize(table, Privilege.ALTER_DATA);
                }
            }
            //other alter operations are already supported by Hive
        }

        // we should be careful when authorizing table based on just the
        // table name. If columns have separate authorization domain, it
        // must be honored
        DescTableDesc descTable = work.getDescTblDesc();
        if (descTable != null) {
            String tableName = extractTableName(descTable.getTableName());
            authorizeTable(cntxt.getHive(), tableName, Privilege.SELECT);
        }

        ShowPartitionsDesc showParts = work.getShowPartsDesc();
        if (showParts != null) {
            String tableName = extractTableName(showParts.getTabName());
            authorizeTable(cntxt.getHive(), tableName, Privilege.SELECT);
        }
    }
}
TOP

Related Classes of org.apache.hcatalog.cli.SemanticAnalysis.HCatSemanticAnalyzer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.