diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java index 7e0cb23..a256968 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java @@ -155,6 +155,7 @@ import org.apache.hadoop.hive.ql.plan.ExprNodeConstantDesc; import org.apache.hadoop.hive.ql.plan.ExprNodeDesc; import org.apache.hadoop.hive.ql.plan.ExprNodeDescUtils; +import org.apache.hadoop.hive.ql.plan.ExprNodeFieldDesc; import org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc; import org.apache.hadoop.hive.ql.plan.FileSinkDesc; import org.apache.hadoop.hive.ql.plan.FilterDesc; @@ -10539,6 +10540,8 @@ private ExprNodeDesc getExprNodeDescCached(ASTNode expr, RowResolver input) // Not creating a view, so no need to track view expansions. return nodeOutputs; } + + Map nodeToText = new HashMap<>(); for (Map.Entry entry : nodeOutputs.entrySet()) { if (!(entry.getValue() instanceof ExprNodeColumnDesc)) { @@ -10557,9 +10560,48 @@ private ExprNodeDesc getExprNodeDescCached(ASTNode expr, RowResolver input) replacementText.append(HiveUtils.unparseIdentifier(tmp[0], conf)); replacementText.append("."); replacementText.append(HiveUtils.unparseIdentifier(tmp[1], conf)); + nodeToText.put(columnDesc, replacementText.toString()); unparseTranslator.addTranslation(node, replacementText.toString()); } - + + // we need to translate the ExprNodeFieldDesc too, e.g., identifiers in + // struct<>. + Map fieldDescMap = new HashMap<>(); + for (Map.Entry entry : nodeOutputs.entrySet()) { + if (entry.getValue() instanceof ExprNodeFieldDesc) { + fieldDescMap.put(entry.getKey(), entry.getValue()); + } + } + while (fieldDescMap.size() != 0) { + ASTNode find = null; + // pick the most inner ASTNode + for (Map.Entry entry : fieldDescMap.entrySet()) { + ASTNode node = entry.getKey(); + ExprNodeFieldDesc fieldDesc = (ExprNodeFieldDesc) entry.getValue(); + if (nodeToText.containsKey(fieldDesc)) { + continue; + } else { + ExprNodeDesc exprNodeDesc = fieldDesc.getDesc(); + if (nodeToText.containsKey(exprNodeDesc)) { + find = node; + String fieldName = fieldDesc.getFieldName(); + StringBuilder replacementText = new StringBuilder(); + replacementText.append(nodeToText.get(exprNodeDesc)); + replacementText.append("."); + replacementText.append(HiveUtils.unparseIdentifier(fieldName, conf)); + nodeToText.put(fieldDesc, replacementText.toString()); + unparseTranslator.addTranslation(node, replacementText.toString()); + break; + } + } + } + if (find == null) { + throw new SemanticException("Can not find replacement text for ASTNode " + expr.dump()); + } else { + fieldDescMap.remove(find); + } + } + return nodeOutputs; } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/UnparseTranslator.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/UnparseTranslator.java index 4ca8329..29c2365 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/UnparseTranslator.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/UnparseTranslator.java @@ -267,6 +267,10 @@ public String toString() { ASTNode sourceNode; } + public NavigableMap getTranslations() { + return translations; + } + public void clear() { translations.clear(); copyTranslations.clear(); diff --git a/ql/src/test/queries/clientpositive/struct_in_view.q b/ql/src/test/queries/clientpositive/struct_in_view.q new file mode 100644 index 0000000..d420030 --- /dev/null +++ b/ql/src/test/queries/clientpositive/struct_in_view.q @@ -0,0 +1,28 @@ +drop table testreserved; + +create table testreserved (data struct<`end`:string, id: string>); + +create view testreservedview as select data.`end` as data_end, data.id as data_id from testreserved; + +describe extended testreservedview; + +select data.`end` from testreserved; + +drop view testreservedview; + +drop table testreserved; + +create table s (default struct, id: string>, id: string>); + +create view vs1 as select default.src.`end`.key from s; + +describe extended vs1; + +create view vs2 as select default.src.`end` from s; + +describe extended vs2; + +drop view vs1; + +drop view vs2; + diff --git a/ql/src/test/results/clientpositive/struct_in_view.q.out b/ql/src/test/results/clientpositive/struct_in_view.q.out new file mode 100644 index 0000000..10b2f2e --- /dev/null +++ b/ql/src/test/results/clientpositive/struct_in_view.q.out @@ -0,0 +1,118 @@ +PREHOOK: query: drop table testreserved +PREHOOK: type: DROPTABLE +POSTHOOK: query: drop table testreserved +POSTHOOK: type: DROPTABLE +PREHOOK: query: create table testreserved (data struct<`end`:string, id: string>) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@testreserved +POSTHOOK: query: create table testreserved (data struct<`end`:string, id: string>) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@testreserved +PREHOOK: query: create view testreservedview as select data.`end` as data_end, data.id as data_id from testreserved +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@testreserved +PREHOOK: Output: database:default +PREHOOK: Output: default@testreservedview +POSTHOOK: query: create view testreservedview as select data.`end` as data_end, data.id as data_id from testreserved +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@testreserved +POSTHOOK: Output: database:default +POSTHOOK: Output: default@testreservedview +PREHOOK: query: describe extended testreservedview +PREHOOK: type: DESCTABLE +PREHOOK: Input: default@testreservedview +POSTHOOK: query: describe extended testreservedview +POSTHOOK: type: DESCTABLE +POSTHOOK: Input: default@testreservedview +data_end string +data_id string + +#### A masked pattern was here #### +PREHOOK: query: select data.`end` from testreserved +PREHOOK: type: QUERY +PREHOOK: Input: default@testreserved +#### A masked pattern was here #### +POSTHOOK: query: select data.`end` from testreserved +POSTHOOK: type: QUERY +POSTHOOK: Input: default@testreserved +#### A masked pattern was here #### +PREHOOK: query: drop view testreservedview +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@testreservedview +PREHOOK: Output: default@testreservedview +POSTHOOK: query: drop view testreservedview +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@testreservedview +POSTHOOK: Output: default@testreservedview +PREHOOK: query: drop table testreserved +PREHOOK: type: DROPTABLE +PREHOOK: Input: default@testreserved +PREHOOK: Output: default@testreserved +POSTHOOK: query: drop table testreserved +POSTHOOK: type: DROPTABLE +POSTHOOK: Input: default@testreserved +POSTHOOK: Output: default@testreserved +PREHOOK: query: create table s (default struct, id: string>, id: string>) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@s +POSTHOOK: query: create table s (default struct, id: string>, id: string>) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@s +PREHOOK: query: create view vs1 as select default.src.`end`.key from s +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@s +PREHOOK: Output: database:default +PREHOOK: Output: default@vs1 +POSTHOOK: query: create view vs1 as select default.src.`end`.key from s +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@s +POSTHOOK: Output: database:default +POSTHOOK: Output: default@vs1 +PREHOOK: query: describe extended vs1 +PREHOOK: type: DESCTABLE +PREHOOK: Input: default@vs1 +POSTHOOK: query: describe extended vs1 +POSTHOOK: type: DESCTABLE +POSTHOOK: Input: default@vs1 +key string + +#### A masked pattern was here #### +PREHOOK: query: create view vs2 as select default.src.`end` from s +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@s +PREHOOK: Output: database:default +PREHOOK: Output: default@vs2 +POSTHOOK: query: create view vs2 as select default.src.`end` from s +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@s +POSTHOOK: Output: database:default +POSTHOOK: Output: default@vs2 +PREHOOK: query: describe extended vs2 +PREHOOK: type: DESCTABLE +PREHOOK: Input: default@vs2 +POSTHOOK: query: describe extended vs2 +POSTHOOK: type: DESCTABLE +POSTHOOK: Input: default@vs2 +end struct + +#### A masked pattern was here #### +PREHOOK: query: drop view vs1 +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@vs1 +PREHOOK: Output: default@vs1 +POSTHOOK: query: drop view vs1 +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@vs1 +POSTHOOK: Output: default@vs1 +PREHOOK: query: drop view vs2 +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@vs2 +PREHOOK: Output: default@vs2 +POSTHOOK: query: drop view vs2 +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@vs2 +POSTHOOK: Output: default@vs2