diff --git ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java index cbc471e..3aed787 100644 --- ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java +++ ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java @@ -295,6 +295,8 @@ public enum ErrorMsg { "Please use the following syntax if not sure " + "whether the property existed or not:\n" + "ALTER TABLE tableName UNSET TBLPROPERTIES IF EXISTS (key1, key2, ...)\n"), + ALTER_VIEW_AS_SELECT_NOT_EXIST(10216, + "Cannot ALTER VIEW AS SELECT if view currently does not exist\n"), SCRIPT_INIT_ERROR(20000, "Unable to initialize custom script."), SCRIPT_IO_ERROR(20001, "An error occurred while reading or writing to your custom script. " diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g index ab27963..8f5ad23 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g +++ ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g @@ -199,6 +199,7 @@ TOK_CREATEFUNCTION; TOK_DROPFUNCTION; TOK_CREATEVIEW; TOK_DROPVIEW; +TOK_ALTERVIEW_AS; TOK_ALTERVIEW_PROPERTIES; TOK_DROPVIEW_PROPERTIES; TOK_ALTERVIEW_ADDPARTS; @@ -629,6 +630,8 @@ alterViewStatementSuffix -> ^(TOK_ALTERVIEW_ADDPARTS alterStatementSuffixAddPartitions) | alterStatementSuffixDropPartitions -> ^(TOK_ALTERVIEW_DROPPARTS alterStatementSuffixDropPartitions) + | name=tableName KW_AS selectStatement + -> ^(TOK_ALTERVIEW_AS $name selectStatement) ; alterIndexStatementSuffix diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java index f65ee96..55108b7 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java +++ ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java @@ -8211,7 +8211,8 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer { } // analyze create view command - if (ast.getToken().getType() == HiveParser.TOK_CREATEVIEW) { + if (ast.getToken().getType() == HiveParser.TOK_CREATEVIEW || + ast.getToken().getType() == HiveParser.TOK_ALTERVIEW_AS) { child = analyzeCreateView(ast, qb); SessionState.get().setCommandType(HiveOperation.CREATEVIEW); if (child == null) { @@ -8918,6 +8919,7 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer { List cols = null; boolean ifNotExists = false; boolean orReplace = false; + boolean isAlterViewAs = false; String comment = null; ASTNode selectStmt = null; Map tblProps = null; @@ -8959,8 +8961,31 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer { throw new SemanticException("Can't combine IF NOT EXISTS and OR REPLACE."); } + if (ast.getToken().getType() == HiveParser.TOK_ALTERVIEW_AS) { + isAlterViewAs = true; + orReplace = true; + } + createVwDesc = new CreateViewDesc( - tableName, cols, comment, tblProps, partColNames, ifNotExists, orReplace); + tableName, cols, comment, tblProps, partColNames, + ifNotExists, orReplace, isAlterViewAs); + + // alter view as select + // requires the view must exist + if (ast.getToken().getType() == HiveParser.TOK_ALTERVIEW_AS) { + String errorMsg = "The following view does not exist: " + createVwDesc.getViewName(); + try { + Table oldview = db.getTable(createVwDesc.getViewName(), false); + if (createVwDesc.getIsAlterViewAs() && oldview == null) { + throw new SemanticException( + ErrorMsg.ALTER_VIEW_AS_SELECT_NOT_EXIST.getMsg(errorMsg)); + } + } catch (HiveException e) { + throw new SemanticException( + ErrorMsg.ALTER_VIEW_AS_SELECT_NOT_EXIST.getMsg(errorMsg)); + } + } + unparseTranslator.enable(); rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), createVwDesc), conf)); diff --git ql/src/java/org/apache/hadoop/hive/ql/plan/CreateViewDesc.java ql/src/java/org/apache/hadoop/hive/ql/plan/CreateViewDesc.java index cf398dd..30549e7 100644 --- ql/src/java/org/apache/hadoop/hive/ql/plan/CreateViewDesc.java +++ ql/src/java/org/apache/hadoop/hive/ql/plan/CreateViewDesc.java @@ -43,6 +43,7 @@ public class CreateViewDesc extends DDLDesc implements Serializable { private String comment; private boolean ifNotExists; private boolean orReplace; + private boolean isAlterViewAs; /** * For serialization only. @@ -52,7 +53,8 @@ public class CreateViewDesc extends DDLDesc implements Serializable { public CreateViewDesc(String viewName, List schema, String comment, Map tblProps, - List partColNames, boolean ifNotExists, boolean orReplace) { + List partColNames, boolean ifNotExists, + boolean orReplace, boolean isAlterViewAs) { this.viewName = viewName; this.schema = schema; this.comment = comment; @@ -60,6 +62,7 @@ public class CreateViewDesc extends DDLDesc implements Serializable { this.partColNames = partColNames; this.ifNotExists = ifNotExists; this.orReplace = orReplace; + this.isAlterViewAs = isAlterViewAs; } @Explain(displayName = "name") @@ -158,4 +161,13 @@ public class CreateViewDesc extends DDLDesc implements Serializable { public void setOrReplace(boolean orReplace) { this.orReplace = orReplace; } + + @Explain(displayName = "is alter view as select") + public boolean getIsAlterViewAs() { + return isAlterViewAs; + } + + public void setIsAlterViewAs(boolean isAlterViewAs) { + this.isAlterViewAs = isAlterViewAs; + } } diff --git ql/src/test/queries/clientnegative/alter_view_as_select_not_exist.q ql/src/test/queries/clientnegative/alter_view_as_select_not_exist.q new file mode 100644 index 0000000..30fe4d9 --- /dev/null +++ ql/src/test/queries/clientnegative/alter_view_as_select_not_exist.q @@ -0,0 +1,4 @@ +DROP VIEW testView; + +-- Cannot ALTER VIEW AS SELECT if view currently does not exist +ALTER VIEW testView AS SELECT * FROM srcpart; diff --git ql/src/test/queries/clientnegative/alter_view_as_select_with_partition.q ql/src/test/queries/clientnegative/alter_view_as_select_with_partition.q new file mode 100644 index 0000000..dca6770 --- /dev/null +++ ql/src/test/queries/clientnegative/alter_view_as_select_with_partition.q @@ -0,0 +1,12 @@ +CREATE VIEW testViewPart PARTITIONED ON (value) +AS +SELECT key, value +FROM src +WHERE key=86; + +ALTER VIEW testViewPart +ADD PARTITION (value='val_86') PARTITION (value='val_xyz'); +DESCRIBE FORMATTED testViewPart; + +-- If a view has partition, could not replace it with ALTER VIEW AS SELECT +ALTER VIEW testViewPart as SELECT * FROM srcpart; diff --git ql/src/test/queries/clientpositive/alter_view_as_select.q ql/src/test/queries/clientpositive/alter_view_as_select.q new file mode 100644 index 0000000..dcab3ca --- /dev/null +++ ql/src/test/queries/clientpositive/alter_view_as_select.q @@ -0,0 +1,13 @@ +DROP VIEW testView; +CREATE VIEW testView as SELECT * FROM srcpart; +DESCRIBE FORMATTED testView; + +ALTER VIEW testView AS SELECT value FROM src WHERE key=86; +DESCRIBE FORMATTED testView; + +ALTER VIEW testView AS +SELECT * FROM src +WHERE key > 80 AND key < 100 +ORDER BY key, value +LIMIT 10; +DESCRIBE FORMATTED testView; diff --git ql/src/test/results/clientnegative/alter_view_as_select_not_exist.q.out ql/src/test/results/clientnegative/alter_view_as_select_not_exist.q.out new file mode 100644 index 0000000..66deaac --- /dev/null +++ ql/src/test/results/clientnegative/alter_view_as_select_not_exist.q.out @@ -0,0 +1,6 @@ +PREHOOK: query: DROP VIEW testView +PREHOOK: type: DROPVIEW +POSTHOOK: query: DROP VIEW testView +POSTHOOK: type: DROPVIEW +FAILED: SemanticException [Error 10216]: Cannot ALTER VIEW AS SELECT if view currently does not exist + The following view does not exist: testView diff --git ql/src/test/results/clientnegative/alter_view_as_select_with_partition.q.out ql/src/test/results/clientnegative/alter_view_as_select_with_partition.q.out new file mode 100644 index 0000000..0820974 --- /dev/null +++ ql/src/test/results/clientnegative/alter_view_as_select_with_partition.q.out @@ -0,0 +1,71 @@ +PREHOOK: query: CREATE VIEW testViewPart PARTITIONED ON (value) +AS +SELECT key, value +FROM src +WHERE key=86 +PREHOOK: type: CREATEVIEW +#### A masked pattern was here #### +POSTHOOK: query: CREATE VIEW testViewPart PARTITIONED ON (value) +AS +SELECT key, value +FROM src +WHERE key=86 +POSTHOOK: type: CREATEVIEW +POSTHOOK: Output: default@testViewPart +#### A masked pattern was here #### +PREHOOK: query: ALTER VIEW testViewPart +ADD PARTITION (value='val_86') PARTITION (value='val_xyz') +PREHOOK: type: ALTERTABLE_ADDPARTS +PREHOOK: Input: default@src +PREHOOK: Input: default@testviewpart +POSTHOOK: query: ALTER VIEW testViewPart +ADD PARTITION (value='val_86') PARTITION (value='val_xyz') +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Input: default@src +POSTHOOK: Input: default@testviewpart +POSTHOOK: Output: default@testviewpart@value=val_86 +POSTHOOK: Output: default@testviewpart@value=val_xyz +PREHOOK: query: DESCRIBE FORMATTED testViewPart +PREHOOK: type: DESCTABLE +POSTHOOK: query: DESCRIBE FORMATTED testViewPart +POSTHOOK: type: DESCTABLE +# col_name data_type comment + +key string None + +# Partition Information +# col_name data_type comment + +value string None + +# Detailed Table Information +Database: default +#### A masked pattern was here #### +Protect Mode: None +Retention: 0 +Table Type: VIRTUAL_VIEW +Table Parameters: +#### A masked pattern was here #### + +# Storage Information +SerDe Library: null +InputFormat: org.apache.hadoop.mapred.SequenceFileInputFormat +OutputFormat: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat +Compressed: No +Num Buckets: -1 +Bucket Columns: [] +Sort Columns: [] + +# View Information +View Original Text: SELECT key, value +FROM src +WHERE key=86 +View Expanded Text: SELECT `src`.`key`, `src`.`value` +FROM `default`.`src` +WHERE `src`.`key`=86 +PREHOOK: query: -- If a view has partition, could not replace it with ALTER VIEW AS SELECT +ALTER VIEW testViewPart as SELECT * FROM srcpart +PREHOOK: type: CREATEVIEW +#### A masked pattern was here #### +FAILED: Error in metadata: Cannot add or drop partition columns with CREATE OR REPLACE VIEW if partitions currently exist +FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask diff --git ql/src/test/results/clientpositive/alter_view_as_select.q.out ql/src/test/results/clientpositive/alter_view_as_select.q.out new file mode 100644 index 0000000..bc00e1e --- /dev/null +++ ql/src/test/results/clientpositive/alter_view_as_select.q.out @@ -0,0 +1,130 @@ +PREHOOK: query: DROP VIEW testView +PREHOOK: type: DROPVIEW +POSTHOOK: query: DROP VIEW testView +POSTHOOK: type: DROPVIEW +PREHOOK: query: CREATE VIEW testView as SELECT * FROM srcpart +PREHOOK: type: CREATEVIEW +#### A masked pattern was here #### +POSTHOOK: query: CREATE VIEW testView as SELECT * FROM srcpart +POSTHOOK: type: CREATEVIEW +POSTHOOK: Output: default@testView +#### A masked pattern was here #### +PREHOOK: query: DESCRIBE FORMATTED testView +PREHOOK: type: DESCTABLE +POSTHOOK: query: DESCRIBE FORMATTED testView +POSTHOOK: type: DESCTABLE +# col_name data_type comment + +key string None +value string None +ds string None +hr string None + +# Detailed Table Information +Database: default +#### A masked pattern was here #### +Protect Mode: None +Retention: 0 +Table Type: VIRTUAL_VIEW +Table Parameters: +#### A masked pattern was here #### + +# Storage Information +SerDe Library: null +InputFormat: org.apache.hadoop.mapred.SequenceFileInputFormat +OutputFormat: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat +Compressed: No +Num Buckets: -1 +Bucket Columns: [] +Sort Columns: [] + +# View Information +View Original Text: SELECT * FROM srcpart +View Expanded Text: SELECT `srcpart`.`key`, `srcpart`.`value`, `srcpart`.`ds`, `srcpart`.`hr` FROM `default`.`srcpart` +PREHOOK: query: ALTER VIEW testView AS SELECT value FROM src WHERE key=86 +PREHOOK: type: CREATEVIEW +#### A masked pattern was here #### +POSTHOOK: query: ALTER VIEW testView AS SELECT value FROM src WHERE key=86 +POSTHOOK: type: CREATEVIEW +POSTHOOK: Output: default@testview +#### A masked pattern was here #### +PREHOOK: query: DESCRIBE FORMATTED testView +PREHOOK: type: DESCTABLE +POSTHOOK: query: DESCRIBE FORMATTED testView +POSTHOOK: type: DESCTABLE +# col_name data_type comment + +value string None + +# Detailed Table Information +Database: default +#### A masked pattern was here #### +Protect Mode: None +Retention: 0 +Table Type: VIRTUAL_VIEW +Table Parameters: +#### A masked pattern was here #### + +# Storage Information +SerDe Library: null +InputFormat: org.apache.hadoop.mapred.SequenceFileInputFormat +OutputFormat: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat +Compressed: No +Num Buckets: -1 +Bucket Columns: [] +Sort Columns: [] + +# View Information +View Original Text: SELECT value FROM src WHERE key=86 +View Expanded Text: SELECT `src`.`value` FROM `default`.`src` WHERE `src`.`key`=86 +PREHOOK: query: ALTER VIEW testView AS +SELECT * FROM src +WHERE key > 80 AND key < 100 +ORDER BY key, value +LIMIT 10 +PREHOOK: type: CREATEVIEW +#### A masked pattern was here #### +POSTHOOK: query: ALTER VIEW testView AS +SELECT * FROM src +WHERE key > 80 AND key < 100 +ORDER BY key, value +LIMIT 10 +POSTHOOK: type: CREATEVIEW +POSTHOOK: Output: default@testview +#### A masked pattern was here #### +PREHOOK: query: DESCRIBE FORMATTED testView +PREHOOK: type: DESCTABLE +POSTHOOK: query: DESCRIBE FORMATTED testView +POSTHOOK: type: DESCTABLE +# col_name data_type comment + +key string None +value string None + +# Detailed Table Information +Database: default +#### A masked pattern was here #### +Protect Mode: None +Retention: 0 +Table Type: VIRTUAL_VIEW +Table Parameters: +#### A masked pattern was here #### + +# Storage Information +SerDe Library: null +InputFormat: org.apache.hadoop.mapred.SequenceFileInputFormat +OutputFormat: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat +Compressed: No +Num Buckets: -1 +Bucket Columns: [] +Sort Columns: [] + +# View Information +View Original Text: SELECT * FROM src +WHERE key > 80 AND key < 100 +ORDER BY key, value +LIMIT 10 +View Expanded Text: SELECT `src`.`key`, `src`.`value` FROM `default`.`src` +WHERE `src`.`key` > 80 AND `src`.`key` < 100 +ORDER BY `src`.`key`, `src`.`value` +LIMIT 10