| /** |
| * 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.IOException; |
| import java.io.Serializable; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.hive.conf.HiveConf; |
| import org.apache.hadoop.hive.metastore.api.FieldSchema; |
| import org.apache.hadoop.hive.ql.exec.DDLTask; |
| import org.apache.hadoop.hive.ql.exec.Task; |
| import org.apache.hadoop.hive.ql.io.RCFileInputFormat; |
| import org.apache.hadoop.hive.ql.io.RCFileOutputFormat; |
| import org.apache.hadoop.hive.ql.metadata.Hive; |
| import org.apache.hadoop.hive.ql.metadata.HiveException; |
| import org.apache.hadoop.hive.ql.metadata.Table; |
| import org.apache.hadoop.hive.ql.parse.ASTNode; |
| import org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer; |
| 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.CreateTableDesc; |
| import org.apache.hadoop.hive.ql.security.authorization.Privilege; |
| import org.apache.hcatalog.common.HCatConstants; |
| import org.apache.hcatalog.common.HCatUtil; |
| import org.apache.hcatalog.mapreduce.HCatStorageHandler; |
| |
| final class CreateTableHook extends HCatSemanticAnalyzerBase { |
| |
| private String tableName; |
| |
| @Override |
| public ASTNode preAnalyze(HiveSemanticAnalyzerHookContext context, |
| ASTNode ast) throws SemanticException { |
| |
| Hive db; |
| try { |
| db = context.getHive(); |
| } catch (HiveException e) { |
| throw new SemanticException( |
| "Couldn't get Hive DB instance in semantic analysis phase.", |
| e); |
| } |
| |
| // Analyze and create tbl properties object |
| int numCh = ast.getChildCount(); |
| |
| String inputFormat = null, outputFormat = null; |
| tableName = BaseSemanticAnalyzer.getUnescapedName((ASTNode) ast |
| .getChild(0)); |
| boolean likeTable = false; |
| |
| for (int num = 1; num < numCh; num++) { |
| ASTNode child = (ASTNode) ast.getChild(num); |
| |
| switch (child.getToken().getType()) { |
| |
| case HiveParser.TOK_QUERY: // CTAS |
| throw new SemanticException( |
| "Operation not supported. Create table as " + |
| "Select is not a valid operation."); |
| |
| case HiveParser.TOK_TABLEBUCKETS: |
| break; |
| |
| case HiveParser.TOK_TBLSEQUENCEFILE: |
| inputFormat = HCatConstants.SEQUENCEFILE_INPUT; |
| outputFormat = HCatConstants.SEQUENCEFILE_OUTPUT; |
| break; |
| |
| case HiveParser.TOK_TBLTEXTFILE: |
| inputFormat = org.apache.hadoop.mapred.TextInputFormat.class.getName(); |
| outputFormat = org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat.class.getName(); |
| |
| break; |
| |
| case HiveParser.TOK_LIKETABLE: |
| likeTable = true; |
| break; |
| |
| case HiveParser.TOK_IFNOTEXISTS: |
| try { |
| List<String> tables = db.getTablesByPattern(tableName); |
| if (tables != null && tables.size() > 0) { // table |
| // exists |
| return ast; |
| } |
| } catch (HiveException e) { |
| throw new SemanticException(e); |
| } |
| break; |
| |
| case HiveParser.TOK_TABLEPARTCOLS: |
| List<FieldSchema> partCols = BaseSemanticAnalyzer |
| .getColumns((ASTNode) child.getChild(0), false); |
| for (FieldSchema fs : partCols) { |
| if (!fs.getType().equalsIgnoreCase("string")) { |
| throw new SemanticException( |
| "Operation not supported. HCatalog only " + |
| "supports partition columns of type string. " |
| + "For column: " |
| + fs.getName() |
| + " Found type: " + fs.getType()); |
| } |
| } |
| break; |
| |
| case HiveParser.TOK_STORAGEHANDLER: |
| String storageHandler = BaseSemanticAnalyzer |
| .unescapeSQLString(child.getChild(0).getText()); |
| if (org.apache.commons.lang.StringUtils |
| .isNotEmpty(storageHandler)) { |
| return ast; |
| } |
| |
| break; |
| |
| case HiveParser.TOK_TABLEFILEFORMAT: |
| if (child.getChildCount() < 2) { |
| throw new SemanticException( |
| "Incomplete specification of File Format. " + |
| "You must provide InputFormat, OutputFormat."); |
| } |
| inputFormat = BaseSemanticAnalyzer.unescapeSQLString(child |
| .getChild(0).getText()); |
| outputFormat = BaseSemanticAnalyzer.unescapeSQLString(child |
| .getChild(1).getText()); |
| break; |
| |
| case HiveParser.TOK_TBLRCFILE: |
| inputFormat = RCFileInputFormat.class.getName(); |
| outputFormat = RCFileOutputFormat.class.getName(); |
| break; |
| |
| } |
| } |
| |
| if (!likeTable && (inputFormat == null || outputFormat == null)) { |
| throw new SemanticException( |
| "STORED AS specification is either incomplete or incorrect."); |
| } |
| |
| |
| return ast; |
| } |
| |
| @Override |
| public void postAnalyze(HiveSemanticAnalyzerHookContext context, |
| List<Task<? extends Serializable>> rootTasks) |
| throws SemanticException { |
| |
| if (rootTasks.size() == 0) { |
| // There will be no DDL task created in case if its CREATE TABLE IF |
| // NOT EXISTS |
| return; |
| } |
| CreateTableDesc desc = ((DDLTask) rootTasks.get(rootTasks.size() - 1)) |
| .getWork().getCreateTblDesc(); |
| if (desc == null) { |
| // Desc will be null if its CREATE TABLE LIKE. Desc will be |
| // contained in CreateTableLikeDesc. Currently, HCat disallows CTLT in |
| // pre-hook. So, desc can never be null. |
| return; |
| } |
| Map<String, String> tblProps = desc.getTblProps(); |
| if (tblProps == null) { |
| // tblProps will be null if user didnt use tblprops in his CREATE |
| // TABLE cmd. |
| tblProps = new HashMap<String, String>(); |
| |
| } |
| |
| // first check if we will allow the user to create table. |
| String storageHandler = desc.getStorageHandler(); |
| if (StringUtils.isEmpty(storageHandler)) { |
| } else { |
| try { |
| HCatStorageHandler storageHandlerInst = HCatUtil |
| .getStorageHandler(context.getConf(), |
| desc.getStorageHandler(), |
| desc.getSerName(), |
| desc.getInputFormat(), |
| desc.getOutputFormat()); |
| //Authorization checks are performed by the storageHandler.getAuthorizationProvider(), if |
| //StorageDelegationAuthorizationProvider is used. |
| } catch (IOException e) { |
| throw new SemanticException(e); |
| } |
| } |
| |
| if (desc != null) { |
| try { |
| Table table = context.getHive().newTable(desc.getTableName()); |
| if (desc.getLocation() != null) { |
| table.setDataLocation(new Path(desc.getLocation()).toUri()); |
| } |
| if (desc.getStorageHandler() != null) { |
| table.setProperty( |
| org.apache.hadoop.hive.metastore.api.hive_metastoreConstants.META_TABLE_STORAGE, |
| desc.getStorageHandler()); |
| } |
| for (Map.Entry<String, String> prop : tblProps.entrySet()) { |
| table.setProperty(prop.getKey(), prop.getValue()); |
| } |
| for (Map.Entry<String, String> prop : desc.getSerdeProps().entrySet()) { |
| table.setSerdeParam(prop.getKey(), prop.getValue()); |
| } |
| //TODO: set other Table properties as needed |
| |
| //authorize against the table operation so that location permissions can be checked if any |
| |
| if (HiveConf.getBoolVar(context.getConf(), |
| HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED)) { |
| authorize(table, Privilege.CREATE); |
| } |
| } catch (HiveException ex) { |
| throw new SemanticException(ex); |
| } |
| } |
| |
| desc.setTblProps(tblProps); |
| context.getConf().set(HCatConstants.HCAT_CREATE_TBL_NAME, tableName); |
| } |
| } |