diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/QB.java ql/src/java/org/apache/hadoop/hive/ql/parse/QB.java index 50b5a77..fa111cc 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/QB.java +++ ql/src/java/org/apache/hadoop/hive/ql/parse/QB.java @@ -65,6 +65,11 @@ */ private HashMap destToWindowingSpec; + /* + * If this QB represents a SubQuery predicate then this will point to the SubQuery object. + */ + private QBSubQuery subQueryPredicateDef; + // results public void print(String msg) { @@ -308,5 +313,12 @@ public boolean hasWindowingSpec(String dest) { return destToWindowingSpec; } + protected void setSubQueryDef(QBSubQuery subQueryPredicateDef) { + this.subQueryPredicateDef = subQueryPredicateDef; + } + + protected QBSubQuery getSubQueryPredicateDef() { + return subQueryPredicateDef; + } } 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 cf0c895..a9ef728 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java +++ ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java @@ -1792,7 +1792,15 @@ private Operator genFilterPlan(String dest, QB qb, Operator input, ASTNode searchCond = (ASTNode) whereExpr.getChild(0); List subQueriesInOriginalTree = SubQueryUtils.findSubQueries(searchCond); - if ( subQueriesInOriginalTree != null ) { + if ( subQueriesInOriginalTree.size() > 0 ) { + + /* + * Restriction.9.m :: disallow nested SubQuery expressions. + */ + if (qb.getSubQueryPredicateDef() != null ) { + throw new SemanticException(ErrorMsg.UNSUPPORTED_SUBQUERY_EXPRESSION.getMsg( + subQueriesInOriginalTree.get(0), "Nested SubQuery expressions are not supported.")); + } /* * Restriction.8.m :: We allow only 1 SubQuery expression per Query. @@ -1822,6 +1830,7 @@ private Operator genFilterPlan(String dest, QB qb, Operator input, subQuery.validateAndRewriteAST(inputRR); QB qbSQ = new QB(subQuery.getOuterQueryId(), subQuery.getAlias(), true); + qbSQ.setSubQueryDef(subQuery); Phase1Ctx ctx_1 = initPhase1Ctx(); doPhase1(subQuery.getSubQueryAST(), qbSQ, ctx_1); getMetaData(qbSQ); diff --git ql/src/java/org/apache/hadoop/hive/ql/parse/SubQueryUtils.java ql/src/java/org/apache/hadoop/hive/ql/parse/SubQueryUtils.java index 2d7775c..ddc096d 100644 --- ql/src/java/org/apache/hadoop/hive/ql/parse/SubQueryUtils.java +++ ql/src/java/org/apache/hadoop/hive/ql/parse/SubQueryUtils.java @@ -4,8 +4,6 @@ import java.util.List; import java.util.Map; -import org.antlr.runtime.tree.TreeWizard; -import org.antlr.runtime.tree.TreeWizard.ContextVisitor; import org.apache.hadoop.hive.ql.Context; import org.apache.hadoop.hive.ql.ErrorMsg; import org.apache.hadoop.hive.ql.exec.ColumnInfo; @@ -173,31 +171,22 @@ ASTNode remove() throws SemanticException { static List findSubQueries(ASTNode node) throws SemanticException { - TreeWizard tw = new TreeWizard(ParseDriver.adaptor, HiveParser.tokenNames); - SubQueryVisitor visitor = new SubQueryVisitor(); - tw.visit(node, HiveParser.TOK_SUBQUERY_EXPR, visitor); - return visitor.getSubQueries(); + List subQueries = new ArrayList(); + findSubQueries(node, subQueries); + return subQueries; } - static class SubQueryVisitor implements ContextVisitor { - String errMsg; - boolean throwError = false; - ASTNode errorNode; - List subQueries; - - @SuppressWarnings("rawtypes") - @Override - public void visit(Object t, Object parent, int childIndex, Map labels) { - if (subQueries == null ) { - subQueries = new ArrayList(); + private static void findSubQueries(ASTNode node, List subQueries) { + switch(node.getType()) { + case HiveParser.TOK_SUBQUERY_EXPR: + subQueries.add(node); + break; + default: + int childCount = node.getChildCount(); + for(int i=0; i < childCount; i++) { + findSubQueries((ASTNode) node.getChild(i), subQueries); } - subQueries.add((ASTNode)t); } - - public List getSubQueries() { - return subQueries; - } - } static QBSubQuery buildSubQuery(String outerQueryId, @@ -208,6 +197,16 @@ static QBSubQuery buildSubQuery(String outerQueryId, ASTNode sqOp = (ASTNode) sqAST.getChild(0); ASTNode sq = (ASTNode) sqAST.getChild(1); ASTNode outerQueryExpr = (ASTNode) sqAST.getChild(2); + + /* + * Restriction.8.m :: We allow only 1 SubQuery expression per Query. + */ + if (outerQueryExpr != null && outerQueryExpr.getType() == HiveParser.TOK_SUBQUERY_EXPR ) { + + throw new SemanticException(ErrorMsg.UNSUPPORTED_SUBQUERY_EXPRESSION.getMsg( + originalSQAST.getChild(1), "Only 1 SubQuery expression is supported.")); + } + return new QBSubQuery(outerQueryId, sqIdx, sq, outerQueryExpr, buildSQOperator(sqOp), originalSQAST, diff --git ql/src/test/queries/clientnegative/subquery_nested_subquery.q ql/src/test/queries/clientnegative/subquery_nested_subquery.q new file mode 100644 index 0000000..e8c41e6 --- /dev/null +++ ql/src/test/queries/clientnegative/subquery_nested_subquery.q @@ -0,0 +1,18 @@ + + +CREATE TABLE part( + p_partkey INT, + p_name STRING, + p_mfgr STRING, + p_brand STRING, + p_type STRING, + p_size INT, + p_container STRING, + p_retailprice DOUBLE, + p_comment STRING +); + +select * +from part x +where x.p_name in (select y.p_name from part y where exists (select z.p_name from part z where y.p_name = z.p_name)) +; \ No newline at end of file diff --git ql/src/test/results/clientnegative/subquery_nested_subquery.q.out ql/src/test/results/clientnegative/subquery_nested_subquery.q.out new file mode 100644 index 0000000..68a3a98 --- /dev/null +++ ql/src/test/results/clientnegative/subquery_nested_subquery.q.out @@ -0,0 +1,28 @@ +PREHOOK: query: CREATE TABLE part( + p_partkey INT, + p_name STRING, + p_mfgr STRING, + p_brand STRING, + p_type STRING, + p_size INT, + p_container STRING, + p_retailprice DOUBLE, + p_comment STRING +) +PREHOOK: type: CREATETABLE +POSTHOOK: query: CREATE TABLE part( + p_partkey INT, + p_name STRING, + p_mfgr STRING, + p_brand STRING, + p_type STRING, + p_size INT, + p_container STRING, + p_retailprice DOUBLE, + p_comment STRING +) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: default@part +FAILED: SemanticException Line 5:53 Unsupported SubQuery Expression 'p_name' in definition of SubQuery sq_1 [ +x.p_name in (select y.p_name from part y where exists (select z.p_name from part z where y.p_name = z.p_name)) +] used as sq_1 at Line 5:15: Nested SubQuery expressions are not supported. diff --git ql/src/test/results/clientnegative/subquery_subquery_chain.q.out ql/src/test/results/clientnegative/subquery_subquery_chain.q.out index 2eadfc3..448bfb2 100644 --- ql/src/test/results/clientnegative/subquery_subquery_chain.q.out +++ ql/src/test/results/clientnegative/subquery_subquery_chain.q.out @@ -1 +1 @@ -FAILED: SemanticException [Error 10249]: Line 5:14 Unsupported SubQuery Expression 'key': Only 1 SubQuery expression is supported. +FAILED: SemanticException [Error 10249]: Line 5:59 Unsupported SubQuery Expression 'key': Only 1 SubQuery expression is supported.