Author: rhbutani
Date: Fri Sep 19 22:00:22 2014
New Revision: 1626348
URL: http://svn.apache.org/r1626348
Log:
HIVE-8194 CBO: bail for having clause referring select expr aliases (Harish
Butani via Gunther Hagleitner)
Modified:
hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
Modified:
hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
URL:
http://svn.apache.org/viewvc/hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java?rev=1626348&r1=1626347&r2=1626348&view=diff
==============================================================================
---
hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
(original)
+++
hive/branches/cbo/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
Fri Sep 19 22:00:22 2014
@@ -46,6 +46,8 @@ import net.hydromatic.optiq.tools.Framew
import org.antlr.runtime.ClassicToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.Tree;
+import org.antlr.runtime.tree.TreeVisitor;
+import org.antlr.runtime.tree.TreeVisitorAction;
import org.antlr.runtime.tree.TreeWizard;
import org.antlr.runtime.tree.TreeWizard.ContextVisitor;
import org.apache.commons.lang.StringUtils;
@@ -2423,7 +2425,7 @@ public class SemanticAnalyzer extends Ba
output = putOpInsertMap(output, inputRR);
return output;
}
-
+
private Operator genPlanForSubQueryPredicate(
QB qbSQ,
ISubQueryJoinInfo subQueryPredicate) throws SemanticException {
@@ -13950,13 +13952,80 @@ public class SemanticAnalyzer extends Ba
QBParseInfo qbp = getQBParseInfo(qb);
ASTNode havingClause =
qbp.getHavingForClause(qbp.getClauseNames().iterator().next());
- if (havingClause != null)
+ if (havingClause != null) {
+ validateNoHavingReferenceToAlias(qb, (ASTNode)
havingClause.getChild(0));
gbFilter = genFilterRelNode(qb, (ASTNode) havingClause.getChild(0),
srcRel, aliasToRel,
true);
+ }
return gbFilter;
}
+ /*
+ * Bail if having clause uses Select Expression aliases for Aggregation
+ * expressions. We could do what Hive does. But this is non standard
+ * behavior. Making sure this doesn't cause issues when translating through
+ * Optiq is not worth it.
+ */
+ private void validateNoHavingReferenceToAlias(QB qb, ASTNode havingExpr)
+ throws OptiqSemanticException {
+
+ QBParseInfo qbPI = qb.getParseInfo();
+ Map<ASTNode, String> exprToAlias = qbPI.getAllExprToColumnAlias();
+ /*
+ * a mouthful, but safe:
+ * - a QB is guaranteed to have atleast 1 destination
+ * - we don't support multi insert, so picking the first dest.
+ */
+ Set<String> aggExprs = qbPI.getDestToAggregationExprs().values()
+ .iterator().next().keySet();
+
+ for (Map.Entry<ASTNode, String> selExpr : exprToAlias.entrySet()) {
+ ASTNode selAST = selExpr.getKey();
+ if (!aggExprs.contains(selAST.toStringTree().toLowerCase())) {
+ continue;
+ }
+ final String aliasToCheck = selExpr.getValue();
+ final Set<Object> aliasReferences = new HashSet<Object>();
+ TreeVisitorAction action = new TreeVisitorAction() {
+
+ @Override
+ public Object pre(Object t) {
+ if (ParseDriver.adaptor.getType(t) == HiveParser.TOK_TABLE_OR_COL)
{
+ Object c = ParseDriver.adaptor.getChild(t, 0);
+ if (c != null
+ && ParseDriver.adaptor.getType(c) == HiveParser.Identifier
+ && ParseDriver.adaptor.getText(c).equals(aliasToCheck)) {
+ aliasReferences.add(t);
+ }
+ }
+ return t;
+ }
+
+ @Override
+ public Object post(Object t) {
+ return t;
+ }
+ };
+ new TreeVisitor(ParseDriver.adaptor).visit(havingExpr, action);
+
+ if (aliasReferences.size() > 0) {
+ String havingClause = SemanticAnalyzer.this.ctx
+ .getTokenRewriteStream().toString(
+ havingExpr.getTokenStartIndex(),
+ havingExpr.getTokenStopIndex());
+ String msg = String.format(
+ "Encountered Select alias '%s' in having clause '%s'"
+ + " This non standard behavior is not supported with cbo on."
+ + " Turn off cbo for these queries.", aliasToCheck,
+ havingClause);
+ LOG.debug(msg);
+ throw new OptiqSemanticException(msg);
+ }
+ }
+
+ }
+
private ImmutableMap<String, Integer>
buildHiveToOptiqColumnMap(RowResolver rr, RelNode rNode) {
ImmutableMap.Builder<String, Integer> b = new
ImmutableMap.Builder<String, Integer>();
int i = 0;