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 58887d20be1b..d9db1d5333e5 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 @@ -8379,6 +8379,7 @@ private QBJoinTree genJoinTree(QB qb, ASTNode joinParseTree, QBJoinTree joinTree = new QBJoinTree(); JoinCond[] condn = new JoinCond[1]; + int joinType = joinParseTree.getToken().getType(); switch (joinParseTree.getToken().getType()) { case HiveParser.TOK_LEFTOUTERJOIN: joinTree.setNoOuterJoin(false); @@ -8406,10 +8407,27 @@ private QBJoinTree genJoinTree(QB qb, ASTNode joinParseTree, ASTNode left = (ASTNode) joinParseTree.getChild(0); ASTNode right = (ASTNode) joinParseTree.getChild(1); - - if ((left.getToken().getType() == HiveParser.TOK_TABREF) - || (left.getToken().getType() == HiveParser.TOK_SUBQUERY) - || (left.getToken().getType() == HiveParser.TOK_PTBLFUNCTION)) { + boolean isValidLeftToken = isValidJoinSide(left); + boolean isJoinLeftToken = !isValidLeftToken && isJoinToken(left); + boolean isValidRightToken = isValidJoinSide(right); + boolean isJoinRightToken = !isValidRightToken && isJoinToken(right); + // TODO: if we didn't care about the column order, we could switch join sides here + // for TOK_JOIN and TOK_FULLOUTERJOIN. + if (!isValidLeftToken && !isJoinLeftToken) { + throw new SemanticException("Invalid token on the left side of the join: " + + left.getToken().getText() + "; please rewrite your query"); + } else if (!isValidRightToken) { + String advice= ""; + if (isJoinRightToken && !isJoinLeftToken) { + advice = "; for example, put the nested join on the left side, or nest joins differently"; + } else if (isJoinRightToken) { + advice = "; for example, nest joins differently"; + } + throw new SemanticException("Invalid token on the right side of the join: " + + right.getToken().getText() + "; please rewrite your query" + advice); + } + + if (isValidLeftToken) { String tableName = getUnescapedUnqualifiedTableName((ASTNode) left.getChild(0)) .toLowerCase(); String alias = extractJoinAlias(left, tableName); @@ -8423,7 +8441,7 @@ private QBJoinTree genJoinTree(QB qb, ASTNode joinParseTree, joinTree.setId(qb.getId()); joinTree.getAliasToOpInfo().put( getModifiedAlias(qb, alias), aliasToOpInfo.get(alias)); - } else if (isJoinToken(left)) { + } else if (isJoinLeftToken) { QBJoinTree leftTree = genJoinTree(qb, left, aliasToOpInfo); joinTree.setJoinSrc(leftTree); String[] leftChildAliases = leftTree.getLeftAliases(); @@ -8437,9 +8455,7 @@ private QBJoinTree genJoinTree(QB qb, ASTNode joinParseTree, assert (false); } - if ((right.getToken().getType() == HiveParser.TOK_TABREF) - || (right.getToken().getType() == HiveParser.TOK_SUBQUERY) - || (right.getToken().getType() == HiveParser.TOK_PTBLFUNCTION)) { + if (isValidRightToken) { String tableName = getUnescapedUnqualifiedTableName((ASTNode) right.getChild(0)) .toLowerCase(); String alias = extractJoinAlias(right, tableName); @@ -8529,6 +8545,12 @@ private QBJoinTree genJoinTree(QB qb, ASTNode joinParseTree, return joinTree; } + private static boolean isValidJoinSide(ASTNode right) { + return (right.getToken().getType() == HiveParser.TOK_TABREF) + || (right.getToken().getType() == HiveParser.TOK_SUBQUERY) + || (right.getToken().getType() == HiveParser.TOK_PTBLFUNCTION); + } + private String extractJoinAlias(ASTNode node, String tableName) { // ptf node form is: // ^(TOK_PTBLFUNCTION $name $alias? partitionTableFunctionSource partitioningSpec? expression*) diff --git a/ql/src/test/queries/clientnegative/right_side_join.q b/ql/src/test/queries/clientnegative/right_side_join.q new file mode 100644 index 000000000000..78771c83bfca --- /dev/null +++ b/ql/src/test/queries/clientnegative/right_side_join.q @@ -0,0 +1,12 @@ +set hive.cbo.enable=false; + +explain +select * + from alltypesorc, +( + (select csmallint from alltypesorc) a + left join + (select csmallint from alltypesorc) b + on a.csmallint = b.csmallint +); + diff --git a/ql/src/test/results/clientnegative/right_side_join.q.out b/ql/src/test/results/clientnegative/right_side_join.q.out new file mode 100644 index 000000000000..ad4fb725329c --- /dev/null +++ b/ql/src/test/results/clientnegative/right_side_join.q.out @@ -0,0 +1 @@ +FAILED: SemanticException Invalid token on the right side of the join: TOK_LEFTOUTERJOIN; please rewrite your query; for example, put the nested join on the left side, or nest joins differently