This is an automated email from the ASF dual-hosted git repository.

krisztiankasa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new 38dc6b61a69 HIVE-28792: Wrong results when query has function call 
with char parameter type in case expression (Krisztian Kasa, reviewed by 
Stamatis Zampetakis)
38dc6b61a69 is described below

commit 38dc6b61a695a799c447d6f90503742dcc22e7bb
Author: Krisztian Kasa <[email protected]>
AuthorDate: Wed Mar 12 05:52:02 2025 +0100

    HIVE-28792: Wrong results when query has function call with char parameter 
type in case expression (Krisztian Kasa, reviewed by Stamatis Zampetakis)
---
 .../hadoop/hive/ql/parse/IdentifiersParser.g       |  41 ++++-
 .../apache/hadoop/hive/ql/parse/TestParseCase.java |  91 ++++++++++
 .../hive/ql/exec/ExprNodeGenericFuncEvaluator.java |   6 +-
 .../hadoop/hive/ql/exec/FunctionRegistry.java      |   1 -
 .../hive/ql/exec/vector/VectorizationContext.java  |   7 +-
 .../ql/optimizer/ConstantPropagateProcFactory.java |  73 +-------
 .../ql/optimizer/calcite/HiveRexExecutorImpl.java  |   2 +-
 .../calcite/translator/RexNodeConverter.java       |  72 +++-----
 .../hive/ql/optimizer/physical/Vectorizer.java     |   1 -
 .../hive/ql/parse/type/HiveFunctionHelper.java     |   2 +-
 .../hadoop/hive/ql/udf/generic/GenericUDFCase.java | 167 ------------------
 .../calcite/translator/TestRexNodeConverter.java   | 186 --------------------
 .../clientpositive/cbo_case_when_type_conversion.q |  40 +++++
 ql/src/test/queries/clientpositive/udf_case.q      |   3 -
 .../llap/cbo_case_when_type_conversion.q.out       | 189 +++++++++++++++++++++
 .../clientpositive/llap/order_by_expr_2.q.out      |   4 +-
 .../clientpositive/llap/show_functions.q.out       |   4 -
 .../results/clientpositive/llap/udf_case.q.out     |  24 ---
 .../clientpositive/llap/udf_case_thrift.q.out      |   2 +-
 .../perf/tpcds30tb/tez/cbo_query39.q.out           |   8 +-
 20 files changed, 387 insertions(+), 536 deletions(-)

diff --git 
a/parser/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g 
b/parser/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g
index 7dad9dcdc31..3d219dbe294 100644
--- a/parser/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g
+++ b/parser/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g
@@ -341,24 +341,47 @@ castExpression
     -> ^(TOK_FUNCTION {adaptor.create(Identifier, "cast_format")} 
NumberLiteral[Integer.toString(((CommonTree)toType.getTree()).token.getType())] 
expression StringLiteral 
NumberLiteral[((CommonTree)toType.getTree()).getChild(0).getText()])
     ;
 
-caseExpression
+whenExpression
 @init { gParent.pushMsg("case expression", state); }
 @after { gParent.popMsg(state); }
     :
-    KW_CASE expression
-    (KW_WHEN expression KW_THEN expression)+
+    KW_CASE
+     ( KW_WHEN expression KW_THEN expression)+
     (KW_ELSE expression)?
-    KW_END -> ^(TOK_FUNCTION KW_CASE expression*)
+    KW_END -> ^(TOK_FUNCTION KW_WHEN expression*)
     ;
 
-whenExpression
+// Make caseExpression to build a whenExpression tree
+// Rewrite
+// CASE a
+//   WHEN b THEN c
+//   [WHEN d THEN e]* [ELSE f]
+// END
+// to
+// CASE
+//   WHEN a=b THEN c
+//   [WHEN a=d THEN e]* [ELSE f]
+// END
+caseExpression
 @init { gParent.pushMsg("case expression", state); }
 @after { gParent.popMsg(state); }
     :
-    KW_CASE
-     ( KW_WHEN expression KW_THEN expression)+
-    (KW_ELSE expression)?
-    KW_END -> ^(TOK_FUNCTION KW_WHEN expression*)
+    KW_CASE caseOperand=expression
+    // Pass the case operand to the rule parses the when branches
+    whenBranches[$caseOperand.tree]
+    (KW_ELSE elseResult=expression)?
+    KW_END -> ^(TOK_FUNCTION Identifier["when"] whenBranches $elseResult?)
+    ;
+
+whenBranches[CommonTree caseOperand]
+    :
+    (whenExpressionBranch[caseOperand] KW_THEN! expression)+
+    ;
+
+whenExpressionBranch[CommonTree caseOperand]
+    :
+    KW_WHEN when=expression
+    -> ^(EQUAL["="] {$caseOperand} $when)
     ;
 
 floorExpression
diff --git a/parser/src/test/org/apache/hadoop/hive/ql/parse/TestParseCase.java 
b/parser/src/test/org/apache/hadoop/hive/ql/parse/TestParseCase.java
new file mode 100644
index 00000000000..0bf5c781dc0
--- /dev/null
+++ b/parser/src/test/org/apache/hadoop/hive/ql/parse/TestParseCase.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hive.ql.parse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestParseCase {
+  ParseDriver parseDriver = new ParseDriver();
+
+  @Test
+  public void testParseCaseWithOperandAndOneBranch() throws Exception {
+    ASTNode tree = parseDriver.parseSelect("select case upper(col1) when 'A' 
then 'OK' else 'N/A' end from t1", null).getTree();
+
+    String result = "\n" +
+            "TOK_SELECT\n" +
+            "   TOK_SELEXPR\n" +
+            "      TOK_FUNCTION\n" +
+            "         when\n" +
+            "         =\n" +
+            "            TOK_FUNCTION\n" +
+            "               upper\n" +
+            "               TOK_TABLE_OR_COL\n" +
+            "                  col1\n" +
+            "            'A'\n" +
+            "         'OK'\n" +
+            "         'N/A'\n";
+
+    Assert.assertEquals(result, tree.dump());
+  }
+
+  @Test
+  public void testParseCaseWithOperandAndMultipleBranches() throws Exception {
+    ASTNode tree = parseDriver.parseSelect(
+            "select case a" +
+                    "  when 'B' then 'bean'" +
+                    "  when 'A' then 'apple' else 'N/A' end from t1", 
null).getTree();
+
+    String result = "\n" +
+            "TOK_SELECT\n" +
+            "   TOK_SELEXPR\n" +
+            "      TOK_FUNCTION\n" +
+            "         when\n" +
+            "         =\n" +
+            "            TOK_TABLE_OR_COL\n" +
+            "               a\n" +
+            "            'B'\n" +
+            "         'bean'\n" +
+            "         =\n" +
+            "            TOK_TABLE_OR_COL\n" +
+            "               a\n" +
+            "            'A'\n" +
+            "         'apple'\n" +
+            "         'N/A'\n";
+
+    Assert.assertEquals(result, tree.dump());
+  }
+
+  @Test
+  public void testParseCaseWithOperandAndNoElse() throws Exception {
+    ASTNode tree = parseDriver.parseSelect("select case a when 'A' then 'OK' 
end from t1", null).getTree();
+
+    String result = "\n" +
+            "TOK_SELECT\n" +
+            "   TOK_SELEXPR\n" +
+            "      TOK_FUNCTION\n" +
+            "         when\n" +
+            "         =\n" +
+            "            TOK_TABLE_OR_COL\n" +
+            "               a\n" +
+            "            'A'\n" +
+            "         'OK'\n";
+
+    Assert.assertEquals(result, tree.dump());
+  }
+}
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/exec/ExprNodeGenericFuncEvaluator.java 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/ExprNodeGenericFuncEvaluator.java
index cdf3cf35154..41ede68c925 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/exec/ExprNodeGenericFuncEvaluator.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/ExprNodeGenericFuncEvaluator.java
@@ -18,8 +18,6 @@
 
 package org.apache.hadoop.hive.ql.exec;
 
-import com.google.common.base.Preconditions;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.hadoop.conf.Configuration;
@@ -30,7 +28,6 @@
 import org.apache.hadoop.hive.ql.session.SessionState;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBaseCompare;
-import org.apache.hadoop.hive.ql.udf.generic.GenericUDFCase;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFWhen;
 import org.apache.hadoop.hive.serde2.objectinspector.ConstantObjectInspector;
 import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
@@ -118,8 +115,7 @@ public ExprNodeGenericFuncEvaluator(ExprNodeGenericFuncDesc 
expr, Configuration
       }
     }
     genericUDF = expr.getGenericUDF();
-    if (isEager &&
-        (genericUDF instanceof GenericUDFCase || genericUDF instanceof 
GenericUDFWhen)) {
+    if (isEager && genericUDF instanceof GenericUDFWhen) {
       throw new HiveException("Stateful expressions cannot be used inside of 
CASE");
     }
   }
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
index c54a59f9516..f644bd81c9d 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
@@ -590,7 +590,6 @@ public final class FunctionRegistry {
     system.registerGenericUDF("create_union", GenericUDFUnion.class);
     system.registerGenericUDF("extract_union", GenericUDFExtractUnion.class);
 
-    system.registerGenericUDF("case", GenericUDFCase.class);
     system.registerGenericUDF("when", GenericUDFWhen.class);
     system.registerGenericUDF("nullif", GenericUDFNullif.class);
     system.registerGenericUDF("hash", GenericUDFHash.class);
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/VectorizationContext.java 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/VectorizationContext.java
index e49cd5bf3f9..a20d400894a 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/VectorizationContext.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/exec/vector/VectorizationContext.java
@@ -1474,17 +1474,16 @@ private static boolean 
isNonVectorizedPathUDF(ExprNodeGenericFuncDesc expr,
     } else if (gudf instanceof GenericUDFFromUnixTime && 
isIntFamily(arg0Type(expr))
           || (gudf instanceof GenericUDFTimestamp && 
isStringFamily(arg0Type(expr)))
 
-            /* GenericUDFCase and GenericUDFWhen are implemented with the UDF 
Adaptor because
-             * of their complexity and generality. In the future, variations 
of these
+            /* GenericUDFWhen is implemented with the UDF Adaptor because
+             * of its complexity and generality. In the future, variations of 
this
              * can be optimized to run faster for the vectorized code path. 
For example,
              * CASE col WHEN 1 then "one" WHEN 2 THEN "two" ELSE "other" END
-             * is an example of a GenericUDFCase that has all constant 
arguments
+             * is an example when all constant arguments
              * except for the first argument. This is probably a common case 
and a
              * good candidate for a fast, special-purpose VectorExpression. 
Then
              * the UDF Adaptor code path could be used as a catch-all for
              * non-optimized general cases.
              */
-            || gudf instanceof GenericUDFCase
             || gudf instanceof GenericUDFWhen) {
       return true;
     } else // between has 4 args here, but can be vectorized like this
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ConstantPropagateProcFactory.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ConstantPropagateProcFactory.java
index 01285f8f553..6f107798bae 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ConstantPropagateProcFactory.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ConstantPropagateProcFactory.java
@@ -67,7 +67,6 @@
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredJavaObject;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBaseCompare;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBridge;
-import org.apache.hadoop.hive.ql.udf.generic.GenericUDFCase;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFCoalesce;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPAnd;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqual;
@@ -564,13 +563,13 @@ private static ExprNodeDesc shortcutFunction(GenericUDF 
udf, List<ExprNodeDesc>
      ExprNodeGenericFuncDesc caseOrWhenexpr = null;
      if (newExprs.get(0) instanceof ExprNodeGenericFuncDesc) {
        caseOrWhenexpr = (ExprNodeGenericFuncDesc) newExprs.get(0);
-       if (caseOrWhenexpr.getGenericUDF() instanceof GenericUDFWhen || 
caseOrWhenexpr.getGenericUDF() instanceof GenericUDFCase) {
+       if (caseOrWhenexpr.getGenericUDF() instanceof GenericUDFWhen) {
          foundUDFInFirst = true;
        }
      }
      if (!foundUDFInFirst && newExprs.get(1) instanceof 
ExprNodeGenericFuncDesc) {
        caseOrWhenexpr = (ExprNodeGenericFuncDesc) newExprs.get(1);
-       if (!(caseOrWhenexpr.getGenericUDF() instanceof GenericUDFWhen || 
caseOrWhenexpr.getGenericUDF() instanceof GenericUDFCase)) {
+       if (!(caseOrWhenexpr.getGenericUDF() instanceof GenericUDFWhen)) {
          return null;
        }
      }
@@ -596,21 +595,6 @@ private static ExprNodeDesc shortcutFunction(GenericUDF 
udf, List<ExprNodeDesc>
        ExprNodeGenericFuncDesc newCaseOrWhenExpr = 
ExprNodeGenericFuncDesc.newInstance(childUDF,
            caseOrWhenexpr.getFuncText(), children);
        return newCaseOrWhenExpr;
-     } else if (childUDF instanceof GenericUDFCase) {
-       for (i = 2; i < children.size(); i+=2) {
-         children.set(i, ExprNodeGenericFuncDesc.newInstance(new 
GenericUDFOPEqual(),
-             Lists.newArrayList(children.get(i),newExprs.get(foundUDFInFirst ? 
1 : 0))));
-       }
-        if(children.size() % 2 == 0) {
-          i = children.size()-1;
-          children.set(i, ExprNodeGenericFuncDesc.newInstance(new 
GenericUDFOPEqual(),
-              Lists.newArrayList(children.get(i),newExprs.get(foundUDFInFirst 
? 1 : 0))));
-        }
-       // after constant folding of child expression the return type of 
UDFCase might have changed,
-       // so recreate the expression
-       ExprNodeGenericFuncDesc newCaseOrWhenExpr = 
ExprNodeGenericFuncDesc.newInstance(childUDF,
-           caseOrWhenexpr.getFuncText(), children);
-       return newCaseOrWhenExpr;
      } else {
        // cant happen
        return null;
@@ -769,59 +753,6 @@ private static ExprNodeDesc shortcutFunction(GenericUDF 
udf, List<ExprNodeDesc>
       }
     }
 
-    if (udf instanceof GenericUDFCase) {
-      // HIVE-9644 Attempt to fold expression like :
-      // where (case ss_sold_date when '1998-01-01' then 1=1 else null=1 end);
-      // where ss_sold_date= '1998-01-01' ;
-      if (!(newExprs.size() == 3 || newExprs.size() == 4)) {
-        // In general case can have unlimited # of branches,
-        // we currently only handle either 1 or 2 branch.
-        return null;
-      }
-      ExprNodeDesc thenExpr = newExprs.get(2);
-      ExprNodeDesc elseExpr = newExprs.size() == 4 ? newExprs.get(3) :
-        new ExprNodeConstantDesc(newExprs.get(2).getTypeInfo(),null);
-
-      if (thenExpr instanceof ExprNodeConstantDesc && elseExpr instanceof 
ExprNodeConstantDesc) {
-        ExprNodeConstantDesc constThen = (ExprNodeConstantDesc) thenExpr;
-        ExprNodeConstantDesc constElse = (ExprNodeConstantDesc) elseExpr;
-        Object thenVal = constThen.getValue();
-        Object elseVal = constElse.getValue();
-        if (thenVal == null) {
-          if (null == elseVal) {
-            return thenExpr;
-          } else if (op instanceof FilterOperator) {
-            return Boolean.TRUE.equals(elseVal) ? 
ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPNotEqual(), 
newExprs.subList(0, 2)) :
-              Boolean.FALSE.equals(elseVal) ? elseExpr : null;
-          } else {
-            return null;
-          }
-        } else if (null == elseVal && op instanceof FilterOperator) {
-            return Boolean.TRUE.equals(thenVal) ? 
ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPEqual(), 
newExprs.subList(0, 2)) :
-              Boolean.FALSE.equals(thenVal) ? thenExpr : null;
-        } else if(thenVal.equals(elseVal)){
-          return thenExpr;
-        } else if (thenVal instanceof Boolean && elseVal instanceof Boolean) {
-          ExprNodeGenericFuncDesc equal = ExprNodeGenericFuncDesc.newInstance(
-              new GenericUDFOPEqual(), newExprs.subList(0, 2));
-          List<ExprNodeDesc> children = new ArrayList<>();
-          children.add(equal);
-          children.add(new ExprNodeConstantDesc(false));
-          ExprNodeGenericFuncDesc func = 
ExprNodeGenericFuncDesc.newInstance(new GenericUDFCoalesce(),
-              children);
-          if (Boolean.TRUE.equals(thenVal)) {
-            return func;
-          } else {
-            List<ExprNodeDesc> exprs = new ArrayList<>();
-            exprs.add(func);
-            return ExprNodeGenericFuncDesc.newInstance(new GenericUDFOPNot(), 
exprs);
-          }
-        } else {
-          return null;
-        }
-      }
-    }
-
     if (udf instanceof GenericUDFUnixTimeStamp) {
       if (newExprs.size() >= 1) {
         // unix_timestamp(args) -> to_unix_timestamp(args)
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexExecutorImpl.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexExecutorImpl.java
index 47ee70f8ad6..66984a3ebde 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexExecutorImpl.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/HiveRexExecutorImpl.java
@@ -47,7 +47,7 @@ public HiveRexExecutorImpl() {
 
   @Override
   public void reduce(RexBuilder rexBuilder, List<RexNode> constExps, 
List<RexNode> reducedValues) {
-    RexNodeConverter rexNodeConverter = new RexNodeConverter(rexBuilder, 
rexBuilder.getTypeFactory());
+    RexNodeConverter rexNodeConverter = new RexNodeConverter(rexBuilder);
     for (RexNode rexNode : constExps) {
       // initialize the converter
       ExprNodeConverter converter = new ExprNodeConverter("", null, null, null,
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/RexNodeConverter.java
 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/RexNodeConverter.java
index 31e0d4dee57..cddc7cb9ca2 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/RexNodeConverter.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/RexNodeConverter.java
@@ -39,7 +39,6 @@
 import org.apache.calcite.sql.fun.SqlCastFunction;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParserPos;
-import org.apache.calcite.sql.type.ArraySqlType;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.util.ConversionUtil;
@@ -75,7 +74,6 @@
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBaseCompare;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBetween;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFBridge;
-import org.apache.hadoop.hive.ql.udf.generic.GenericUDFCase;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFIn;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFTimestamp;
 import org.apache.hadoop.hive.ql.udf.generic.GenericUDFToArray;
@@ -121,9 +119,9 @@ public class RexNodeConverter {
   /**
    * Constructor used by HiveRexExecutorImpl.
    */
-  public RexNodeConverter(RexBuilder rexBuilder, RelDataTypeFactory 
typeFactory) {
+  public RexNodeConverter(RexBuilder rexBuilder) {
     this.rexBuilder = rexBuilder;
-    this.typeFactory = typeFactory;
+    this.typeFactory = rexBuilder.getTypeFactory();
   }
 
   public RexNode convert(ExprNodeDesc expr) throws SemanticException {
@@ -168,7 +166,7 @@ private RexNode convert(ExprNodeGenericFuncDesc func) 
throws SemanticException {
         && (PrimitiveGrouping.NUMERIC_GROUP == 
PrimitiveObjectInspectorUtils.getPrimitiveGrouping(
         ((PrimitiveTypeInfo) func.getTypeInfo()).getPrimitiveCategory())));
     boolean isCompare = !isNumeric && tgtUdf instanceof GenericUDFBaseCompare;
-    boolean isWhenCase = tgtUdf instanceof GenericUDFWhen || tgtUdf instanceof 
GenericUDFCase;
+    boolean isWhenCase = tgtUdf instanceof GenericUDFWhen;
     boolean isTransformableTimeStamp = func.getGenericUDF() instanceof 
GenericUDFUnixTimeStamp &&
         !func.getChildren().isEmpty();
     boolean isBetween = !isNumeric && tgtUdf instanceof GenericUDFBetween;
@@ -249,7 +247,7 @@ private RexNode convert(ExprNodeGenericFuncDesc func) 
throws SemanticException {
           func.getGenericUDF(), argTypeBldr.build(), retType);
       if (calciteOp.getKind() == SqlKind.CASE) {
         // If it is a case operator, we need to rewrite it
-        childRexNodeLst = rewriteCaseChildren(func.getFuncText(), 
childRexNodeLst, rexBuilder);
+        childRexNodeLst = rewriteCaseChildren(childRexNodeLst, rexBuilder);
         // Adjust branch types by inserting explicit casts if the actual is 
ambiguous
         childRexNodeLst = adjustCaseBranchTypes(childRexNodeLst, retType, 
rexBuilder);
       } else if (HiveExtractDate.ALL_FUNCTIONS.contains(calciteOp)) {
@@ -357,60 +355,30 @@ public static RexNode handleExplicitCast(GenericUDF udf, 
RelDataType returnType,
    *   "case" function, ELSE clause is optional)
    * - CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END (translated into the
    *   "when" function, ELSE clause is optional)
-   * However, Calcite only has the equivalent to the "when" Hive function. 
Thus,
-   * we need to transform the "case" function into "when". Further, ELSE 
clause is
-   * not optional in Calcite.
+   * The first type is transformed to the second one at parsing time.
+   * Calcite only has the equivalent to the "when" Hive function and ELSE 
clause is
+   * not optional.
    *
-   * Example. Consider the following statement:
-   * CASE x + y WHEN 1 THEN 'fee' WHEN 2 THEN 'fie' END
-   * It will be transformed into:
-   * CASE WHEN =(x + y, 1) THEN 'fee' WHEN =(x + y, 2) THEN 'fie' ELSE null END
+   * See parser rule caseExpression in IdentifiersParser.g
    */
-  public static List<RexNode> rewriteCaseChildren(String funcText, 
List<RexNode> childRexNodeLst,
-      RexBuilder rexBuilder) throws SemanticException {
+  public static List<RexNode> rewriteCaseChildren(List<RexNode> 
childRexNodeLst, RexBuilder rexBuilder) {
     List<RexNode> newChildRexNodeLst = new ArrayList<>();
-    if (FunctionRegistry.getNormalizedFunctionName(funcText).equals("case")) {
-      RexNode firstPred = childRexNodeLst.get(0);
-      int length = childRexNodeLst.size() % 2 == 1 ?
-          childRexNodeLst.size() : childRexNodeLst.size() - 1;
-      for (int i = 1; i < length; i++) {
-        if (i % 2 == 1) {
-          // We rewrite it
-          RexNode node = childRexNodeLst.get(i);
-          if (node.isA(SqlKind.LITERAL) && 
!node.getType().equals(firstPred.getType())) {
-            // this effectively changes the type of the literal to that of the 
predicate
-            // to which it is anyway going to be compared with
-            // ex: CASE WHEN =($0:SMALLINT, 1:INTEGER) ... => CASE WHEN 
=($0:SMALLINT, 1:SMALLINT)
-            node = rexBuilder.makeCast(firstPred.getType(), node);
+    for (int i = 0; i < childRexNodeLst.size(); i++) {
+      RexNode child = childRexNodeLst.get(i);
+      if (RexUtil.isNull(child)) {
+        if (i % 2 == 0 && i != childRexNodeLst.size() - 1) {
+          if (SqlTypeName.NULL.equals(child.getType().getSqlTypeName())) {
+            child = 
rexBuilder.makeNullLiteral(rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN));
           }
-          newChildRexNodeLst.add(
-              rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, firstPred, 
node));
         } else {
-          newChildRexNodeLst.add(childRexNodeLst.get(i));
-        }
-      }
-      // The else clause
-      if (length != childRexNodeLst.size()) {
-        newChildRexNodeLst.add(childRexNodeLst.get(childRexNodeLst.size()-1));
-      }
-    } else {
-      for (int i = 0; i < childRexNodeLst.size(); i++) {
-        RexNode child = childRexNodeLst.get(i);
-        if (RexUtil.isNull(child)) {
-          if (i % 2 == 0 && i != childRexNodeLst.size() - 1) {
-            if (SqlTypeName.NULL.equals(child.getType().getSqlTypeName())) {
-              child = 
rexBuilder.makeNullLiteral(rexBuilder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN));
-            }
-          } else {
-            // this is needed to provide typed NULLs which were working before
-            // example: IF(false, array(1,2,3), NULL)
-            if (!RexUtil.isNull(childRexNodeLst.get(1))) {
-              child = rexBuilder.makeCast(childRexNodeLst.get(1).getType(), 
child);
-            }
+          // this is needed to provide typed NULLs which were working before
+          // example: IF(false, array(1,2,3), NULL)
+          if (!RexUtil.isNull(childRexNodeLst.get(1))) {
+            child = rexBuilder.makeCast(childRexNodeLst.get(1).getType(), 
child);
           }
         }
-        newChildRexNodeLst.add(child);
       }
+      newChildRexNodeLst.add(child);
     }
     // Calcite always needs the else clause to be defined explicitly
     if (newChildRexNodeLst.size() % 2 == 0) {
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java
index f3dadc46011..4eeb19dfe7b 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/physical/Vectorizer.java
@@ -525,7 +525,6 @@ public Vectorizer() {
     supportedGenericUDFs.add(GenericUDFAbs.class);
     supportedGenericUDFs.add(GenericUDFBetween.class);
     supportedGenericUDFs.add(GenericUDFIn.class);
-    supportedGenericUDFs.add(GenericUDFCase.class);
     supportedGenericUDFs.add(GenericUDFWhen.class);
     supportedGenericUDFs.add(GenericUDFCoalesce.class);
     supportedGenericUDFs.add(GenericUDFElt.class);
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/parse/type/HiveFunctionHelper.java 
b/ql/src/java/org/apache/hadoop/hive/ql/parse/type/HiveFunctionHelper.java
index 7ebbb95efb9..32c1f0d8c46 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/parse/type/HiveFunctionHelper.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/type/HiveFunctionHelper.java
@@ -255,7 +255,7 @@ public RexNode getExpression(String functionText, 
FunctionInfo fi,
           fi.getGenericUDF(), argsTypes.build(), returnType);
       if (calciteOp.getKind() == SqlKind.CASE) {
         // If it is a case operator, we need to rewrite it
-        inputs = RexNodeConverter.rewriteCaseChildren(functionText, inputs, 
rexBuilder);
+        inputs = RexNodeConverter.rewriteCaseChildren(inputs, rexBuilder);
         // Adjust branch types by inserting explicit casts if the actual is 
ambiguous
         inputs = RexNodeConverter.adjustCaseBranchTypes(inputs, returnType, 
rexBuilder);
         checkForStatefulFunctions(inputs);
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java 
b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java
deleted file mode 100644
index 641188434af..00000000000
--- a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFCase.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.hive.ql.udf.generic;
-
-import java.util.List;
-import java.util.Optional;
-
-import org.apache.hadoop.hive.ql.exec.Description;
-import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
-import org.apache.hadoop.hive.ql.metadata.HiveException;
-import org.apache.hadoop.hive.ql.plan.ColStatistics;
-import org.apache.hadoop.hive.ql.stats.estimator.StatEstimator;
-import org.apache.hadoop.hive.ql.stats.estimator.StatEstimatorProvider;
-import org.apache.hadoop.hive.ql.stats.estimator.PessimisticStatCombiner;
-import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
-import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
-import 
org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils;
-
-/**
- * GenericUDF Class for SQL construct "CASE a WHEN b THEN c [ELSE f] END".
- *
- * NOTES: 1. a and b should be compatible, or an exception will be
- * thrown. 2. c and f should be compatible types, or an exception will be
- * thrown.
- */
-@Description(
-    name = "case",
-    value = "CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END - "
-        + "When a = b, returns c; when a = d, return e; else return f",
-    extended = "Example:\n "
-    + "SELECT\n"
-    + " CASE deptno\n"
-    + "   WHEN 1 THEN Engineering\n"
-    + "   WHEN 2 THEN Finance\n"
-    + "   ELSE admin\n"
-    + " END,\n"
-    + " CASE zone\n"
-    + "   WHEN 7 THEN Americas\n"
-    + "   ELSE Asia-Pac\n"
-    + " END\n"
-    + " FROM emp_details")
-
-public class GenericUDFCase extends GenericUDF implements 
StatEstimatorProvider {
-  private transient ObjectInspector[] argumentOIs;
-  private transient GenericUDFUtils.ReturnObjectInspectorResolver 
returnOIResolver;
-  private transient GenericUDFUtils.ReturnObjectInspectorResolver 
caseOIResolver;
-
-  @Override
-  public ObjectInspector initialize(ObjectInspector[] arguments) throws 
UDFArgumentTypeException {
-
-    argumentOIs = arguments;
-    caseOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true);
-    returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true);
-
-    boolean r = caseOIResolver.update(arguments[0]);
-    assert (r);
-    for (int i = 1; i + 1 < arguments.length; i += 2) {
-      if (!caseOIResolver.update(arguments[i])) {
-        throw new UDFArgumentTypeException(i,
-            "The expressions after WHEN should have the same type with that 
after CASE: \""
-            + caseOIResolver.get().getTypeName() + "\" is expected but \""
-            + arguments[i].getTypeName() + "\" is found");
-      }
-      if (!returnOIResolver.update(arguments[i + 1])) {
-        throw new UDFArgumentTypeException(i + 1,
-            "The expressions after THEN should have the same type: \""
-            + returnOIResolver.get().getTypeName()
-            + "\" is expected but \"" + arguments[i + 1].getTypeName()
-            + "\" is found");
-      }
-    }
-    if (arguments.length % 2 == 0) {
-      int i = arguments.length - 2;
-      if (!returnOIResolver.update(arguments[i + 1])) {
-        throw new UDFArgumentTypeException(i + 1,
-            "The expression after ELSE should have the same type as those 
after THEN: \""
-            + returnOIResolver.get().getTypeName()
-            + "\" is expected but \"" + arguments[i + 1].getTypeName()
-            + "\" is found");
-      }
-    }
-
-    return returnOIResolver.get();
-  }
-
-  @Override
-  public Object evaluate(DeferredObject[] arguments) throws HiveException {
-    Object exprValue = arguments[0].get();
-    for (int i = 1; i + 1 < arguments.length; i += 2) {
-      Object caseKey = arguments[i].get();
-      // May need to convert to common type to compare
-      PrimitiveObjectInspector caseOI = (PrimitiveObjectInspector) 
caseOIResolver.get();
-      if (PrimitiveObjectInspectorUtils.comparePrimitiveObjects(
-            caseOIResolver.convertIfNecessary(exprValue, argumentOIs[0]), 
caseOI,
-            caseOIResolver.convertIfNecessary(caseKey, argumentOIs[i], false), 
caseOI)) {
-        Object caseValue = arguments[i + 1].get();
-        return returnOIResolver.convertIfNecessary(caseValue, argumentOIs[i + 
1]);
-      }
-    }
-    // Process else statement
-    if (arguments.length % 2 == 0) {
-      int i = arguments.length - 2;
-      Object elseValue = arguments[i + 1].get();
-      return returnOIResolver.convertIfNecessary(elseValue, argumentOIs[i + 
1]);
-    }
-    return null;
-  }
-
-  @Override
-  public String getDisplayString(String[] children) {
-    assert (children.length >= 3);
-    StringBuilder sb = new StringBuilder();
-    sb.append("CASE (");
-    sb.append(children[0]);
-    sb.append(")");
-    for (int i = 1; i + 1 < children.length; i += 2) {
-      sb.append(" WHEN (");
-      sb.append(children[i]);
-      sb.append(") THEN (");
-      sb.append(children[i + 1]);
-      sb.append(")");
-    }
-    if (children.length % 2 == 0) {
-      sb.append(" ELSE (");
-      sb.append(children[children.length - 1]);
-      sb.append(")");
-    }
-    sb.append(" END");
-    return sb.toString();
-  }
-
-  @Override
-  public StatEstimator getStatEstimator() {
-    return new CaseStatEstimator();
-  }
-
-  static class CaseStatEstimator implements StatEstimator {
-
-    @Override
-    public Optional<ColStatistics> estimate(List<ColStatistics> argStats) {
-      PessimisticStatCombiner combiner = new PessimisticStatCombiner();
-      for (int i = 2; i < argStats.size(); i += 2) {
-        combiner.add(argStats.get(i));
-      }
-      if (argStats.size() % 2 == 0) {
-        combiner.add(argStats.get(argStats.size() - 1));
-      }
-      return combiner.getResult();
-    }
-  }
-}
diff --git 
a/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/translator/TestRexNodeConverter.java
 
b/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/translator/TestRexNodeConverter.java
deleted file mode 100644
index 341097b8dd7..00000000000
--- 
a/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/translator/TestRexNodeConverter.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.hadoop.hive.ql.optimizer.calcite.translator;
-
-import com.google.common.collect.ImmutableList;
-import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
-import org.apache.calcite.plan.RelOptCluster;
-import org.apache.calcite.plan.RelOptPlanner;
-import org.apache.calcite.plan.RelOptSchema;
-import org.apache.calcite.rel.RelNode;
-import org.apache.calcite.rel.logical.LogicalTableScan;
-import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
-import org.apache.calcite.rex.RexBuilder;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.type.SqlTypeName;
-import org.apache.calcite.tools.RelBuilder;
-import org.apache.hadoop.hive.conf.HiveConf;
-import org.apache.hadoop.hive.ql.optimizer.calcite.HiveRelFactories;
-import org.apache.hadoop.hive.ql.optimizer.calcite.HiveTypeSystemImpl;
-import org.apache.hadoop.hive.ql.optimizer.calcite.RelOptHiveTable;
-import org.apache.hadoop.hive.ql.parse.CalcitePlanner;
-import org.apache.hadoop.hive.ql.parse.SemanticException;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import java.util.Collections;
-import java.util.List;
-
-import static org.mockito.Mockito.doReturn;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TestRexNodeConverter {
-
-  private static final String CASE_FUNC_TEST = "case";
-  private static final RexBuilder REX_BUILDER = new RexBuilder(
-      new JavaTypeFactoryImpl(new HiveTypeSystemImpl()));
-  private static final RelDataTypeFactory TYPE_FACTORY = 
REX_BUILDER.getTypeFactory();
-
-  private static RelDataType smallIntegerType;
-  private static RelDataType integerType;
-  @SuppressWarnings("FieldCanBeLocal")
-  private static RelDataType nullableSmallIntegerType;
-
-  private static RexNode varChar34;
-  private static RexNode varChar35;
-  private static RexNode varCharNull;
-
-  private static RelOptCluster relOptCluster;
-  private static RelBuilder relBuilder;
-  private static RelDataType tableType;
-
-  @Mock
-  private RelOptSchema schemaMock;
-  @Mock
-  private RelOptHiveTable tableMock;
-
-  private LogicalTableScan tableScan;
-
-  @BeforeClass
-  public static void beforeClass() {
-    smallIntegerType = TYPE_FACTORY.createSqlType(SqlTypeName.SMALLINT);
-    integerType = TYPE_FACTORY.createSqlType(SqlTypeName.INTEGER);
-    nullableSmallIntegerType = 
TYPE_FACTORY.createTypeWithNullability(smallIntegerType, true);
-
-    RelDataType varcharType = TYPE_FACTORY.createSqlType(SqlTypeName.VARCHAR, 
20);
-    varChar34 = REX_BUILDER.makeLiteral("34", varcharType, true);
-    varChar35 = REX_BUILDER.makeLiteral("35", varcharType, true);
-    varCharNull = REX_BUILDER.makeLiteral(null, varcharType, true);
-
-    tableType = TYPE_FACTORY.createStructType(
-        ImmutableList.of(smallIntegerType, nullableSmallIntegerType),
-        ImmutableList.of("f1", "f2")
-    );
-
-    RelOptPlanner planner = CalcitePlanner.createPlanner(new HiveConf());
-    relOptCluster = RelOptCluster.create(planner, REX_BUILDER);
-  }
-
-  @Before
-  public void before() {
-    doReturn(tableType).when(tableMock).getRowType();
-    tableScan = LogicalTableScan.create(relOptCluster, tableMock, 
Collections.emptyList());
-    relBuilder = HiveRelFactories.HIVE_BUILDER.create(relOptCluster, 
schemaMock);
-  }
-
-  @Test public void testRewriteCaseChildren() throws SemanticException {
-    RelNode scan = relBuilder.push(tableScan).build();
-    RexNode inputRef = REX_BUILDER.makeInputRef(scan, 0);
-
-    List<RexNode> childrenNodeList = ImmutableList.of(
-        inputRef,
-        REX_BUILDER.makeLiteral(1, integerType, true),
-        varChar34,
-        REX_BUILDER.makeLiteral(6, integerType, true),
-        varChar35);
-
-    List<RexNode> expected = ImmutableList.of(
-        REX_BUILDER.makeCall(SqlStdOperatorTable.EQUALS,
-            inputRef, REX_BUILDER.makeLiteral(1, smallIntegerType, true)),
-        varChar34,
-        REX_BUILDER.makeCall(SqlStdOperatorTable.EQUALS,
-            inputRef, REX_BUILDER.makeLiteral(6, smallIntegerType, true)),
-        varChar35,
-        varCharNull);
-
-    List<RexNode> computed = RexNodeConverter.rewriteCaseChildren(
-        CASE_FUNC_TEST, childrenNodeList, REX_BUILDER);
-
-    Assert.assertEquals(expected, computed);
-  }
-
-  @Test public void testRewriteCaseChildrenNullChild() throws 
SemanticException {
-    RelNode scan = relBuilder.push(tableScan).build();
-    RexNode inputRef = REX_BUILDER.makeInputRef(scan, 0);
-
-    List<RexNode> childrenNodeList = ImmutableList.of(
-        inputRef,
-        REX_BUILDER.makeLiteral(1, integerType, true),
-        varChar34,
-        REX_BUILDER.makeLiteral(null, integerType, true),
-        varChar35);
-
-    List<RexNode> expected = ImmutableList.of(
-        REX_BUILDER.makeCall(SqlStdOperatorTable.EQUALS,
-            inputRef, REX_BUILDER.makeLiteral(1, smallIntegerType, true)),
-        varChar34,
-        REX_BUILDER.makeCall(SqlStdOperatorTable.EQUALS,
-            inputRef, REX_BUILDER.makeLiteral(null, smallIntegerType, true)),
-        varChar35,
-        varCharNull);
-
-    List<RexNode> computed = RexNodeConverter.rewriteCaseChildren(
-        CASE_FUNC_TEST, childrenNodeList, REX_BUILDER);
-
-    Assert.assertEquals(expected, computed);
-  }
-
-  @Test public void testRewriteCaseChildrenNullChildAndNullableType() throws 
SemanticException {
-    RelNode scan = relBuilder.push(tableScan).build();
-    RexNode inputRef = REX_BUILDER.makeInputRef(scan, 1);
-
-    List<RexNode> childrenNodeList = ImmutableList.of(
-        inputRef,
-        REX_BUILDER.makeLiteral(1, integerType, true),
-        varChar34,
-        REX_BUILDER.makeLiteral(null, integerType, true),
-        varChar35);
-
-    List<RexNode> expected = ImmutableList.of(
-        REX_BUILDER.makeCall(SqlStdOperatorTable.EQUALS,
-            inputRef, REX_BUILDER.makeLiteral(1, smallIntegerType, true)),
-        varChar34,
-        REX_BUILDER.makeCall(SqlStdOperatorTable.EQUALS,
-            inputRef, REX_BUILDER.makeLiteral(null, smallIntegerType, true)),
-        varChar35,
-        varCharNull);
-
-    List<RexNode> computed = RexNodeConverter.rewriteCaseChildren(
-        CASE_FUNC_TEST, childrenNodeList, REX_BUILDER);
-
-    Assert.assertEquals(expected, computed);
-  }
-}
diff --git a/ql/src/test/queries/clientpositive/cbo_case_when_type_conversion.q 
b/ql/src/test/queries/clientpositive/cbo_case_when_type_conversion.q
new file mode 100644
index 00000000000..fe2439e18f5
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/cbo_case_when_type_conversion.q
@@ -0,0 +1,40 @@
+CREATE TABLE t1 (col1 char(3));
+
+INSERT INTO t1 VALUES ('A'),('b'),('c'),(null);
+
+explain cbo
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from 
t1;
+explain
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from 
t1;
+
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from 
t1;
+
+explain cbo
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from 
t1;
+explain
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from 
t1;
+
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from 
t1;
+
+explain cbo
+select col1,
+  case lower(col1)
+    when 'a' then 'OK a'
+    when 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1;
+
+explain cbo
+select col1,
+  case
+    when lower(col1) = 'a' then 'OK a'
+    when lower(col1) = 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1;
+
+select col1,
+  case lower(col1)
+    when 'a' then 'OK a'
+    when 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1;
diff --git a/ql/src/test/queries/clientpositive/udf_case.q 
b/ql/src/test/queries/clientpositive/udf_case.q
index 28d87a85451..f3810e71c6b 100644
--- a/ql/src/test/queries/clientpositive/udf_case.q
+++ b/ql/src/test/queries/clientpositive/udf_case.q
@@ -1,9 +1,6 @@
 --! qt:dataset:src
 set hive.fetch.task.conversion=more;
 
-DESCRIBE FUNCTION case;
-DESCRIBE FUNCTION EXTENDED case;
-
 EXPLAIN
 SELECT CASE 1
         WHEN 1 THEN 2
diff --git 
a/ql/src/test/results/clientpositive/llap/cbo_case_when_type_conversion.q.out 
b/ql/src/test/results/clientpositive/llap/cbo_case_when_type_conversion.q.out
new file mode 100644
index 00000000000..5f22106d856
--- /dev/null
+++ 
b/ql/src/test/results/clientpositive/llap/cbo_case_when_type_conversion.q.out
@@ -0,0 +1,189 @@
+PREHOOK: query: CREATE TABLE t1 (col1 char(3))
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@t1
+POSTHOOK: query: CREATE TABLE t1 (col1 char(3))
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@t1
+PREHOOK: query: INSERT INTO t1 VALUES ('A'),('b'),('c'),(null)
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@t1
+POSTHOOK: query: INSERT INTO t1 VALUES ('A'),('b'),('c'),(null)
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@t1
+POSTHOOK: Lineage: t1.col1 SCRIPT []
+PREHOOK: query: explain cbo
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[CASE(=(CAST(UPPER($0)):VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", _UTF-16LE'A'), _UTF-16LE'OK':VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", _UTF-16LE'N/A':VARCHAR(2147483647) CHARACTER SET 
"UTF-16LE")])
+  HiveTableScan(table=[[default, t1]], table:alias=[t1])
+
+PREHOOK: query: explain
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: explain
+select col1, case upper(col1) when 'A' then 'OK' else 'N/A' end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+STAGE DEPENDENCIES:
+  Stage-0 is a root stage
+
+STAGE PLANS:
+  Stage: Stage-0
+    Fetch Operator
+      limit: -1
+      Processor Tree:
+        TableScan
+          alias: t1
+          Select Operator
+            expressions: col1 (type: char(3)), if((CAST( upper(col1) AS 
STRING) = 'A'), 'OK', 'N/A') (type: string)
+            outputColumnNames: _col0, _col1
+            ListSink
+
+PREHOOK: query: select col1, case upper(col1) when 'A' then 'OK' else 'N/A' 
end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: select col1, case upper(col1) when 'A' then 'OK' else 'N/A' 
end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+A      OK
+b      N/A
+c      N/A
+NULL   N/A
+PREHOOK: query: explain cbo
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[CASE(=(CAST(UPPER($0)):VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", _UTF-16LE'A'), _UTF-16LE'OK':VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", _UTF-16LE'N/A':VARCHAR(2147483647) CHARACTER SET 
"UTF-16LE")])
+  HiveTableScan(table=[[default, t1]], table:alias=[t1])
+
+PREHOOK: query: explain
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: explain
+select col1, case when upper(col1)='A' then 'OK' else 'N/A' end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+STAGE DEPENDENCIES:
+  Stage-0 is a root stage
+
+STAGE PLANS:
+  Stage: Stage-0
+    Fetch Operator
+      limit: -1
+      Processor Tree:
+        TableScan
+          alias: t1
+          Select Operator
+            expressions: col1 (type: char(3)), if((CAST( upper(col1) AS 
STRING) = 'A'), 'OK', 'N/A') (type: string)
+            outputColumnNames: _col0, _col1
+            ListSink
+
+PREHOOK: query: select col1, case when upper(col1)='A' then 'OK' else 'N/A' 
end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: select col1, case when upper(col1)='A' then 'OK' else 'N/A' 
end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+A      OK
+b      N/A
+c      N/A
+NULL   N/A
+PREHOOK: query: explain cbo
+select col1,
+  case lower(col1)
+    when 'a' then 'OK a'
+    when 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+select col1,
+  case lower(col1)
+    when 'a' then 'OK a'
+    when 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[CASE(=(CAST(LOWER($0)):VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", _UTF-16LE'a'), _UTF-16LE'OK a':VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", =(CAST(LOWER($0)):VARCHAR(2147483647) CHARACTER SET 
"UTF-16LE", _UTF-16LE'b'), _UTF-16LE'OK b':VARCHAR(2147483647) CHARACTER SET 
"UTF-16LE", _UTF-16LE'N/A':VARCHAR(2147483647) CHARACTER SET "UTF-16LE")])
+  HiveTableScan(table=[[default, t1]], table:alias=[t1])
+
+PREHOOK: query: explain cbo
+select col1,
+  case
+    when lower(col1) = 'a' then 'OK a'
+    when lower(col1) = 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+select col1,
+  case
+    when lower(col1) = 'a' then 'OK a'
+    when lower(col1) = 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(col1=[$0], col2=[CASE(=(CAST(LOWER($0)):VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", _UTF-16LE'a'), _UTF-16LE'OK a':VARCHAR(2147483647) 
CHARACTER SET "UTF-16LE", =(CAST(LOWER($0)):VARCHAR(2147483647) CHARACTER SET 
"UTF-16LE", _UTF-16LE'b'), _UTF-16LE'OK b':VARCHAR(2147483647) CHARACTER SET 
"UTF-16LE", _UTF-16LE'N/A':VARCHAR(2147483647) CHARACTER SET "UTF-16LE")])
+  HiveTableScan(table=[[default, t1]], table:alias=[t1])
+
+PREHOOK: query: select col1,
+  case lower(col1)
+    when 'a' then 'OK a'
+    when 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@t1
+#### A masked pattern was here ####
+POSTHOOK: query: select col1,
+  case lower(col1)
+    when 'a' then 'OK a'
+    when 'b' then 'OK b'
+    else 'N/A'
+    end as col2 from t1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@t1
+#### A masked pattern was here ####
+A      OK a
+b      OK b
+c      N/A
+NULL   N/A
diff --git a/ql/src/test/results/clientpositive/llap/order_by_expr_2.q.out 
b/ql/src/test/results/clientpositive/llap/order_by_expr_2.q.out
index 78bd0459bc3..04bc76156a3 100644
--- a/ql/src/test/results/clientpositive/llap/order_by_expr_2.q.out
+++ b/ql/src/test/results/clientpositive/llap/order_by_expr_2.q.out
@@ -139,7 +139,7 @@ POSTHOOK: Input: default@store
 CBO PLAN:
 HiveProject(c0=[$0], c1=[$1], c2=[$2])
   HiveSortLimit(sort0=[$3], dir0=[ASC])
-    HiveProject(c0=[$0], c1=[$1], c2=[$2], (tok_function case 
(tok_table_or_col store_name) 'HQ' tok_null (tok_table_or_col store_name))=[$1])
+    HiveProject(c0=[$0], c1=[$1], c2=[$2], (tok_function when (= 
(tok_table_or_col store_name) 'HQ') tok_null (tok_table_or_col 
store_name))=[$1])
       HiveAggregate(group=[{0, 1, 2}])
         HiveProject($f0=[$0], $f1=[CASE(=($0, _UTF-16LE'HQ'), 
null:VARCHAR(2147483647) CHARACTER SET "UTF-16LE", $0)], $f2=[$1])
           HiveTableScan(table=[[default, store]], table:alias=[store])
@@ -183,7 +183,7 @@ POSTHOOK: Input: default@store
 CBO PLAN:
 HiveProject(c0=[$0], c1=[$1], c2=[$2])
   HiveSortLimit(sort0=[$3], dir0=[ASC])
-    HiveProject(c0=[$0], c1=[$1], c2=[$2], (tok_function case 
(tok_table_or_col store_name) 'hq' tok_null (tok_table_or_col 
store_name))0=[CASE(=($0, _UTF-16LE'hq'), null:VARCHAR(2147483647) CHARACTER 
SET "UTF-16LE", $0)])
+    HiveProject(c0=[$0], c1=[$1], c2=[$2], (tok_function when (= 
(tok_table_or_col store_name) 'hq') tok_null (tok_table_or_col 
store_name))0=[CASE(=($0, _UTF-16LE'hq'), null:VARCHAR(2147483647) CHARACTER 
SET "UTF-16LE", $0)])
       HiveAggregate(group=[{0, 1, 2}])
         HiveProject($f0=[$0], $f1=[CASE(=($0, _UTF-16LE'HQ'), 
null:VARCHAR(2147483647) CHARACTER SET "UTF-16LE", $0)], $f2=[$1])
           HiveTableScan(table=[[default, store]], table:alias=[store])
diff --git a/ql/src/test/results/clientpositive/llap/show_functions.q.out 
b/ql/src/test/results/clientpositive/llap/show_functions.q.out
index 1de66c3def6..9150f13015b 100644
--- a/ql/src/test/results/clientpositive/llap/show_functions.q.out
+++ b/ql/src/test/results/clientpositive/llap/show_functions.q.out
@@ -73,7 +73,6 @@ bround
 bucket_number
 buildversion
 cardinality_violation
-case
 cast_format
 cbrt
 ceil
@@ -528,7 +527,6 @@ PREHOOK: type: SHOWFUNCTIONS
 POSTHOOK: query: SHOW FUNCTIONS LIKE 'c%'
 POSTHOOK: type: SHOWFUNCTIONS
 cardinality_violation
-case
 cast_format
 cbrt
 ceil
@@ -569,7 +567,6 @@ POSTHOOK: type: SHOWFUNCTIONS
 array_remove
 array_slice
 assert_true
-case
 coalesce
 current_database
 current_date
@@ -711,7 +708,6 @@ bround
 bucket_number
 buildversion
 cardinality_violation
-case
 cast_format
 cbrt
 ceil
diff --git a/ql/src/test/results/clientpositive/llap/udf_case.q.out 
b/ql/src/test/results/clientpositive/llap/udf_case.q.out
index 80c0ec52e09..bfc8880f00e 100644
--- a/ql/src/test/results/clientpositive/llap/udf_case.q.out
+++ b/ql/src/test/results/clientpositive/llap/udf_case.q.out
@@ -1,27 +1,3 @@
-PREHOOK: query: DESCRIBE FUNCTION case
-PREHOOK: type: DESCFUNCTION
-POSTHOOK: query: DESCRIBE FUNCTION case
-POSTHOOK: type: DESCFUNCTION
-CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END - When a = b, returns c; 
when a = d, return e; else return f
-PREHOOK: query: DESCRIBE FUNCTION EXTENDED case
-PREHOOK: type: DESCFUNCTION
-POSTHOOK: query: DESCRIBE FUNCTION EXTENDED case
-POSTHOOK: type: DESCFUNCTION
-CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END - When a = b, returns c; 
when a = d, return e; else return f
-Example:
- SELECT
- CASE deptno
-   WHEN 1 THEN Engineering
-   WHEN 2 THEN Finance
-   ELSE admin
- END,
- CASE zone
-   WHEN 7 THEN Americas
-   ELSE Asia-Pac
- END
- FROM emp_details
-Function class:org.apache.hadoop.hive.ql.udf.generic.GenericUDFCase
-Function type:BUILTIN
 PREHOOK: query: EXPLAIN
 SELECT CASE 1
         WHEN 1 THEN 2
diff --git a/ql/src/test/results/clientpositive/llap/udf_case_thrift.q.out 
b/ql/src/test/results/clientpositive/llap/udf_case_thrift.q.out
index 3a70d8b4d60..6f7322821d0 100644
--- a/ql/src/test/results/clientpositive/llap/udf_case_thrift.q.out
+++ b/ql/src/test/results/clientpositive/llap/udf_case_thrift.q.out
@@ -50,7 +50,7 @@ STAGE PLANS:
           alias: src_thrift
           Row Limit Per Split: 3
           Select Operator
-            expressions: CASE (lint[0]) WHEN (0) THEN ((lint[0] + 1)) WHEN (1) 
THEN ((lint[0] + 2)) WHEN (2) THEN (100) ELSE (5) END (type: int), CASE 
(lstring[0]) WHEN ('0') THEN ('zero') WHEN ('10') THEN (concat(lstring[0], ' is 
ten')) ELSE ('default') END (type: string), CASE (lstring[0]) WHEN ('0') THEN 
(lstring) ELSE (null) END[0] (type: string)
+            expressions: CASE WHEN ((lint[0] = 0)) THEN ((lint[0] + 1)) WHEN 
((lint[0] = 1)) THEN ((lint[0] + 2)) WHEN ((lint[0] = 2)) THEN (100) ELSE (5) 
END (type: int), CASE WHEN ((lstring[0] = '0')) THEN ('zero') WHEN ((lstring[0] 
= '10')) THEN (concat(lstring[0], ' is ten')) ELSE ('default') END (type: 
string), CASE WHEN ((lstring[0] = '0')) THEN (lstring) ELSE (null) END[0] 
(type: string)
             outputColumnNames: _col0, _col1, _col2
             ListSink
 
diff --git 
a/ql/src/test/results/clientpositive/perf/tpcds30tb/tez/cbo_query39.q.out 
b/ql/src/test/results/clientpositive/perf/tpcds30tb/tez/cbo_query39.q.out
index 1ef18c2019d..5e6bcc5f689 100644
--- a/ql/src/test/results/clientpositive/perf/tpcds30tb/tez/cbo_query39.q.out
+++ b/ql/src/test/results/clientpositive/perf/tpcds30tb/tez/cbo_query39.q.out
@@ -3,8 +3,8 @@ HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], 
d_moy=[CAST(4):INTEGER], mean=[
   HiveSortLimit(sort0=[$0], sort1=[$1], sort2=[$2], sort3=[$3], sort4=[$6], 
sort5=[$7], dir0=[ASC], dir1=[ASC], dir2=[ASC], dir3=[ASC], dir4=[ASC], 
dir5=[ASC])
     HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], mean=[$6], cov=[$7], 
w_warehouse_sk0=[$0], i_item_sk0=[$1], mean0=[$2], cov0=[$3])
       HiveJoin(condition=[AND(=($5, $1), =($4, $0))], joinType=[inner], 
algorithm=[none], cost=[not available])
-        HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], 
mean=[/(CAST($5):DOUBLE, $6)], cov=[CASE(=(/(CAST($5):DOUBLE, $6), 0), 
null:DOUBLE, /(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, 
-($4, 1))), 0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)))])
-          HiveFilter(condition=[CASE(=(/(CAST($5):DOUBLE, $6), 0), false, 
>(/(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, -($4, 1))), 
0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)), 1))])
+        HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], 
mean=[/(CAST($5):DOUBLE, $6)], cov=[CASE(=(/(CAST($5):DOUBLE, $6), 0E0), 
null:DOUBLE, /(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, 
-($4, 1))), 0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)))])
+          HiveFilter(condition=[CASE(=(/(CAST($5):DOUBLE, $6), 0E0), false, 
>(/(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, -($4, 1))), 
0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)), 1))])
             HiveAggregate(group=[{1, 2}], agg#0=[sum($5)], agg#1=[sum($4)], 
agg#2=[count($4)], agg#3=[sum($3)], agg#4=[count($3)])
               HiveProject($f0=[$6], $f1=[$5], $f2=[$3], $f4=[$2], 
$f40=[CAST($2):DOUBLE], $f6=[*(CAST($2):DOUBLE, CAST($2):DOUBLE)])
                 HiveJoin(condition=[=($1, $5)], joinType=[inner], 
algorithm=[none], cost=[not available])
@@ -16,8 +16,8 @@ HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], 
d_moy=[CAST(4):INTEGER], mean=[
                         HiveTableScan(table=[[default, date_dim]], 
table:alias=[date_dim])
                   HiveProject(w_warehouse_sk=[$0], w_warehouse_name=[$2])
                     HiveTableScan(table=[[default, warehouse]], 
table:alias=[warehouse])
-        HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], 
mean=[/(CAST($5):DOUBLE, $6)], cov=[CASE(=(/(CAST($5):DOUBLE, $6), 0), 
null:DOUBLE, /(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, 
-($4, 1))), 0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)))])
-          HiveFilter(condition=[CASE(=(/(CAST($5):DOUBLE, $6), 0), false, 
>(/(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, -($4, 1))), 
0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)), 1))])
+        HiveProject(w_warehouse_sk=[$0], i_item_sk=[$1], 
mean=[/(CAST($5):DOUBLE, $6)], cov=[CASE(=(/(CAST($5):DOUBLE, $6), 0E0), 
null:DOUBLE, /(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, 
-($4, 1))), 0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)))])
+          HiveFilter(condition=[CASE(=(/(CAST($5):DOUBLE, $6), 0E0), false, 
>(/(POWER(/(-($2, /(*($3, $3), $4)), CASE(=($4, 1), null:BIGINT, -($4, 1))), 
0.5:DECIMAL(2, 1)), /(CAST($5):DOUBLE, $6)), 1))])
             HiveAggregate(group=[{1, 2}], agg#0=[sum($5)], agg#1=[sum($4)], 
agg#2=[count($4)], agg#3=[sum($3)], agg#4=[count($3)])
               HiveProject($f0=[$6], $f1=[$5], $f2=[$3], $f4=[$2], 
$f40=[CAST($2):DOUBLE], $f6=[*(CAST($2):DOUBLE, CAST($2):DOUBLE)])
                 HiveJoin(condition=[=($1, $5)], joinType=[inner], 
algorithm=[none], cost=[not available])

Reply via email to