You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by bu...@apache.org on 2016/07/26 21:23:24 UTC

[4/4] asterixdb git commit: Support CASE expression in SQL++.

Support CASE expression in SQL++.

- support both simple CASE expression and searched CASE expression;
- support heterogenous return types of a CASE expression;
- remove IfElseExpression in SQL++;
- remove IfElseToSwitchCaseFunctionRule.java since the plan pattern it tries to identify is no longer right;
- unify CastRecordDescriptor and CastListDescriptor into CastTypeDescriptor;
- fix IS NULL for the case that the input is MISSING;
- let CastTypeDescriptor have a generated runtime so as to handle NULL/MISSING correctly.

Change-Id: Id9de7c3df70be43456e38a61ce767cc14f09e661
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1015
Reviewed-by: Till Westmann <ti...@apache.org>
Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>


Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/c8c067c5
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/c8c067c5
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/c8c067c5

Branch: refs/heads/master
Commit: c8c067c58cd19052fa9c108f08e42fdfd9ae6cec
Parents: f23d86e
Author: Yingyi Bu <yi...@couchbase.com>
Authored: Mon Jul 25 23:37:19 2016 -0700
Committer: Yingyi Bu <bu...@gmail.com>
Committed: Tue Jul 26 14:21:59 2016 -0700

----------------------------------------------------------------------
 .../asterix/optimizer/base/RuleCollections.java |   4 +-
 .../rules/AsterixInlineVariablesRule.java       |   2 +-
 .../optimizer/rules/ConstantFoldingRule.java    |  19 +-
 .../rules/IfElseToSwitchCaseFunctionRule.java   | 130 --------
 .../rules/InjectToAnyTypeCastRule.java          | 145 +++++++++
 ...eDynamicTypeCastForExternalFunctionRule.java |  24 +-
 .../rules/IntroduceDynamicTypeCastRule.java     |  10 +-
 ...IntroduceSecondaryIndexInsertDeleteRule.java |   2 +-
 .../rules/typecast/StaticTypeCastUtil.java      |  14 +-
 .../LangExpressionToPlanTranslator.java         |  51 ++-
 .../SqlppExpressionToPlanTranslator.java        | 153 +++++++--
 .../translator/util/FunctionCollection.java     |  10 +-
 .../file/SecondaryBTreeOperationsHelper.java    |  54 ++--
 .../file/SecondaryIndexOperationsHelper.java    |  39 ++-
 .../SecondaryInvertedIndexOperationsHelper.java |  46 +--
 .../file/SecondaryRTreeOperationsHelper.java    | 102 +++---
 .../apache/asterix/runtime/NullMissingTest.java |   6 +-
 .../optimizerts/queries/tpch/q12_shipping.sqlpp |  56 ++++
 .../results/query-ASTERIXDB-1203.plan           |   3 +-
 .../results/query-ASTERIXDB-865.plan            |   3 +-
 .../optimizerts/results/tpch/q12_shipping.plan  |  43 +++
 .../parserts/queries_sqlpp/IfInFLOWGR.sqlpp     |   5 +-
 .../parserts/queries_sqlpp/IfThenElse.sqlpp     |   8 +-
 .../parserts/queries_sqlpp/functionDecl2.sqlpp  |   4 +-
 .../parserts/queries_sqlpp/nestedFLWOGR1.sqlpp  |   7 +-
 .../parserts/queries_sqlpp/nestedFLWOGR2.sqlpp  |   8 +-
 .../results_parser_sqlpp/IfInFLOWGR.ast         |  16 +-
 .../results_parser_sqlpp/IfThenElse.ast         |  16 +-
 .../results_parser_sqlpp/functionDecl2.ast      |  16 +-
 .../results_parser_sqlpp/nestedFLWOGR1.ast      |  16 +-
 .../results_parser_sqlpp/nestedFLWOGR2.ast      |  16 +-
 .../ifthenelse_02/ifthenelse_01.3.query.aql     |  23 ++
 .../query-ASTERIXDB-819-2.1.query.aql           |  23 ++
 .../query-ASTERIXDB-819.1.query.aql             |  23 ++
 .../misc/case_01/case_01.1.query.sqlpp          |  28 ++
 .../misc/case_02/case_02.1.query.sqlpp          |  29 ++
 .../misc/case_03/case_03.1.query.sqlpp          |  28 ++
 .../misc/case_04/case_04.1.query.sqlpp          |  28 ++
 .../misc/case_05/case_05.1.query.sqlpp          |  30 ++
 .../misc/case_06/case_06.1.query.sqlpp          |  26 ++
 .../misc/case_07/case_07.1.query.sqlpp          |  30 ++
 .../ifthenelse_01/ifthenelse_01.3.query.sqlpp   |  12 +-
 .../query-issue258.2.update.sqlpp               |  14 +-
 .../q08_national_market_share.3.query.sqlpp     |   2 +-
 .../q12_shipping/q12_shipping.3.query.sqlpp     |  10 +-
 .../q14_promotion_effect.3.query.sqlpp          |   5 +-
 .../q08_national_market_share.3.query.sqlpp     |   3 +-
 .../q12_shipping/q12_shipping.3.query.sqlpp     |   6 +-
 .../q14_promotion_effect.3.query.sqlpp          |   6 +-
 .../q08_national_market_share.3.query.sqlpp     |   2 +-
 .../q12_shipping/q12_shipping.3.query.sqlpp     |   4 +-
 .../q14_promotion_effect.3.query.sqlpp          |   2 +-
 .../q08_national_market_share.3.query.sqlpp     |   2 +-
 .../q12_shipping/q12_shipping.3.query.sqlpp     |  10 +-
 .../q14_promotion_effect.3.query.sqlpp          |   5 +-
 .../q08_national_market_share.3.query.sqlpp     |   2 +-
 .../q12_shipping/q12_shipping.3.query.sqlpp     |   5 +-
 .../q14_promotion_effect.3.query.sqlpp          |   2 +-
 .../query-issue218-2.1.ddl.sqlpp                |   8 +-
 .../query-issue218/query-issue218.1.ddl.sqlpp   |   8 +-
 .../results/misc/case_01/case_01.1.adm          |   6 +
 .../results/misc/case_02/case_02.1.adm          |   6 +
 .../results/misc/case_03/case_03.1.adm          |   6 +
 .../results/misc/case_04/case_04.1.adm          |   6 +
 .../results/misc/case_05/case_05.1.adm          |   6 +
 .../results/misc/case_06/case_06.1.adm          |   6 +
 .../misc/ifthenelse_02/ifthenelse_02.1.adm      |   1 +
 .../query-ASTERIXDB-819-2.1.adm                 |   1 +
 .../query-ASTERIXDB-819.1.adm                   |   1 +
 .../runtimets/results/null-missing/is/is.1.adm  |   2 +-
 .../misc/ifthenelse_01/ifthenelse_01.3.ast      |  16 +-
 .../q08_national_market_share.3.ast             |  31 +-
 .../q12_shipping/q12_shipping.3.ast             |  96 +++---
 .../q14_promotion_effect.3.ast                  |  50 +--
 .../q08_national_market_share.3.ast             |  34 +-
 .../tpch/q12_shipping/q12_shipping.3.ast        |  93 +++---
 .../q14_promotion_effect.3.ast                  |  47 +--
 .../src/test/resources/runtimets/testsuite.xml  |  15 +
 .../resources/runtimets/testsuite_sqlpp.xml     |  35 ++
 .../lang/aql/visitor/AQLInlineUdfsVisitor.java  |   4 +-
 .../asterix/lang/common/base/Expression.java    |   3 +-
 .../visitor/AbstractInlineUdfsVisitor.java      |  93 +++---
 .../visitor/SubstituteExpressionVisitor.java    |   2 +-
 .../lang/sqlpp/expression/CaseExpression.java   | 129 ++++++++
 .../lang/sqlpp/rewrites/SqlppQueryRewriter.java |  14 +
 .../visitor/InlineColumnAliasVisitor.java       |  14 +
 .../SqlppBuiltinFunctionRewriteVisitor.java     |  52 +++
 .../visitor/SqlppInlineUdfsVisitor.java         |  26 +-
 .../lang/sqlpp/util/SqlppRewriteUtil.java       |  10 +
 .../visitor/CheckSql92AggregateVisitor.java     |   9 +-
 .../sqlpp/visitor/CheckSubqueryVisitor.java     | 316 +++++++++++++++++++
 .../lang/sqlpp/visitor/DeepCopyVisitor.java     |  34 +-
 .../lang/sqlpp/visitor/FreeVariableVisitor.java |  37 ++-
 .../sqlpp/visitor/SqlppAstPrintVisitor.java     |  27 +-
 ...SqlppCloneAndSubstituteVariablesVisitor.java |  15 +
 .../sqlpp/visitor/SqlppFormatPrintVisitor.java  |  22 ++
 .../SqlppSubstituteExpressionsVisitor.java      |  15 +
 .../visitor/base/AbstractSqlppAstVisitor.java   |   6 +
 .../AbstractSqlppSimpleExpressionVisitor.java   |  30 +-
 .../lang/sqlpp/visitor/base/ISqlppVisitor.java  |   3 +
 .../src/main/javacc/SQLPP.html                  |   7 +-
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj |  42 ++-
 .../om/functions/AsterixBuiltinFunctions.java   |  14 +-
 .../impl/CastListResultTypeComputer.java        |  46 ---
 .../impl/CastRecordResultTypeComputer.java      |  40 ---
 .../om/typecomputer/impl/CastTypeComputer.java  |  46 +++
 .../typecomputer/impl/SwitchCaseComputer.java   |  33 +-
 .../common/AbstractTypeCheckEvaluator.java      |  18 +-
 .../functions/CastListDescriptor.java           | 105 ------
 .../functions/CastRecordDescriptor.java         | 102 ------
 .../functions/CastTypeDescriptor.java           | 154 +++++++++
 .../functions/IsMissingDescriptor.java          |   4 +-
 .../evaluators/functions/IsNullDescriptor.java  |   7 +-
 .../functions/IsUnknownDescriptor.java          |   6 +-
 .../functions/SwitchCaseDescriptor.java         |   7 +-
 .../runtime/formats/NonTaggedDataFormat.java    |  68 ++--
 116 files changed, 2336 insertions(+), 1086 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
index 683d722..0fba9da 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/base/RuleCollections.java
@@ -36,7 +36,7 @@ import org.apache.asterix.optimizer.rules.ExtractDistinctByExpressionsRule;
 import org.apache.asterix.optimizer.rules.ExtractOrderExpressionsRule;
 import org.apache.asterix.optimizer.rules.FeedScanCollectionToUnnest;
 import org.apache.asterix.optimizer.rules.FuzzyEqRule;
-import org.apache.asterix.optimizer.rules.IfElseToSwitchCaseFunctionRule;
+import org.apache.asterix.optimizer.rules.InjectToAnyTypeCastRule;
 import org.apache.asterix.optimizer.rules.InlineUnnestFunctionRule;
 import org.apache.asterix.optimizer.rules.IntroduceAutogenerateIDRule;
 import org.apache.asterix.optimizer.rules.IntroduceDynamicTypeCastForExternalFunctionRule;
@@ -173,7 +173,6 @@ public final class RuleCollections {
         normalization.add(new RemoveRedundantSelectRule());
         normalization.add(new UnnestToDataScanRule());
         normalization.add(new MetaFunctionToMetaVariableRule());
-        normalization.add(new IfElseToSwitchCaseFunctionRule());
         normalization.add(new FuzzyEqRule());
         normalization.add(new SimilarityCheckRule());
         return normalization;
@@ -282,6 +281,7 @@ public final class RuleCollections {
         planCleanupRules.add(new IntroduceDynamicTypeCastForExternalFunctionRule());
         planCleanupRules.add(new RemoveUnusedAssignAndAggregateRule());
         planCleanupRules.add(new RemoveCartesianProductWithEmptyBranchRule());
+        planCleanupRules.add(new InjectToAnyTypeCastRule());
         return planCleanupRules;
     }
 

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/AsterixInlineVariablesRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/AsterixInlineVariablesRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/AsterixInlineVariablesRule.java
index 5486e64..74640a6 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/AsterixInlineVariablesRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/AsterixInlineVariablesRule.java
@@ -31,7 +31,7 @@ public class AsterixInlineVariablesRule extends InlineVariablesRule {
         doNotInlineFuncs.add(AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX);
         doNotInlineFuncs.add(AsterixBuiltinFunctions.CLOSED_RECORD_CONSTRUCTOR);
         doNotInlineFuncs.add(AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR);
-        doNotInlineFuncs.add(AsterixBuiltinFunctions.CAST_RECORD);
+        doNotInlineFuncs.add(AsterixBuiltinFunctions.CAST_TYPE);
         doNotInlineFuncs.add(AsterixBuiltinFunctions.CREATE_CIRCLE);
         doNotInlineFuncs.add(AsterixBuiltinFunctions.CREATE_LINE);
         doNotInlineFuncs.add(AsterixBuiltinFunctions.CREATE_MBR);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
index b29f110..9d9dda0 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/ConstantFoldingRule.java
@@ -83,13 +83,13 @@ public class ConstantFoldingRule implements IAlgebraicRewriteRule {
 
     // Function Identifier sets that the ConstantFolding rule should skip to apply.
     // Most of them are record-related functions.
-    private static final ImmutableSet<FunctionIdentifier> FUNC_ID_SET_THAT_SHOULD_NOT_BE_APPLIED = ImmutableSet.of(
-            AsterixBuiltinFunctions.RECORD_MERGE, AsterixBuiltinFunctions.ADD_FIELDS,
-            AsterixBuiltinFunctions.REMOVE_FIELDS, AsterixBuiltinFunctions.GET_RECORD_FIELDS,
-            AsterixBuiltinFunctions.GET_RECORD_FIELD_VALUE, AsterixBuiltinFunctions.FIELD_ACCESS_NESTED,
-            AsterixBuiltinFunctions.GET_ITEM, AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR,
-            AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX, AsterixBuiltinFunctions.CAST_RECORD,
-            AsterixBuiltinFunctions.CAST_LIST, AsterixBuiltinFunctions.META, AsterixBuiltinFunctions.META_KEY);
+    private static final ImmutableSet<FunctionIdentifier> FUNC_ID_SET_THAT_SHOULD_NOT_BE_APPLIED =
+            ImmutableSet.of(AsterixBuiltinFunctions.RECORD_MERGE, AsterixBuiltinFunctions.ADD_FIELDS,
+                    AsterixBuiltinFunctions.REMOVE_FIELDS, AsterixBuiltinFunctions.GET_RECORD_FIELDS,
+                    AsterixBuiltinFunctions.GET_RECORD_FIELD_VALUE, AsterixBuiltinFunctions.FIELD_ACCESS_NESTED,
+                    AsterixBuiltinFunctions.GET_ITEM, AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR,
+                    AsterixBuiltinFunctions.FIELD_ACCESS_BY_INDEX, AsterixBuiltinFunctions.CAST_TYPE,
+                    AsterixBuiltinFunctions.META, AsterixBuiltinFunctions.META_KEY);
 
     /** Throws exceptions in substituiteProducedVariable, setVarType, and one getVarType method. */
     private static final IVariableTypeEnvironment _emptyTypeEnv = new IVariableTypeEnvironment() {
@@ -204,8 +204,9 @@ public class ConstantFoldingRule implements IAlgebraicRewriteRule {
             }
             if (expr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.FIELD_ACCESS_BY_NAME)) {
                 ARecordType rt = (ARecordType) _emptyTypeEnv.getType(expr.getArguments().get(0).getValue());
-                String str = ((AString) ((AsterixConstantValue) ((ConstantExpression) expr.getArguments().get(1)
-                        .getValue()).getValue()).getObject()).getStringValue();
+                String str =
+                        ((AString) ((AsterixConstantValue) ((ConstantExpression) expr.getArguments().get(1).getValue())
+                                .getValue()).getObject()).getStringValue();
                 int k = rt.getFieldIndex(str);
                 if (k >= 0) {
                     // wait for the ByNameToByIndex rule to apply

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java
deleted file mode 100644
index 76d4a47..0000000
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IfElseToSwitchCaseFunctionRule.java
+++ /dev/null
@@ -1,130 +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.asterix.optimizer.rules;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.asterix.lang.common.util.FunctionUtil;
-import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
-import org.apache.commons.lang3.mutable.Mutable;
-import org.apache.commons.lang3.mutable.MutableObject;
-import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
-import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
-import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
-import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
-import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
-import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
-import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.AssignOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SelectOperator;
-import org.apache.hyracks.algebricks.core.algebra.operators.logical.SubplanOperator;
-import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
-
-public class IfElseToSwitchCaseFunctionRule implements IAlgebraicRewriteRule {
-
-    @Override
-    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
-            throws AlgebricksException {
-        return false;
-    }
-
-    @Override
-    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
-            throws AlgebricksException {
-        AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
-        if (op1.getOperatorTag() != LogicalOperatorTag.ASSIGN)
-            return false;
-
-        AssignOperator assignOp = (AssignOperator) op1;
-        List<Mutable<ILogicalExpression>> assignExprs = assignOp.getExpressions();
-        if (assignExprs.size() > 1)
-            return false;
-        ILogicalExpression expr = assignExprs.get(0).getValue();
-        if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
-            AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) expr;
-            if (!funcExpr.getFunctionIdentifier().equals(AsterixBuiltinFunctions.CONCAT_NON_NULL))
-                return false;
-        }
-
-        AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
-        if (op2.getOperatorTag() != LogicalOperatorTag.SUBPLAN)
-            return false;
-
-        SubplanOperator subplan = (SubplanOperator) op2;
-        List<ILogicalPlan> subPlans = subplan.getNestedPlans();
-        List<Mutable<ILogicalExpression>> arguments = new ArrayList<Mutable<ILogicalExpression>>();
-        for (ILogicalPlan plan : subPlans) {
-            List<Mutable<ILogicalOperator>> roots = plan.getRoots();
-
-            AbstractLogicalOperator nestedRoot = (AbstractLogicalOperator) roots.get(0).getValue();
-            if (nestedRoot.getOperatorTag() != LogicalOperatorTag.SELECT)
-                return false;
-            SelectOperator selectOp = (SelectOperator) nestedRoot;
-
-            AbstractLogicalOperator nestedNextOp = (AbstractLogicalOperator) nestedRoot.getInputs().get(0).getValue();
-            if (nestedNextOp.getOperatorTag() != LogicalOperatorTag.ASSIGN)
-                return false;
-            AssignOperator assignRoot = (AssignOperator) nestedNextOp;
-            Mutable<ILogicalExpression> actionExprRef = assignRoot.getExpressions().get(0);
-
-            arguments.add(selectOp.getCondition());
-            arguments.add(actionExprRef);
-            AbstractLogicalOperator nestedBottomOp = (AbstractLogicalOperator) assignRoot.getInputs().get(0).getValue();
-
-            if (nestedBottomOp.getOperatorTag() != LogicalOperatorTag.NESTEDTUPLESOURCE)
-                return false;
-        }
-
-        AbstractLogicalOperator op3 = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
-        if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN)
-            return false;
-
-        AssignOperator bottomAssign = (AssignOperator) op3;
-        LogicalVariable conditionVar = bottomAssign.getVariables().get(0);
-        Mutable<ILogicalExpression> switchCondition = new MutableObject<ILogicalExpression>(
-                new VariableReferenceExpression(conditionVar));
-        List<Mutable<ILogicalExpression>> argumentRefs = new ArrayList<Mutable<ILogicalExpression>>();
-        argumentRefs.add(switchCondition);
-        argumentRefs.addAll(arguments);
-
-        /** replace the branch conditions */
-        for (int i = 0; i < arguments.size(); i += 2) {
-            if (arguments.get(i).getValue().equals(switchCondition.getValue())) {
-                arguments.get(i).setValue(ConstantExpression.TRUE);
-            } else {
-                arguments.get(i).setValue(ConstantExpression.FALSE);
-            }
-        }
-
-        ILogicalExpression callExpr = new ScalarFunctionCallExpression(
-                FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.SWITCH_CASE), argumentRefs);
-
-        assignOp.getInputs().get(0).setValue(op3);
-        assignOp.getExpressions().get(0).setValue(callExpr);
-        context.computeAndSetTypeEnvironmentForOperator(assignOp);
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectToAnyTypeCastRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectToAnyTypeCastRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectToAnyTypeCastRule.java
new file mode 100644
index 0000000..075c1f0
--- /dev/null
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/InjectToAnyTypeCastRule.java
@@ -0,0 +1,145 @@
+/*
+ * 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.asterix.optimizer.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.asterix.lang.common.util.FunctionUtil;
+import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
+import org.apache.asterix.om.typecomputer.base.TypeCastUtils;
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.asterix.om.types.AUnionType;
+import org.apache.asterix.om.types.BuiltinType;
+import org.apache.asterix.om.types.IAType;
+import org.apache.commons.lang3.mutable.Mutable;
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
+import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
+import org.apache.hyracks.algebricks.core.algebra.base.IOptimizationContext;
+import org.apache.hyracks.algebricks.core.algebra.base.LogicalExpressionTag;
+import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
+import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
+
+/**
+ * This rule injects cast functions for "THEN" and "ELSE" branches of a switch-case function if
+ * different "THEN" and "ELSE" branches have heterogeneous return types.
+ */
+public class InjectToAnyTypeCastRule implements IAlgebraicRewriteRule {
+
+    @Override
+    public boolean rewritePost(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
+        ILogicalOperator op = opRef.getValue();
+        if (op.getInputs().isEmpty()) {
+            return false;
+        }
+        // Populates the latest type information.
+        context.computeAndSetTypeEnvironmentForOperator(op);
+        if (op.acceptExpressionTransform(exprRef -> injectToAnyTypeCast(op, exprRef, context))) {
+            // Generates the up-to-date type information.
+            context.computeAndSetTypeEnvironmentForOperator(op);
+            return true;
+        }
+        return false;
+    }
+
+    // Injects type casts to cast return expressions' return types to ANY.
+    private boolean injectToAnyTypeCast(ILogicalOperator op, Mutable<ILogicalExpression> exprRef,
+            IOptimizationContext context) throws AlgebricksException {
+        ILogicalExpression expr = exprRef.getValue();
+        if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return false;
+        }
+        boolean rewritten = false;
+        AbstractFunctionCallExpression func = (AbstractFunctionCallExpression) expr;
+        for (Mutable<ILogicalExpression> argRef : func.getArguments()) {
+            // Recursively rewrites arguments.
+            if (injectToAnyTypeCast(op, argRef, context)) {
+                context.computeAndSetTypeEnvironmentForOperator(op);
+                rewritten = true;
+            }
+        }
+        if (!func.getFunctionIdentifier().equals(AsterixBuiltinFunctions.SWITCH_CASE)) {
+            return rewritten;
+        }
+        return rewriteSwitchCase(op, func, context);
+    }
+
+    // Injects casts that cast types to ANY for different "THEN" and "ELSE" branches.
+    private boolean rewriteSwitchCase(ILogicalOperator op, AbstractFunctionCallExpression func,
+            IOptimizationContext context) throws AlgebricksException {
+        IVariableTypeEnvironment env = context.getOutputTypeEnvironment(op.getInputs().get(0).getValue());
+        if (!this.isHeterogenous(func, env)) {
+            return false;
+        }
+        List<Mutable<ILogicalExpression>> argRefs = func.getArguments();
+        int argSize = argRefs.size();
+        boolean rewritten = false;
+        for (int argIndex = 2; argIndex < argSize; argIndex += (argIndex + 2 == argSize) ? 1 : 2) {
+            Mutable<ILogicalExpression> argRef = argRefs.get(argIndex);
+            IAType type = (IAType) env.getType(argRefs.get(argIndex).getValue());
+            ATypeTag tag = type.getTypeTag();
+            // Casts are only needed when the original return type is a complex type.
+            // (In the runtime, there is already a type tag for scalar types.)
+            if (tag == ATypeTag.RECORD || tag == ATypeTag.UNORDEREDLIST || tag == ATypeTag.ORDEREDLIST) {
+                ILogicalExpression argExpr = argRef.getValue();
+                // Injects a cast call to cast the data type to ANY.
+                ScalarFunctionCallExpression castFunc = new ScalarFunctionCallExpression(
+                        FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_TYPE),
+                        new ArrayList<>(Collections.singletonList(new MutableObject<>(argExpr))));
+                TypeCastUtils.setRequiredAndInputTypes(castFunc, BuiltinType.ANY, type);
+                argRef.setValue(castFunc);
+                rewritten = true;
+            }
+        }
+        return rewritten;
+    }
+
+    // Checks whether "THEN" and "ELSE" branches return the heterogeneous types.
+    private boolean isHeterogenous(AbstractFunctionCallExpression func, IVariableTypeEnvironment env)
+            throws AlgebricksException {
+        List<Mutable<ILogicalExpression>> argRefs = func.getArguments();
+        int argSize = argRefs.size();
+        IAType currentType = null;
+        boolean heterogenous = false;
+        for (int argIndex = 2; argIndex < argSize; argIndex += (argIndex + 2 == argSize) ? 1 : 2) {
+            IAType type = (IAType) env.getType(argRefs.get(argIndex).getValue());
+            ATypeTag typeTag = type.getTypeTag();
+            // Null and missing are not considered as heterogeneous with other types.
+            if (typeTag != ATypeTag.NULL && typeTag != ATypeTag.MISSING) {
+                if (typeTag == ATypeTag.UNION) {
+                    type = ((AUnionType) type).getActualType();
+                }
+                if (currentType != null && !type.equals(currentType)) {
+                    heterogenous = true;
+                    break;
+                }
+                currentType = type;
+            }
+        }
+        return heterogenous;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
index 0fb5b0b..946ec39 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastForExternalFunctionRule.java
@@ -22,14 +22,13 @@ package org.apache.asterix.optimizer.rules;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.lang3.mutable.Mutable;
-
 import org.apache.asterix.metadata.functions.AsterixExternalScalarFunctionInfo;
 import org.apache.asterix.om.functions.AsterixBuiltinFunctions;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.AUnionType;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.util.NonTaggedFormatUtil;
+import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
@@ -52,7 +51,8 @@ import org.apache.hyracks.algebricks.core.rewriter.base.IAlgebraicRewriteRule;
 public class IntroduceDynamicTypeCastForExternalFunctionRule implements IAlgebraicRewriteRule {
 
     @Override
-    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context) throws AlgebricksException {
+    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
+            throws AlgebricksException {
         return false;
     }
 
@@ -64,17 +64,21 @@ public class IntroduceDynamicTypeCastForExternalFunctionRule implements IAlgebra
          * resulting plan: distribute_result - project - assign (external function call) - assign (cast-record) - assign(open_record_constructor)
          */
         AbstractLogicalOperator op1 = (AbstractLogicalOperator) opRef.getValue();
-        if (op1.getOperatorTag() != LogicalOperatorTag.DISTRIBUTE_RESULT)
+        if (op1.getOperatorTag() != LogicalOperatorTag.DISTRIBUTE_RESULT) {
             return false;
+        }
         AbstractLogicalOperator op2 = (AbstractLogicalOperator) op1.getInputs().get(0).getValue();
-        if (op2.getOperatorTag() != LogicalOperatorTag.PROJECT)
+        if (op2.getOperatorTag() != LogicalOperatorTag.PROJECT) {
             return false;
+        }
         AbstractLogicalOperator op3 = (AbstractLogicalOperator) op2.getInputs().get(0).getValue();
-        if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+        if (op3.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
             return false;
+        }
         AbstractLogicalOperator op4 = (AbstractLogicalOperator) op3.getInputs().get(0).getValue();
-        if (op4.getOperatorTag() != LogicalOperatorTag.ASSIGN)
+        if (op4.getOperatorTag() != LogicalOperatorTag.ASSIGN) {
             return false;
+        }
 
         // Op1 : assign (external function call), Op2 : assign (open_record_constructor)
         AssignOperator assignOp1 = (AssignOperator) op3;
@@ -84,8 +88,8 @@ public class IntroduceDynamicTypeCastForExternalFunctionRule implements IAlgebra
         FunctionIdentifier fid = null;
         ILogicalExpression assignExpr = assignOp2.getExpressions().get(0).getValue();
         if (assignExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) {
-            ScalarFunctionCallExpression funcExpr = (ScalarFunctionCallExpression) assignOp2.getExpressions().get(0)
-                    .getValue();
+            ScalarFunctionCallExpression funcExpr =
+                    (ScalarFunctionCallExpression) assignOp2.getExpressions().get(0).getValue();
             fid = funcExpr.getFunctionIdentifier();
 
             if (fid != AsterixBuiltinFunctions.OPEN_RECORD_CONSTRUCTOR) {
@@ -137,7 +141,7 @@ public class IntroduceDynamicTypeCastForExternalFunctionRule implements IAlgebra
         }
         if (cast) {
             IntroduceDynamicTypeCastRule.addWrapperFunction(requiredRecordType, recordVar.get(0), assignOp1, context,
-                    AsterixBuiltinFunctions.CAST_RECORD);
+                    AsterixBuiltinFunctions.CAST_TYPE);
         }
         return cast || checkUnknown;
     }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
index e692678..f6cd015 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceDynamicTypeCastRule.java
@@ -173,7 +173,7 @@ public class IntroduceDynamicTypeCastRule implements IAlgebraicRewriteRule {
                     AsterixBuiltinFunctions.CHECK_UNKNOWN);
         }
         if (cast) {
-            addWrapperFunction(requiredRecordType, recordVar, op, context, AsterixBuiltinFunctions.CAST_RECORD);
+            addWrapperFunction(requiredRecordType, recordVar, op, context, AsterixBuiltinFunctions.CAST_TYPE);
         }
         return cast || checkUnknown;
     }
@@ -210,15 +210,15 @@ public class IntroduceDynamicTypeCastRule implements IAlgebraicRewriteRule {
                 if (var.equals(recordVar)) {
                     /** insert an assign operator to call the function on-top-of the variable */
                     IAType actualType = (IAType) env.getVarType(var);
-                    AbstractFunctionCallExpression cast = new ScalarFunctionCallExpression(
-                            FunctionUtil.getFunctionInfo(fd));
+                    AbstractFunctionCallExpression cast =
+                            new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(fd));
                     cast.getArguments()
                             .add(new MutableObject<ILogicalExpression>(new VariableReferenceExpression(var)));
                     /** enforce the required record type */
                     TypeCastUtils.setRequiredAndInputTypes(cast, requiredRecordType, actualType);
                     LogicalVariable newAssignVar = context.newVar();
-                    AssignOperator newAssignOperator = new AssignOperator(newAssignVar,
-                            new MutableObject<ILogicalExpression>(cast));
+                    AssignOperator newAssignOperator =
+                            new AssignOperator(newAssignVar, new MutableObject<ILogicalExpression>(cast));
                     newAssignOperator.getInputs().add(new MutableObject<ILogicalOperator>(op));
                     opRef.setValue(newAssignOperator);
                     context.computeAndSetTypeEnvironmentForOperator(newAssignOperator);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
index ae69093..c64258f 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
@@ -255,7 +255,7 @@ public class IntroduceSecondaryIndexInsertDeleteRule implements IAlgebraicRewrit
                     context.addNotToBeInlinedVar(castedRecVar);
                     //introduce casting to enforced type
                     AbstractFunctionCallExpression castFunc = new ScalarFunctionCallExpression(
-                            FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_RECORD));
+                            FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_TYPE));
                     // The first argument is the record
                     castFunc.getArguments()
                             .add(new MutableObject<ILogicalExpression>(insertOp.getPayloadExpression().getValue()));

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
index eaf9484..eac35cd 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/typecast/StaticTypeCastUtil.java
@@ -49,7 +49,6 @@ import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCa
 import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.IVariableTypeEnvironment;
 import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
-import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.algebricks.core.algebra.functions.IFunctionInfo;
 
 /**
@@ -455,24 +454,25 @@ public class StaticTypeCastUtil {
         if (argExpr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL
                 || argExpr.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
             IAType reqFieldType = inputFieldType;
-            FunctionIdentifier fi = null;
             // do not enforce nested type in the case of no-used variables
             switch (inputFieldType.getTypeTag()) {
                 case RECORD:
                     reqFieldType = DefaultOpenFieldType.NESTED_OPEN_RECORD_TYPE;
-                    fi = AsterixBuiltinFunctions.CAST_RECORD;
                     break;
                 case ORDEREDLIST:
                     reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AORDERED_LIST_TYPE;
-                    fi = AsterixBuiltinFunctions.CAST_LIST;
                     break;
                 case UNORDEREDLIST:
                     reqFieldType = DefaultOpenFieldType.NESTED_OPEN_AUNORDERED_LIST_TYPE;
-                    fi = AsterixBuiltinFunctions.CAST_LIST;
+                    break;
+                default:
+                    break;
             }
-            if (fi != null && !inputFieldType.equals(reqFieldType) && parameterVars.size() > 0) {
+            // do not enforce nested type in the case of no-used variables
+            if (!inputFieldType.equals(reqFieldType) && !parameterVars.isEmpty()) {
                 //inject dynamic type casting
-                injectCastFunction(FunctionUtil.getFunctionInfo(fi), reqFieldType, inputFieldType, expRef, argExpr);
+                injectCastFunction(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.CAST_TYPE), reqFieldType,
+                        inputFieldType, expRef, argExpr);
                 castInjected = true;
             }
             //recursively rewrite function arguments

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index 1894cc3..136dd5e 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -870,9 +870,9 @@ class LangExpressionToPlanTranslator
                 new MutableObject<>(new VariableReferenceExpression(varCond)), ifexpr.getThenExpr());
 
         // Creates a subplan for the "else" branch.
-        AbstractFunctionCallExpression notVarCond =
-                new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AlgebricksBuiltinFunctions.NOT),
-                        Collections.singletonList(new MutableObject<>(new VariableReferenceExpression(varCond))));
+        AbstractFunctionCallExpression notVarCond = new ScalarFunctionCallExpression(
+                FunctionUtil.getFunctionInfo(AlgebricksBuiltinFunctions.NOT),
+                Collections.singletonList(generateAndNotIsUnknownWrap(new VariableReferenceExpression(varCond))));
         Pair<ILogicalOperator, LogicalVariable> opAndVarForElse = constructSubplanOperatorForBranch(
                 opAndVarForThen.first, new MutableObject<>(notVarCond), ifexpr.getElseExpr());
 
@@ -882,7 +882,6 @@ class LangExpressionToPlanTranslator
         arguments.add(new MutableObject<>(new VariableReferenceExpression(varCond)));
         arguments.add(new MutableObject<>(ConstantExpression.TRUE));
         arguments.add(new MutableObject<>(new VariableReferenceExpression(opAndVarForThen.second)));
-        arguments.add(new MutableObject<>(ConstantExpression.FALSE));
         arguments.add(new MutableObject<>(new VariableReferenceExpression(opAndVarForElse.second)));
         AbstractFunctionCallExpression swithCaseExpr = new ScalarFunctionCallExpression(
                 FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.SWITCH_CASE), arguments);
@@ -1364,10 +1363,14 @@ class LangExpressionToPlanTranslator
 
     protected boolean expressionNeedsNoNesting(Expression expr) {
         Kind k = expr.getKind();
-        return k == Kind.LITERAL_EXPRESSION || k == Kind.LIST_CONSTRUCTOR_EXPRESSION
-                || k == Kind.RECORD_CONSTRUCTOR_EXPRESSION || k == Kind.VARIABLE_EXPRESSION || k == Kind.CALL_EXPRESSION
-                || k == Kind.OP_EXPRESSION || k == Kind.FIELD_ACCESSOR_EXPRESSION || k == Kind.INDEX_ACCESSOR_EXPRESSION
-                || k == Kind.UNARY_EXPRESSION || k == Kind.IF_EXPRESSION || k == Kind.INDEPENDENT_SUBQUERY;
+        boolean noNesting = k == Kind.LITERAL_EXPRESSION || k == Kind.LIST_CONSTRUCTOR_EXPRESSION
+                || k == Kind.RECORD_CONSTRUCTOR_EXPRESSION || k == Kind.VARIABLE_EXPRESSION;
+        noNesting = noNesting || k == Kind.CALL_EXPRESSION || k == Kind.OP_EXPRESSION
+                || k == Kind.FIELD_ACCESSOR_EXPRESSION;
+        noNesting = noNesting || k == Kind.INDEX_ACCESSOR_EXPRESSION || k == Kind.UNARY_EXPRESSION
+                || k == Kind.IF_EXPRESSION;
+        return noNesting || k == Kind.INDEPENDENT_SUBQUERY || k == Kind.CASE_EXPRESSION;
+
     }
 
     protected <T> List<T> mkSingletonArrayList(T item) {
@@ -1519,7 +1522,7 @@ class LangExpressionToPlanTranslator
      * @return a pair of the constructed subplan operator and the output variable for the branch.
      * @throws AsterixException
      */
-    private Pair<ILogicalOperator, LogicalVariable> constructSubplanOperatorForBranch(ILogicalOperator inputOp,
+    protected Pair<ILogicalOperator, LogicalVariable> constructSubplanOperatorForBranch(ILogicalOperator inputOp,
             Mutable<ILogicalExpression> selectExpr, Expression branchExpression) throws AsterixException {
         context.enterSubplan();
         SubplanOperator subplanOp = new SubplanOperator();
@@ -1555,4 +1558,34 @@ class LangExpressionToPlanTranslator
                 .add(new MutableObject<>(new ConstantExpression(new AsterixConstantValue(new AInt64(0L)))));
         return new AssignOperator(v1, new MutableObject<>(comparison));
     }
+
+    // Generates the filter condition for whether a conditional branch should be executed.
+    protected Mutable<ILogicalExpression> generateNoMatchedPrecedingWhenBranchesFilter(
+            List<ILogicalExpression> inputBooleanExprs) {
+        List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
+        for (ILogicalExpression inputBooleanExpr : inputBooleanExprs) {
+            // A NULL/MISSING valued WHEN expression does not lead to the corresponding THEN execution.
+            // Therefore, we should check a previous WHEN boolean condition is not unknown.
+            arguments.add(generateAndNotIsUnknownWrap(inputBooleanExpr));
+        }
+        Mutable<ILogicalExpression> hasBeenExecutedExprRef = new MutableObject<>(
+                new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.OR), arguments));
+        return new MutableObject<>(
+                new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.NOT),
+                        new ArrayList<>(Collections.singletonList(hasBeenExecutedExprRef))));
+    }
+
+    // For an input expression `expr`, return `expr AND expr IS NOT UNKOWN`.
+    protected Mutable<ILogicalExpression> generateAndNotIsUnknownWrap(ILogicalExpression logicalExpr) {
+        List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
+        arguments.add(new MutableObject<>(logicalExpr));
+        Mutable<ILogicalExpression> expr = new MutableObject<>(
+                new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.IS_UNKOWN),
+                        new ArrayList<>(Collections.singletonList(new MutableObject<>(logicalExpr)))));
+        arguments.add(new MutableObject<>(
+                new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.NOT),
+                        new ArrayList<>(Collections.singletonList(expr)))));
+        return new MutableObject<>(
+                new ScalarFunctionCallExpression(FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.AND), arguments));
+    }
 }

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
index b7ed988..e40de4b 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
@@ -20,6 +20,7 @@ package org.apache.asterix.translator;
 
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.List;
 
@@ -51,12 +52,14 @@ import org.apache.asterix.lang.sqlpp.clause.SelectElement;
 import org.apache.asterix.lang.sqlpp.clause.SelectRegular;
 import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
 import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
+import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
 import org.apache.asterix.lang.sqlpp.expression.IndependentSubquery;
 import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
 import org.apache.asterix.lang.sqlpp.optype.JoinType;
 import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
 import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
 import org.apache.asterix.metadata.declared.AqlMetadataProvider;
+import org.apache.asterix.om.base.ABoolean;
 import org.apache.asterix.om.base.AInt32;
 import org.apache.asterix.om.base.AString;
 import org.apache.asterix.om.constants.AsterixConstantValue;
@@ -72,9 +75,11 @@ import org.apache.hyracks.algebricks.core.algebra.base.ILogicalOperator;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalPlan;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalOperatorTag;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
+import org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.AggregateFunctionCallExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
+import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
 import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractBinaryJoinOperator;
 import org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractUnnestNonMapOperator;
@@ -142,8 +147,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
                 currentOpRef = new MutableObject<>(letClause.accept(this, currentOpRef).first);
             }
         }
-        Pair<ILogicalOperator, LogicalVariable> select = selectExpression.getSelectSetOperation().accept(this,
-                currentOpRef);
+        Pair<ILogicalOperator, LogicalVariable> select =
+                selectExpression.getSelectSetOperation().accept(this, currentOpRef);
         currentOpRef = new MutableObject<>(select.first);
         if (selectExpression.hasOrderby()) {
             currentOpRef = new MutableObject<>(selectExpression.getOrderbyClause().accept(this, currentOpRef).first);
@@ -151,8 +156,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
         if (selectExpression.hasLimit()) {
             currentOpRef = new MutableObject<>(selectExpression.getLimitClause().accept(this, currentOpRef).first);
         }
-        Pair<ILogicalOperator, LogicalVariable> result = produceSelectPlan(selectExpression.isSubquery(), currentOpRef,
-                select.second);
+        Pair<ILogicalOperator, LogicalVariable> result =
+                produceSelectPlan(selectExpression.isSubquery(), currentOpRef, select.second);
         if (selectExpression.isSubquery()) {
             context.exitSubplan();
         }
@@ -162,8 +167,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
     @Override
     public Pair<ILogicalOperator, LogicalVariable> visit(IndependentSubquery independentSubquery,
             Mutable<ILogicalOperator> tupleSource) throws AsterixException {
-        Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo = langExprToAlgExpression(independentSubquery.getExpr(),
-                tupleSource);
+        Pair<ILogicalExpression, Mutable<ILogicalOperator>> eo =
+                langExprToAlgExpression(independentSubquery.getExpr(), tupleSource);
         // Replaces nested tuple source with empty tuple source so that the subquery can be independent
         // from its input operators.
         replaceNtsWithEts(eo.second.getValue());
@@ -177,8 +182,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
     public Pair<ILogicalOperator, LogicalVariable> visit(SelectSetOperation selectSetOperation,
             Mutable<ILogicalOperator> tupSource) throws AsterixException {
         Mutable<ILogicalOperator> currentOpRef = tupSource;
-        Pair<ILogicalOperator, LogicalVariable> currentResult = selectSetOperation.getLeftInput().accept(this,
-                currentOpRef);
+        Pair<ILogicalOperator, LogicalVariable> currentResult =
+                selectSetOperation.getLeftInput().accept(this, currentOpRef);
         if (selectSetOperation.hasRightInputs()) {
             throw new NotImplementedException();
         }
@@ -236,12 +241,12 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
         if (fromTerm.hasPositionalVariable()) {
             LogicalVariable pVar = context.newVar(fromTerm.getPositionalVariable());
             // We set the positional variable type as INT64 type.
-            unnestOp = new UnnestOperator(fromVar,
-                    new MutableObject<ILogicalExpression>(makeUnnestExpression(eo.first)), pVar, BuiltinType.AINT64,
-                    new AqlPositionWriter());
+            unnestOp =
+                    new UnnestOperator(fromVar, new MutableObject<ILogicalExpression>(makeUnnestExpression(eo.first)),
+                            pVar, BuiltinType.AINT64, new AqlPositionWriter());
         } else {
-            unnestOp = new UnnestOperator(fromVar,
-                    new MutableObject<ILogicalExpression>(makeUnnestExpression(eo.first)));
+            unnestOp =
+                    new UnnestOperator(fromVar, new MutableObject<ILogicalExpression>(makeUnnestExpression(eo.first)));
         }
         unnestOp.getInputs().add(eo.second);
 
@@ -267,41 +272,41 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
             throws AsterixException {
         Mutable<ILogicalOperator> leftInputRef = uncorrelatedLeftBranchStack.pop();
         if (joinClause.getJoinType() == JoinType.INNER) {
-            Pair<ILogicalOperator, LogicalVariable> rightBranch = generateUnnestForBinaryCorrelateRightBranch(
-                    joinClause, inputRef, true);
+            Pair<ILogicalOperator, LogicalVariable> rightBranch =
+                    generateUnnestForBinaryCorrelateRightBranch(joinClause, inputRef, true);
             // A join operator with condition TRUE.
-            AbstractBinaryJoinOperator joinOperator = new InnerJoinOperator(
-                    new MutableObject<ILogicalExpression>(ConstantExpression.TRUE), leftInputRef,
-                    new MutableObject<ILogicalOperator>(rightBranch.first));
+            AbstractBinaryJoinOperator joinOperator =
+                    new InnerJoinOperator(new MutableObject<ILogicalExpression>(ConstantExpression.TRUE), leftInputRef,
+                            new MutableObject<ILogicalOperator>(rightBranch.first));
             Mutable<ILogicalOperator> joinOpRef = new MutableObject<>(joinOperator);
 
             // Add an additional filter operator.
-            Pair<ILogicalExpression, Mutable<ILogicalOperator>> conditionExprOpPair = langExprToAlgExpression(
-                    joinClause.getConditionExpression(), joinOpRef);
-            SelectOperator filter = new SelectOperator(new MutableObject<ILogicalExpression>(conditionExprOpPair.first),
-                    false, null);
+            Pair<ILogicalExpression, Mutable<ILogicalOperator>> conditionExprOpPair =
+                    langExprToAlgExpression(joinClause.getConditionExpression(), joinOpRef);
+            SelectOperator filter =
+                    new SelectOperator(new MutableObject<ILogicalExpression>(conditionExprOpPair.first), false, null);
             filter.getInputs().add(conditionExprOpPair.second);
             return new Pair<>(filter, rightBranch.second);
         } else {
             // Creates a subplan operator.
             SubplanOperator subplanOp = new SubplanOperator();
-            Mutable<ILogicalOperator> ntsRef = new MutableObject<>(
-                    new NestedTupleSourceOperator(new MutableObject<ILogicalOperator>(subplanOp)));
+            Mutable<ILogicalOperator> ntsRef =
+                    new MutableObject<>(new NestedTupleSourceOperator(new MutableObject<ILogicalOperator>(subplanOp)));
             subplanOp.getInputs().add(leftInputRef);
 
             // Enters the translation for a subplan.
             context.enterSubplan();
 
             // Adds an unnest operator to unnest to right expression.
-            Pair<ILogicalOperator, LogicalVariable> rightBranch = generateUnnestForBinaryCorrelateRightBranch(
-                    joinClause, ntsRef, true);
+            Pair<ILogicalOperator, LogicalVariable> rightBranch =
+                    generateUnnestForBinaryCorrelateRightBranch(joinClause, ntsRef, true);
             AbstractUnnestNonMapOperator rightUnnestOp = (AbstractUnnestNonMapOperator) rightBranch.first;
 
             // Adds an additional filter operator for the join condition.
             Pair<ILogicalExpression, Mutable<ILogicalOperator>> conditionExprOpPair = langExprToAlgExpression(
                     joinClause.getConditionExpression(), new MutableObject<ILogicalOperator>(rightUnnestOp));
-            SelectOperator filter = new SelectOperator(new MutableObject<ILogicalExpression>(conditionExprOpPair.first),
-                    false, null);
+            SelectOperator filter =
+                    new SelectOperator(new MutableObject<ILogicalExpression>(conditionExprOpPair.first), false, null);
             filter.getInputs().add(conditionExprOpPair.second);
 
             ILogicalOperator currentTopOp = filter;
@@ -327,8 +332,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
 
                 // Assigns the record constructor function to a record variable.
                 LogicalVariable recordVar = context.newVar();
-                AssignOperator assignOp = new AssignOperator(recordVar,
-                        new MutableObject<ILogicalExpression>(recordCreationFunc));
+                AssignOperator assignOp =
+                        new AssignOperator(recordVar, new MutableObject<ILogicalExpression>(recordCreationFunc));
                 assignOp.getInputs().add(new MutableObject<ILogicalOperator>(currentTopOp));
 
                 // Sets currentTopOp and varToListify for later usages.
@@ -357,8 +362,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
 
             // Outer unnest the aggregated var from the subplan.
             LogicalVariable outerUnnestVar = context.newVar();
-            LeftOuterUnnestOperator outerUnnestOp = new LeftOuterUnnestOperator(outerUnnestVar,
-                    new MutableObject<ILogicalExpression>(
+            LeftOuterUnnestOperator outerUnnestOp =
+                    new LeftOuterUnnestOperator(outerUnnestVar, new MutableObject<ILogicalExpression>(
                             makeUnnestExpression(new VariableReferenceExpression(aggVar))));
             outerUnnestOp.getInputs().add(new MutableObject<ILogicalOperator>(subplanOp));
             currentTopOp = outerUnnestOp;
@@ -423,8 +428,8 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
     @Override
     public Pair<ILogicalOperator, LogicalVariable> visit(HavingClause havingClause, Mutable<ILogicalOperator> tupSource)
             throws AsterixException {
-        Pair<ILogicalExpression, Mutable<ILogicalOperator>> p = langExprToAlgExpression(
-                havingClause.getFilterExpression(), tupSource);
+        Pair<ILogicalExpression, Mutable<ILogicalOperator>> p =
+                langExprToAlgExpression(havingClause.getFilterExpression(), tupSource);
         SelectOperator s = new SelectOperator(new MutableObject<ILogicalExpression>(p.first), false, null);
         s.getInputs().add(p.second);
         return new Pair<>(s, null);
@@ -477,6 +482,86 @@ class SqlppExpressionToPlanTranslator extends LangExpressionToPlanTranslator imp
         throw new UnsupportedOperationException(ERR_MSG);
     }
 
+    @Override
+    public Pair<ILogicalOperator, LogicalVariable> visit(CaseExpression caseExpression,
+            Mutable<ILogicalOperator> tupSource) throws AsterixException {
+        //Creates a series of subplan operators, one for each branch.
+        Mutable<ILogicalOperator> currentOpRef = tupSource;
+        ILogicalOperator currentOperator = null;
+        List<Expression> whenExprList = caseExpression.getWhenExprs();
+        List<Expression> thenExprList = caseExpression.getThenExprs();
+        List<ILogicalExpression> branchCondVarReferences = new ArrayList<>();
+        List<ILogicalExpression> allVarReferences = new ArrayList<>();
+        for (int index = 0; index < whenExprList.size(); ++index) {
+            Pair<ILogicalOperator, LogicalVariable> whenExprResult = whenExprList.get(index).accept(this, currentOpRef);
+            currentOperator = whenExprResult.first;
+            // Variable whenConditionVar is corresponds to the current "WHEN" condition.
+            LogicalVariable whenConditionVar = whenExprResult.second;
+            Mutable<ILogicalExpression> branchEntraceConditionExprRef =
+                    new MutableObject<>(new VariableReferenceExpression(whenConditionVar));
+
+            // Constructs an expression that filters data based on preceding "WHEN" conditions
+            // and the current "WHEN" condition. Note that only one "THEN" expression can be run
+            // even though multiple "WHEN" conditions can be satisfied.
+            if (!branchCondVarReferences.isEmpty()) {
+                // The additional filter generated here makes sure the the tuple has not
+                // entered other matched "WHEN...THEN" case.
+                List<Mutable<ILogicalExpression>> andArgs = new ArrayList<>();
+                andArgs.add(generateNoMatchedPrecedingWhenBranchesFilter(branchCondVarReferences));
+                andArgs.add(branchEntraceConditionExprRef);
+
+                // A "THEN" branch can be entered only when the tuple has not enter any other preceding
+                // branches and the current "WHEN" condition is TRUE.
+                branchEntraceConditionExprRef = new MutableObject<>(new ScalarFunctionCallExpression(
+                        FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.AND), andArgs));
+            }
+
+            // Translates the corresponding "THEN" expression.
+            Pair<ILogicalOperator, LogicalVariable> opAndVarForThen = constructSubplanOperatorForBranch(currentOperator,
+                    branchEntraceConditionExprRef, thenExprList.get(index));
+
+            branchCondVarReferences.add(new VariableReferenceExpression(whenConditionVar));
+            allVarReferences.add(new VariableReferenceExpression(whenConditionVar));
+            allVarReferences.add(new VariableReferenceExpression(opAndVarForThen.second));
+            currentOperator = opAndVarForThen.first;
+            currentOpRef = new MutableObject<>(currentOperator);
+        }
+
+        // Creates a subplan for the "ELSE" branch.
+        Mutable<ILogicalExpression> elseCondExprRef =
+                generateNoMatchedPrecedingWhenBranchesFilter(branchCondVarReferences);
+        Pair<ILogicalOperator, LogicalVariable> opAndVarForElse =
+                constructSubplanOperatorForBranch(currentOperator, elseCondExprRef, caseExpression.getElseExpr());
+
+        // Uses switch-case function to select the results of two branches.
+        LogicalVariable selectVar = context.newVar();
+        List<Mutable<ILogicalExpression>> arguments = new ArrayList<>();
+        arguments.add(new MutableObject<>(new ConstantExpression(new AsterixConstantValue(ABoolean.TRUE))));
+        for (ILogicalExpression argVar : allVarReferences) {
+            arguments.add(new MutableObject<>(argVar));
+        }
+        arguments.add(new MutableObject<>(new VariableReferenceExpression(opAndVarForElse.second)));
+        AbstractFunctionCallExpression swithCaseExpr = new ScalarFunctionCallExpression(
+                FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.SWITCH_CASE), arguments);
+        AssignOperator assignOp = new AssignOperator(selectVar, new MutableObject<>(swithCaseExpr));
+        assignOp.getInputs().add(new MutableObject<>(opAndVarForElse.first));
+
+        // Unnests the selected (a "THEN" or "ELSE" branch) result.
+        LogicalVariable unnestVar = context.newVar();
+        UnnestOperator unnestOp = new UnnestOperator(unnestVar,
+                new MutableObject<>(new UnnestingFunctionCallExpression(
+                        FunctionUtil.getFunctionInfo(AsterixBuiltinFunctions.SCAN_COLLECTION), Collections
+                                .singletonList(new MutableObject<>(new VariableReferenceExpression(selectVar))))));
+        unnestOp.getInputs().add(new MutableObject<>(assignOp));
+
+        // Produces the final assign operator.
+        LogicalVariable resultVar = context.newVar();
+        AssignOperator finalAssignOp =
+                new AssignOperator(resultVar, new MutableObject<>(new VariableReferenceExpression(unnestVar)));
+        finalAssignOp.getInputs().add(new MutableObject<>(unnestOp));
+        return new Pair<>(finalAssignOp, resultVar);
+    }
+
     private Pair<ILogicalOperator, LogicalVariable> produceSelectPlan(boolean isSubquery,
             Mutable<ILogicalOperator> returnOpRef, LogicalVariable resVar) {
         if (isSubquery) {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
index 24ddaf6..2c0aef4 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/FunctionCollection.java
@@ -131,8 +131,7 @@ import org.apache.asterix.runtime.evaluators.constructors.ClosedRecordConstructo
 import org.apache.asterix.runtime.evaluators.constructors.OpenRecordConstructorDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.AndDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.AnyCollectionMemberDescriptor;
-import org.apache.asterix.runtime.evaluators.functions.CastListDescriptor;
-import org.apache.asterix.runtime.evaluators.functions.CastRecordDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.CastTypeDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.CheckUnknownDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.CodePointToStringDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.CountHashedGramTokensDescriptor;
@@ -374,10 +373,8 @@ public class FunctionCollection {
         temp.add(OrderedListConstructorDescriptor.FACTORY);
         temp.add(UnorderedListConstructorDescriptor.FACTORY);
 
-        // Cast functions
+        // Inject failure function
         temp.add(InjectFailureDescriptor.FACTORY);
-        temp.add(CastListDescriptor.FACTORY);
-        temp.add(CastRecordDescriptor.FACTORY);
 
         // Switch case
         temp.add(SwitchCaseDescriptor.FACTORY);
@@ -612,6 +609,9 @@ public class FunctionCollection {
         functionsToInjectUnkownHandling.add(GetOverlappingIntervalDescriptor.FACTORY);
         functionsToInjectUnkownHandling.add(DurationFromIntervalDescriptor.FACTORY);
 
+        // Cast function
+        functionsToInjectUnkownHandling.add(CastTypeDescriptor.FACTORY);
+
         List<IFunctionDescriptorFactory> generatedFactories = new ArrayList<>();
         for (IFunctionDescriptorFactory factory : functionsToInjectUnkownHandling) {
             generatedFactories

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryBTreeOperationsHelper.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryBTreeOperationsHelper.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryBTreeOperationsHelper.java
index 15ea2f8..9e2e0b0 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryBTreeOperationsHelper.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryBTreeOperationsHelper.java
@@ -95,8 +95,8 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
                     secondaryComparatorFactories, secondaryBloomFilterKeyFields, false, dataset.getDatasetId(),
                     mergePolicyFactory, mergePolicyFactoryProperties, filterTypeTraits, filterCmpFactories,
                     secondaryBTreeFields, secondaryFilterFields);
-            localResourceFactoryProvider = new PersistentLocalResourceFactoryProvider(localResourceMetadata,
-                    LocalResource.LSMBTreeResource);
+            localResourceFactoryProvider =
+                    new PersistentLocalResourceFactoryProvider(localResourceMetadata, LocalResource.LSMBTreeResource);
             indexDataflowHelperFactory = new LSMBTreeDataflowHelperFactory(
                     new AsterixVirtualBufferCacheProvider(dataset.getDatasetId()), mergePolicyFactory,
                     mergePolicyFactoryProperties, new SecondaryIndexOperationTrackerProvider(dataset.getDatasetId()),
@@ -146,12 +146,12 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
 
             // Assign op.
             AbstractOperatorDescriptor sourceOp = primaryScanOp;
-            if (isEnforcingKeyTypes) {
+            if (isEnforcingKeyTypes && !enforcedItemType.equals(itemType)) {
                 sourceOp = createCastOp(spec, dataset.getDatasetType());
                 spec.connect(new OneToOneConnectorDescriptor(spec), primaryScanOp, 0, sourceOp, 0);
             }
-            AlgebricksMetaOperatorDescriptor asterixAssignOp = createExternalAssignOp(spec, numSecondaryKeys,
-                    secondaryRecDesc);
+            AlgebricksMetaOperatorDescriptor asterixAssignOp =
+                    createExternalAssignOp(spec, numSecondaryKeys, secondaryRecDesc);
 
             // If any of the secondary fields are nullable, then add a select op that filters nulls.
             AlgebricksMetaOperatorDescriptor selectOp = null;
@@ -165,13 +165,13 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
             AsterixStorageProperties storageProperties = propertiesProvider.getStorageProperties();
             // Create secondary BTree bulk load op.
             AbstractTreeIndexOperatorDescriptor secondaryBulkLoadOp;
-            ExternalBTreeWithBuddyDataflowHelperFactory dataflowHelperFactory = new ExternalBTreeWithBuddyDataflowHelperFactory(
-                    mergePolicyFactory, mergePolicyFactoryProperties,
-                    new SecondaryIndexOperationTrackerProvider(dataset.getDatasetId()),
-                    AsterixRuntimeComponentsProvider.RUNTIME_PROVIDER,
-                    LSMBTreeWithBuddyIOOperationCallbackFactory.INSTANCE,
-                    storageProperties.getBloomFilterFalsePositiveRate(), new int[] { numSecondaryKeys },
-                    ExternalDatasetsRegistry.INSTANCE.getDatasetVersion(dataset), true);
+            ExternalBTreeWithBuddyDataflowHelperFactory dataflowHelperFactory =
+                    new ExternalBTreeWithBuddyDataflowHelperFactory(mergePolicyFactory, mergePolicyFactoryProperties,
+                            new SecondaryIndexOperationTrackerProvider(dataset.getDatasetId()),
+                            AsterixRuntimeComponentsProvider.RUNTIME_PROVIDER,
+                            LSMBTreeWithBuddyIOOperationCallbackFactory.INSTANCE,
+                            storageProperties.getBloomFilterFalsePositiveRate(), new int[] { numSecondaryKeys },
+                            ExternalDatasetsRegistry.INSTANCE.getDatasetVersion(dataset), true);
             IOperatorDescriptor root;
             if (externalFiles != null) {
                 // Transaction load
@@ -208,12 +208,12 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
 
             // Assign op.
             AbstractOperatorDescriptor sourceOp = primaryScanOp;
-            if (isEnforcingKeyTypes) {
+            if (isEnforcingKeyTypes && !enforcedItemType.equals(itemType)) {
                 sourceOp = createCastOp(spec, dataset.getDatasetType());
                 spec.connect(new OneToOneConnectorDescriptor(spec), primaryScanOp, 0, sourceOp, 0);
             }
-            AlgebricksMetaOperatorDescriptor asterixAssignOp = createAssignOp(spec, sourceOp, numSecondaryKeys,
-                    secondaryRecDesc);
+            AlgebricksMetaOperatorDescriptor asterixAssignOp =
+                    createAssignOp(spec, sourceOp, numSecondaryKeys, secondaryRecDesc);
 
             // If any of the secondary fields are nullable, then add a select op that filters nulls.
             AlgebricksMetaOperatorDescriptor selectOp = null;
@@ -311,17 +311,17 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
         secondaryFieldAccessEvalFactories = new IScalarEvaluatorFactory[numSecondaryKeys + numFilterFields];
         secondaryComparatorFactories = new IBinaryComparatorFactory[numSecondaryKeys + numPrimaryKeys];
         secondaryBloomFilterKeyFields = new int[numSecondaryKeys];
-        ISerializerDeserializer[] secondaryRecFields = new ISerializerDeserializer[numPrimaryKeys + numSecondaryKeys
-                + numFilterFields];
-        ISerializerDeserializer[] enforcedRecFields = new ISerializerDeserializer[1 + numPrimaryKeys
-                + (dataset.hasMetaPart() ? 1 : 0) + numFilterFields];
-        ITypeTraits[] enforcedTypeTraits = new ITypeTraits[1 + numPrimaryKeys + (dataset.hasMetaPart() ? 1 : 0)
-                + numFilterFields];
+        ISerializerDeserializer[] secondaryRecFields =
+                new ISerializerDeserializer[numPrimaryKeys + numSecondaryKeys + numFilterFields];
+        ISerializerDeserializer[] enforcedRecFields =
+                new ISerializerDeserializer[1 + numPrimaryKeys + (dataset.hasMetaPart() ? 1 : 0) + numFilterFields];
+        ITypeTraits[] enforcedTypeTraits =
+                new ITypeTraits[1 + numPrimaryKeys + (dataset.hasMetaPart() ? 1 : 0) + numFilterFields];
         secondaryTypeTraits = new ITypeTraits[numSecondaryKeys + numPrimaryKeys];
         ISerializerDeserializerProvider serdeProvider = metadataProvider.getFormat().getSerdeProvider();
         ITypeTraitProvider typeTraitProvider = metadataProvider.getFormat().getTypeTraitProvider();
-        IBinaryComparatorFactoryProvider comparatorFactoryProvider = metadataProvider.getFormat()
-                .getBinaryComparatorFactoryProvider();
+        IBinaryComparatorFactoryProvider comparatorFactoryProvider =
+                metadataProvider.getFormat().getBinaryComparatorFactoryProvider();
         // Record column is 0 for external datasets, numPrimaryKeys for internal ones
         int recordColumn = dataset.getDatasetType() == DatasetType.INTERNAL ? numPrimaryKeys : 0;
         for (int i = 0; i < numSecondaryKeys; i++) {
@@ -336,8 +336,8 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
             }
             secondaryFieldAccessEvalFactories[i] = metadataProvider.getFormat().getFieldAccessEvaluatorFactory(
                     isEnforcingKeyTypes ? enforcedItemType : sourceType, secondaryKeyFields.get(i), sourceColumn);
-            Pair<IAType, Boolean> keyTypePair = Index.getNonNullableOpenFieldType(secondaryKeyTypes.get(i),
-                    secondaryKeyFields.get(i), sourceType);
+            Pair<IAType, Boolean> keyTypePair =
+                    Index.getNonNullableOpenFieldType(secondaryKeyTypes.get(i), secondaryKeyFields.get(i), sourceType);
             IAType keyType = keyTypePair.first;
             anySecondaryKeyIsNullable = anySecondaryKeyIsNullable || keyTypePair.second;
             ISerializerDeserializer keySerde = serdeProvider.getSerializerDeserializer(keyType);
@@ -380,8 +380,8 @@ public class SecondaryBTreeOperationsHelper extends SecondaryIndexOperationsHelp
             ISerializerDeserializer serde = serdeProvider.getSerializerDeserializer(type);
             secondaryRecFields[numPrimaryKeys + numSecondaryKeys] = serde;
             enforcedRecFields[numPrimaryKeys + 1 + (dataset.hasMetaPart() ? 1 : 0)] = serde;
-            enforcedTypeTraits[numPrimaryKeys + 1 + (dataset.hasMetaPart() ? 1 : 0)] = typeTraitProvider
-                    .getTypeTrait(type);
+            enforcedTypeTraits[numPrimaryKeys + 1 + (dataset.hasMetaPart() ? 1 : 0)] =
+                    typeTraitProvider.getTypeTrait(type);
         }
         secondaryRecDesc = new RecordDescriptor(secondaryRecFields, secondaryTypeTraits);
         enforcedRecDesc = new RecordDescriptor(enforcedRecFields, enforcedTypeTraits);

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/c8c067c5/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryIndexOperationsHelper.java
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryIndexOperationsHelper.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryIndexOperationsHelper.java
index e677f54..8ebe246 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryIndexOperationsHelper.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/file/SecondaryIndexOperationsHelper.java
@@ -53,7 +53,7 @@ import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.util.AsterixAppContextInfo;
 import org.apache.asterix.runtime.evaluators.functions.AndDescriptor;
-import org.apache.asterix.runtime.evaluators.functions.CastRecordDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.CastTypeDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.IsUnknownDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.NotDescriptor;
 import org.apache.asterix.runtime.job.listener.JobEventListenerFactory;
@@ -173,8 +173,8 @@ public abstract class SecondaryIndexOperationsHelper {
             case SINGLE_PARTITION_NGRAM_INVIX:
             case LENGTH_PARTITIONED_WORD_INVIX:
             case LENGTH_PARTITIONED_NGRAM_INVIX: {
-                indexOperationsHelper = new SecondaryInvertedIndexOperationsHelper(physOptConf,
-                        asterixPropertiesProvider);
+                indexOperationsHelper =
+                        new SecondaryInvertedIndexOperationsHelper(physOptConf, asterixPropertiesProvider);
                 break;
             }
             default: {
@@ -240,8 +240,8 @@ public abstract class SecondaryIndexOperationsHelper {
         setSecondaryRecDescAndComparators(indexType, secondaryKeyFields, secondaryKeyTypes, gramLength,
                 metadataProvider);
         numElementsHint = metadataProvider.getCardinalityPerPartitionHint(dataset);
-        Pair<ILSMMergePolicyFactory, Map<String, String>> compactionInfo = DatasetUtils.getMergePolicyFactory(dataset,
-                metadataProvider.getMetadataTxnContext());
+        Pair<ILSMMergePolicyFactory, Map<String, String>> compactionInfo =
+                DatasetUtils.getMergePolicyFactory(dataset, metadataProvider.getMetadataTxnContext());
         mergePolicyFactory = compactionInfo.first;
         mergePolicyFactoryProperties = compactionInfo.second;
 
@@ -276,8 +276,8 @@ public abstract class SecondaryIndexOperationsHelper {
     protected void setPrimaryRecDescAndComparators() throws AlgebricksException {
         List<List<String>> partitioningKeys = DatasetUtils.getPartitioningKeys(dataset);
         int numPrimaryKeys = partitioningKeys.size();
-        ISerializerDeserializer[] primaryRecFields = new ISerializerDeserializer[numPrimaryKeys + 1
-                + (dataset.hasMetaPart() ? 1 : 0)];
+        ISerializerDeserializer[] primaryRecFields =
+                new ISerializerDeserializer[numPrimaryKeys + 1 + (dataset.hasMetaPart() ? 1 : 0)];
         ITypeTraits[] primaryTypeTraits = new ITypeTraits[numPrimaryKeys + 1 + (dataset.hasMetaPart() ? 1 : 0)];
         primaryComparatorFactories = new IBinaryComparatorFactory[numPrimaryKeys];
         primaryBloomFilterKeyFields = new int[numPrimaryKeys];
@@ -287,12 +287,12 @@ public abstract class SecondaryIndexOperationsHelper {
             indicators = ((InternalDatasetDetails) dataset.getDatasetDetails()).getKeySourceIndicator();
         }
         for (int i = 0; i < numPrimaryKeys; i++) {
-            IAType keyType = (indicators == null || indicators.get(i) == 0)
-                    ? itemType.getSubFieldType(partitioningKeys.get(i))
-                    : metaType.getSubFieldType(partitioningKeys.get(i));
+            IAType keyType =
+                    (indicators == null || indicators.get(i) == 0) ? itemType.getSubFieldType(partitioningKeys.get(i))
+                            : metaType.getSubFieldType(partitioningKeys.get(i));
             primaryRecFields[i] = serdeProvider.getSerializerDeserializer(keyType);
-            primaryComparatorFactories[i] = AqlBinaryComparatorFactoryProvider.INSTANCE
-                    .getBinaryComparatorFactory(keyType, true);
+            primaryComparatorFactories[i] =
+                    AqlBinaryComparatorFactoryProvider.INSTANCE.getBinaryComparatorFactory(keyType, true);
             primaryTypeTraits[i] = AqlTypeTraitProvider.INSTANCE.getTypeTrait(keyType);
             primaryBloomFilterKeyFields[i] = i;
         }
@@ -398,8 +398,7 @@ public abstract class SecondaryIndexOperationsHelper {
     }
 
     protected AlgebricksMetaOperatorDescriptor createCastOp(JobSpecification spec, DatasetType dsType) {
-        CastRecordDescriptor castFuncDesc = (CastRecordDescriptor) CastRecordDescriptor.FACTORY
-                .createFunctionDescriptor();
+        CastTypeDescriptor castFuncDesc = (CastTypeDescriptor) CastTypeDescriptor.FACTORY.createFunctionDescriptor();
         castFuncDesc.reset(enforcedItemType, itemType);
 
         int[] outColumns = new int[1];
@@ -419,8 +418,8 @@ public abstract class SecondaryIndexOperationsHelper {
         if (dataset.hasMetaPart()) {
             projectionList[numPrimaryKeys + 1] = numPrimaryKeys + 1;
         }
-        IScalarEvaluatorFactory[] castEvalFact = new IScalarEvaluatorFactory[] {
-                new ColumnAccessEvalFactory(recordIdx) };
+        IScalarEvaluatorFactory[] castEvalFact =
+                new IScalarEvaluatorFactory[] { new ColumnAccessEvalFactory(recordIdx) };
         IScalarEvaluatorFactory[] sefs = new IScalarEvaluatorFactory[1];
         sefs[0] = castFuncDesc.createEvaluatorFactory(castEvalFact);
         AssignRuntimeFactory castAssign = new AssignRuntimeFactory(outColumns, sefs, projectionList);
@@ -463,10 +462,10 @@ public abstract class SecondaryIndexOperationsHelper {
         for (int i = 0; i < numSecondaryKeyFields; i++) {
             // Access column i, and apply 'is not null'.
             ColumnAccessEvalFactory columnAccessEvalFactory = new ColumnAccessEvalFactory(i);
-            IScalarEvaluatorFactory isUnknownEvalFactory = isUnknownDesc
-                    .createEvaluatorFactory(new IScalarEvaluatorFactory[] { columnAccessEvalFactory });
-            IScalarEvaluatorFactory notEvalFactory = notDesc
-                    .createEvaluatorFactory(new IScalarEvaluatorFactory[] { isUnknownEvalFactory });
+            IScalarEvaluatorFactory isUnknownEvalFactory =
+                    isUnknownDesc.createEvaluatorFactory(new IScalarEvaluatorFactory[] { columnAccessEvalFactory });
+            IScalarEvaluatorFactory notEvalFactory =
+                    notDesc.createEvaluatorFactory(new IScalarEvaluatorFactory[] { isUnknownEvalFactory });
             andArgsEvalFactories[i] = notEvalFactory;
         }
         IScalarEvaluatorFactory selectCond = null;