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

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


The following commit(s) were added to refs/heads/master by this push:
     new fbdb710  [NO ISSUE][COMP] Make views utilize secondary indexes
fbdb710 is described below

commit fbdb710654bf09ad4db564dea78c2e71d68ac556
Author: Ali Alsuliman <[email protected]>
AuthorDate: Mon Nov 15 19:34:10 2021 -0800

    [NO ISSUE][COMP] Make views utilize secondary indexes
    
    - user model changes: no
    - storage format changes: no
    - interface changes: yes
    
    Details:
    - For B-Tree access method, when analyzing the arguments of an optimizable
      function like LT (e.g $var < 8), allow function call expressions in
      addition to variable expressions.
    - For B-Tree access method, accept only the default-null constructors as
      function call expressions.
    - keep track of all the function calls that the logical variable $var is 
going
      through.
    - set the position of the $var (or function call) in the optimizable 
function
      correctly.
    - don't consider an index as a candidate when it does not match the access 
method.
    
    Change-Id: I7ae50a7ccad9dc4dd2df221c4c643a4af04367b9
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/14043
    Integration-Tests: Jenkins <[email protected]>
    Tested-by: Jenkins <[email protected]>
    Reviewed-by: Ali Alsuliman <[email protected]>
    Reviewed-by: Dmitry Lychagin <[email protected]>
---
 .../am/AbstractIntroduceAccessMethodRule.java      |  99 +++++++-----
 .../optimizer/rules/am/AccessMethodUtils.java      | 174 +++++++++++++++++----
 .../optimizer/rules/am/ArrayBTreeAccessMethod.java |  13 ++
 .../optimizer/rules/am/BTreeAccessMethod.java      |  30 +++-
 .../asterix/optimizer/rules/am/IAccessMethod.java  |  13 ++
 .../optimizer/rules/am/IOptimizableFuncExpr.java   |  14 ++
 .../rules/am/IntroduceLSMComponentFilterRule.java  |   2 +-
 .../rules/am/InvertedIndexAccessMethod.java        |  28 +++-
 .../optimizer/rules/am/OptimizableFuncExpr.java    |  40 ++++-
 .../optimizer/rules/am/RTreeAccessMethod.java      |  13 +-
 .../cast-default-null/cast-default-null-01.sqlpp   |  29 ++++
 .../cast-default-null/cast-default-null-02.sqlpp   |  29 ++++
 .../cast-default-null/cast-default-null-03.sqlpp   |  29 ++++
 .../cast-default-null/cast-default-null-04.sqlpp   |  29 ++++
 .../cast-default-null/cast-default-null-05.sqlpp   |  37 +++++
 .../cast-default-null/cast-default-null-06.sqlpp   |  36 +++++
 .../cast-default-null/cast-default-null-07.sqlpp   |  36 +++++
 .../cast-default-null/cast-default-null-08.sqlpp   |  36 +++++
 .../cast-default-null/cast-default-null-09.sqlpp   |  35 +++++
 .../function-on-pk/function-on-pk-01.sqlpp         |  27 ++++
 .../function-on-pk/function-on-pk-02.sqlpp         |  27 ++++
 .../cast-default-null/cast-default-null-01.plan    |  16 ++
 .../cast-default-null/cast-default-null-02.plan    |  23 +++
 .../cast-default-null/cast-default-null-03.plan    |  16 ++
 .../cast-default-null/cast-default-null-04.plan    |  12 ++
 .../cast-default-null/cast-default-null-05.plan    |  27 ++++
 .../cast-default-null/cast-default-null-06.plan    |  24 +++
 .../cast-default-null/cast-default-null-07.plan    |  24 +++
 .../cast-default-null/cast-default-null-08.plan    |  24 +++
 .../cast-default-null/cast-default-null-09.plan    |  24 +++
 .../function-on-pk/function-on-pk-01.plan          |  10 ++
 .../function-on-pk/function-on-pk-02.plan          |  10 ++
 .../cast-default-null.01.ddl.sqlpp                 |  38 +++++
 .../cast-default-null.02.update.sqlpp              |  65 ++++++++
 .../cast-default-null.03.query.sqlpp               |  22 +++
 .../cast-default-null.04.query.sqlpp               |  22 +++
 .../cast-default-null.05.query.sqlpp               |  22 +++
 .../cast-default-null.06.query.sqlpp               |  22 +++
 .../cast-default-null.07.query.sqlpp               |  24 +++
 .../cast-default-null.08.query.sqlpp               |  24 +++
 .../cast-default-null.09.query.sqlpp               |  24 +++
 .../cast-default-null.10.query.sqlpp               |  24 +++
 .../cast-default-null.11.query.sqlpp               |  24 +++
 .../cast-default-null/cast-default-null.03.adm     |   2 +
 .../cast-default-null/cast-default-null.04.adm     |   2 +
 .../cast-default-null/cast-default-null.05.adm     |   1 +
 .../cast-default-null/cast-default-null.06.adm     |   1 +
 .../cast-default-null/cast-default-null.07.adm     |   8 +
 .../cast-default-null/cast-default-null.08.adm     |   0
 .../cast-default-null/cast-default-null.09.adm     |   8 +
 .../cast-default-null/cast-default-null.10.adm     |   8 +
 .../cast-default-null/cast-default-null.11.adm     |   4 +
 .../test/resources/runtimets/testsuite_sqlpp.xml   |   5 +
 53 files changed, 1250 insertions(+), 86 deletions(-)

diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
index 25e8813..409e2bd 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
@@ -61,7 +61,6 @@ 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.IVariableTypeEnvironment;
-import 
org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
 import 
org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import 
org.apache.hyracks.algebricks.core.algebra.operators.logical.AbstractLogicalOperator;
@@ -144,7 +143,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                 if (isJoinLeftBranch) {
                     fillVarFieldTypeForOptFuncExprs(subTree, amCtx, context);
                 }
-                fillAllIndexExprs(subTree, amCtx, context);
+                fillAllIndexExprs(subTree, amCtx, context, entry.getKey());
             }
         }
     }
@@ -665,15 +664,19 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
      */
     protected boolean fillIndexExprs(List<Index> datasetIndexes, List<String> 
fieldName, IAType fieldType,
             IOptimizableFuncExpr optFuncExpr, int matchedFuncExprIndex, int 
varIdx,
-            OptimizableOperatorSubTree matchedSubTree, 
AccessMethodAnalysisContext analysisCtx, int fieldSource)
-            throws AlgebricksException {
+            OptimizableOperatorSubTree matchedSubTree, 
AccessMethodAnalysisContext analysisCtx, int fieldSource,
+            IAccessMethod accessMethod) throws AlgebricksException {
         List<Index> indexCandidates = new ArrayList<>();
         // Add an index to the candidates if one of the indexed fields is 
fieldName
         for (Index index : datasetIndexes) {
+            if (!accessMethod.matchIndexType(index.getIndexType())) {
+                continue;
+            }
             List<List<String>> keyFieldNames;
             List<IAType> keyFieldTypes;
             List<Integer> keySources;
             boolean isOverridingKeyFieldTypes;
+            boolean hasCastDefaultNull = false;
             switch (Index.IndexCategory.of(index.getIndexType())) {
                 case ARRAY:
                     Index.ArrayIndexDetails arrayIndexDetails = 
(Index.ArrayIndexDetails) index.getIndexDetails();
@@ -696,6 +699,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                     keyFieldTypes = valueIndexDetails.getKeyFieldTypes();
                     keySources = 
valueIndexDetails.getKeyFieldSourceIndicators();
                     isOverridingKeyFieldTypes = 
valueIndexDetails.isOverridingKeyFieldTypes();
+                    hasCastDefaultNull = 
valueIndexDetails.getCastDefaultNull().getOrElse(false);
                     break;
                 case TEXT:
                     Index.TextIndexDetails textIndexDetails = 
(Index.TextIndexDetails) index.getIndexDetails();
@@ -712,13 +716,16 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
             int keyIdx = keyFieldNames.indexOf(fieldName);
             if (keyIdx >= 0 && keySourceMatches(keySources, keyIdx, 
fieldSource)
                     && index.getPendingOp() == MetadataUtil.PENDING_NO_OP) {
-                indexCandidates.add(index);
-                boolean isFieldTypeUnknown = fieldType == BuiltinType.AMISSING 
|| fieldType == BuiltinType.ANY;
-                if (isFieldTypeUnknown && (!isOverridingKeyFieldTypes || 
index.isEnforced())) {
-                    IAType indexedType = keyFieldTypes.get(keyIdx);
-                    optFuncExpr.setFieldType(varIdx, indexedType);
+                IAType indexedType = keyFieldTypes.get(keyIdx);
+                List<AbstractFunctionCallExpression> stepExprs = 
optFuncExpr.getStepsExprs(varIdx);
+                if (acceptSteps(accessMethod, stepExprs, indexedType, 
hasCastDefaultNull)) {
+                    indexCandidates.add(index);
+                    boolean isFieldTypeUnknown = fieldType == 
BuiltinType.AMISSING || fieldType == BuiltinType.ANY;
+                    if (isFieldTypeUnknown && (!isOverridingKeyFieldTypes || 
index.isEnforced())) {
+                        optFuncExpr.setFieldType(varIdx, indexedType);
+                    }
+                    analysisCtx.addIndexExpr(matchedSubTree.getDataset(), 
index, matchedFuncExprIndex, varIdx);
                 }
-                analysisCtx.addIndexExpr(matchedSubTree.getDataset(), index, 
matchedFuncExprIndex, varIdx);
             }
         }
         // No index candidates for fieldName.
@@ -728,13 +735,23 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
         return true;
     }
 
+    private boolean acceptSteps(IAccessMethod accessMethod, 
List<AbstractFunctionCallExpression> stepExprs,
+            IAType indexedType, boolean indexHasCastDefaultNull) throws 
AlgebricksException {
+        for (int i = stepExprs.size() - 1; i >= 0; i--) {
+            if (!accessMethod.acceptsFunction(stepExprs.get(i), indexedType, 
indexHasCastDefaultNull, i == 0)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private static boolean keySourceMatches(List<Integer> keySources, int 
keyIdx, int fieldSource) {
         // TODO(ali): keySources from Index should not be null. should 
investigate if it can happen (ie on external ds)
         return keySources == null ? fieldSource == 0 : keySources.get(keyIdx) 
== fieldSource;
     }
 
     protected void fillAllIndexExprs(OptimizableOperatorSubTree subTree, 
AccessMethodAnalysisContext analysisCtx,
-            IOptimizationContext context) throws AlgebricksException {
+            IOptimizationContext context, IAccessMethod accessMethod) throws 
AlgebricksException {
         int optFuncExprIndex = 0;
         List<Index> datasetIndexes = new ArrayList<>();
         LogicalVariable datasetMetaVar = null;
@@ -754,10 +771,10 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                 AbstractLogicalOperator op = 
subTree.getAssignsAndUnnests().get(assignOrUnnestIndex);
                 if (op.getOperatorTag() == LogicalOperatorTag.ASSIGN) {
                     analyzeAssignOp((AssignOperator) op, optFuncExpr, subTree, 
assignOrUnnestIndex, datasetMetaVar,
-                            context, datasetIndexes, optFuncExprIndex, 
analysisCtx);
+                            context, datasetIndexes, optFuncExprIndex, 
analysisCtx, accessMethod);
                 } else {
                     analyzeUnnestOp((UnnestOperator) op, optFuncExpr, subTree, 
assignOrUnnestIndex, datasetMetaVar,
-                            context, datasetIndexes, optFuncExprIndex, 
analysisCtx);
+                            context, datasetIndexes, optFuncExprIndex, 
analysisCtx, accessMethod);
                 }
             }
 
@@ -766,7 +783,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
             List<LogicalVariable> dsVarList = subTree.getDataSourceVariables();
 
             matchVarsFromOptFuncExprToDataSourceScan(optFuncExpr, 
optFuncExprIndex, datasetIndexes, dsVarList, subTree,
-                    analysisCtx, context, false);
+                    analysisCtx, context, false, accessMethod);
 
             // If there is one more datasource in the subtree, we need to scan 
that datasource, too.
             List<LogicalVariable> additionalDsVarList = null;
@@ -778,7 +795,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                 }
 
                 matchVarsFromOptFuncExprToDataSourceScan(optFuncExpr, 
optFuncExprIndex, datasetIndexes,
-                        additionalDsVarList, subTree, analysisCtx, context, 
true);
+                        additionalDsVarList, subTree, analysisCtx, context, 
true, accessMethod);
 
             }
 
@@ -789,7 +806,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
     private void analyzeUnnestOp(UnnestOperator unnestOp, IOptimizableFuncExpr 
optFuncExpr,
             OptimizableOperatorSubTree subTree, int assignOrUnnestIndex, 
LogicalVariable datasetMetaVar,
             IOptimizationContext context, List<Index> datasetIndexes, int 
optFuncExprIndex,
-            AccessMethodAnalysisContext analysisCtx) throws 
AlgebricksException {
+            AccessMethodAnalysisContext analysisCtx, IAccessMethod 
accessMethod) throws AlgebricksException {
         LogicalVariable var = unnestOp.getVariable();
         int funcVarIndex = optFuncExpr.findLogicalVar(var);
         // No matching var in optFuncExpr.
@@ -803,17 +820,18 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
         List<String> fieldName = null;
         MutableInt fieldSource = new MutableInt(0);
         if (subTree.getDataSourceType() == DataSourceType.COLLECTION_SCAN) {
-            VariableReferenceExpression varRef = new 
VariableReferenceExpression(var);
-            varRef.setSourceLocation(unnestOp.getSourceLocation());
-            optFuncExpr.setLogicalExpr(funcVarIndex, varRef);
+            ILogicalExpression expr = 
optFuncExpr.getArgument(funcVarIndex).getValue();
+            if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) 
{
+                optFuncExpr.addStepExpr(funcVarIndex, 
((AbstractFunctionCallExpression) expr));
+            }
+            optFuncExpr.setLogicalExpr(funcVarIndex, expr);
         } else {
             if (subTree.getDataSourceType() == DataSourceType.DATASOURCE_SCAN) 
{
                 subTree.setLastMatchedDataSourceVars(0, funcVarIndex);
             }
-            fieldName = AccessMethodUtils.getFieldNameFromSubTree(optFuncExpr, 
subTree, assignOrUnnestIndex, 0,
-                    subTree.getRecordType(), funcVarIndex,
-                    
optFuncExpr.getFuncExpr().getArguments().get(funcVarIndex).getValue(), 
subTree.getMetaRecordType(),
-                    datasetMetaVar, fieldSource, false);
+            fieldName = 
AccessMethodUtils.getFieldNameSetStepsFromSubTree(optFuncExpr, subTree, 
assignOrUnnestIndex, 0,
+                    subTree.getRecordType(), funcVarIndex, 
optFuncExpr.getArgument(funcVarIndex).getValue(),
+                    subTree.getMetaRecordType(), datasetMetaVar, fieldSource, 
false);
             if (fieldName.isEmpty()) {
                 return;
             }
@@ -828,14 +846,14 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
         setTypeTag(context, subTree, optFuncExpr, funcVarIndex);
         if (subTree.hasDataSource()) {
             fillIndexExprs(datasetIndexes, fieldName, fieldType, optFuncExpr, 
optFuncExprIndex, funcVarIndex, subTree,
-                    analysisCtx, fieldSource.intValue());
+                    analysisCtx, fieldSource.intValue(), accessMethod);
         }
     }
 
     private void analyzeAssignOp(AssignOperator assignOp, IOptimizableFuncExpr 
optFuncExpr,
             OptimizableOperatorSubTree subTree, int assignOrUnnestIndex, 
LogicalVariable datasetMetaVar,
             IOptimizationContext context, List<Index> datasetIndexes, int 
optFuncExprIndex,
-            AccessMethodAnalysisContext analysisCtx) throws 
AlgebricksException {
+            AccessMethodAnalysisContext analysisCtx, IAccessMethod 
accessMethod) throws AlgebricksException {
         boolean doesArrayIndexQualify = 
context.getPhysicalOptimizationConfig().isArrayIndexEnabled()
                 && datasetIndexes.stream().anyMatch(i -> i.getIndexType() == 
IndexType.ARRAY);
         List<LogicalVariable> varList = assignOp.getVariables();
@@ -850,7 +868,8 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                             .analyzeVarForArrayIndexes(datasetIndexes, 
optFuncExpr, subTree, context, var, analysisCtx);
                     if (fieldTriplet != null && subTree.hasDataSource()) {
                         fillIndexExprs(datasetIndexes, fieldTriplet.second, 
fieldTriplet.third, optFuncExpr,
-                                optFuncExprIndex, fieldTriplet.first, subTree, 
analysisCtx, fieldSource.intValue());
+                                optFuncExprIndex, fieldTriplet.first, subTree, 
analysisCtx, fieldSource.intValue(),
+                                accessMethod);
                     }
                 }
                 continue;
@@ -864,10 +883,10 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
             }
 
             fieldSource.setValue(0);
-            List<String> fieldName = 
AccessMethodUtils.getFieldNameFromSubTree(optFuncExpr, subTree,
+            List<String> fieldName = 
AccessMethodUtils.getFieldNameSetStepsFromSubTree(optFuncExpr, subTree,
                     assignOrUnnestIndex, varIndex, subTree.getRecordType(), 
optVarIndex,
-                    
optFuncExpr.getFuncExpr().getArguments().get(optVarIndex).getValue(), 
subTree.getMetaRecordType(),
-                    datasetMetaVar, fieldSource, false);
+                    optFuncExpr.getArgument(optVarIndex).getValue(), 
subTree.getMetaRecordType(), datasetMetaVar,
+                    fieldSource, false);
 
             IAType fieldType = (IAType) 
context.getOutputTypeEnvironment(assignOp).getVarType(var);
             // Set the fieldName in the corresponding matched
@@ -878,15 +897,15 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
             setTypeTag(context, subTree, optFuncExpr, optVarIndex);
             if (subTree.hasDataSource()) {
                 fillIndexExprs(datasetIndexes, fieldName, fieldType, 
optFuncExpr, optFuncExprIndex, optVarIndex,
-                        subTree, analysisCtx, fieldSource.intValue());
+                        subTree, analysisCtx, fieldSource.intValue(), 
accessMethod);
             }
         }
     }
 
     private void matchVarsFromOptFuncExprToDataSourceScan(IOptimizableFuncExpr 
optFuncExpr, int optFuncExprIndex,
             List<Index> datasetIndexes, List<LogicalVariable> dsVarList, 
OptimizableOperatorSubTree subTree,
-            AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context, boolean fromAdditionalDataSource)
-            throws AlgebricksException {
+            AccessMethodAnalysisContext analysisCtx, IOptimizationContext 
context, boolean fromAdditionalDataSource,
+            IAccessMethod accessMethod) throws AlgebricksException {
         MutableInt mutableFieldSource = new MutableInt(0);
         for (int varIndex = 0; varIndex < dsVarList.size(); varIndex++) {
             LogicalVariable var = dsVarList.get(varIndex);
@@ -943,13 +962,15 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
             optFuncExpr.setFieldName(funcVarIndex, fieldName, fieldSource);
             optFuncExpr.setOptimizableSubTree(funcVarIndex, subTree);
             optFuncExpr.setSourceVar(funcVarIndex, var);
-            VariableReferenceExpression varRef = new 
VariableReferenceExpression(var);
-            
varRef.setSourceLocation(subTree.getDataSourceRef().getValue().getSourceLocation());
-            optFuncExpr.setLogicalExpr(funcVarIndex, varRef);
+            ILogicalExpression expr = 
optFuncExpr.getArgument(funcVarIndex).getValue();
+            if (expr.getExpressionTag() == LogicalExpressionTag.FUNCTION_CALL) 
{
+                optFuncExpr.addStepExpr(funcVarIndex, 
((AbstractFunctionCallExpression) expr));
+            }
+            optFuncExpr.setLogicalExpr(funcVarIndex, expr);
             setTypeTag(context, subTree, optFuncExpr, funcVarIndex);
             if (subTree.hasDataSourceScan()) {
                 fillIndexExprs(datasetIndexes, fieldName, fieldType, 
optFuncExpr, optFuncExprIndex, funcVarIndex,
-                        subTree, analysisCtx, fieldSource);
+                        subTree, analysisCtx, fieldSource, accessMethod);
             }
         }
     }
@@ -986,7 +1007,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                     // funcVarIndex is not required. Thus, we set it to -1.
                     // optFuncExpr and parentFuncExpr are not required, too. 
Thus, we set them to null.
                     fieldSource.setValue(0);
-                    List<String> fieldName = 
AccessMethodUtils.getFieldNameFromSubTree(null, subTree,
+                    List<String> fieldName = 
AccessMethodUtils.getFieldNameSetStepsFromSubTree(null, subTree,
                             assignOrUnnestIndex, varIndex, 
subTree.getRecordType(), -1, null,
                             subTree.getMetaRecordType(), datasetMetaVar, 
fieldSource, false);
                     if (fieldName != null && !fieldName.isEmpty()) {
@@ -1001,7 +1022,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                     // funcVarIndex is not required. Thus, we set it to -1.
                     // optFuncExpr and parentFuncExpr are not required, too. 
Thus, we set them to null.
                     fieldSource.setValue(0);
-                    fieldName = 
AccessMethodUtils.getFieldNameFromSubTree(null, subTree, assignOrUnnestIndex, 0,
+                    fieldName = 
AccessMethodUtils.getFieldNameSetStepsFromSubTree(null, subTree, 
assignOrUnnestIndex, 0,
                             subTree.getRecordType(), -1, null, 
subTree.getMetaRecordType(), datasetMetaVar, fieldSource,
                             false);
                     if (fieldName != null && !fieldName.isEmpty()) {
@@ -1029,7 +1050,7 @@ public abstract class AbstractIntroduceAccessMethodRule 
implements IAlgebraicRew
                     // funcVarIndex is not required. Thus, we set it to -1.
                     // optFuncExpr and parentFuncExpr are not required, too. 
Thus, we set them to null.
                     fieldSource.setValue(0);
-                    List<String> fieldName = 
AccessMethodUtils.getFieldNameFromSubTree(null, subTree,
+                    List<String> fieldName = 
AccessMethodUtils.getFieldNameSetStepsFromSubTree(null, subTree,
                             assignOrUnnestIndex, varIndex, 
subTree.getRecordType(), -1, null,
                             subTree.getMetaRecordType(), datasetMetaVar, 
fieldSource, false);
                     if (fieldName != null && !fieldName.isEmpty()) {
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
index ac80d68..063d55f 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
@@ -19,6 +19,10 @@
 
 package org.apache.asterix.optimizer.rules.am;
 
+import static 
org.apache.asterix.om.functions.BuiltinFunctions.FIELD_ACCESS_BY_INDEX;
+import static 
org.apache.asterix.om.functions.BuiltinFunctions.FIELD_ACCESS_BY_NAME;
+import static 
org.apache.asterix.om.functions.BuiltinFunctions.FIELD_ACCESS_NESTED;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -127,14 +131,19 @@ public class AccessMethodUtils {
         CONDITIONAL_SPLIT_VAR
     }
 
-    // Function Identifier sets that retain the original field variable 
through each function's arguments
-    private final static ImmutableSet<FunctionIdentifier> 
funcIDSetThatRetainFieldName =
-            ImmutableSet.of(BuiltinFunctions.WORD_TOKENS, 
BuiltinFunctions.GRAM_TOKENS, BuiltinFunctions.SUBSTRING,
-                    BuiltinFunctions.SUBSTRING_BEFORE, 
BuiltinFunctions.SUBSTRING_AFTER,
-                    BuiltinFunctions.CREATE_POLYGON, 
BuiltinFunctions.CREATE_MBR, BuiltinFunctions.CREATE_RECTANGLE,
-                    BuiltinFunctions.CREATE_CIRCLE, 
BuiltinFunctions.CREATE_LINE, BuiltinFunctions.CREATE_POINT,
-                    BuiltinFunctions.NUMERIC_ADD, 
BuiltinFunctions.NUMERIC_SUBTRACT, BuiltinFunctions.NUMERIC_MULTIPLY,
-                    BuiltinFunctions.NUMERIC_DIVIDE, 
BuiltinFunctions.NUMERIC_DIV, BuiltinFunctions.NUMERIC_MOD);
+    public final static ImmutableSet<FunctionIdentifier> 
CAST_NULL_TYPE_CONSTRUCTORS = ImmutableSet.of(
+            BuiltinFunctions.BOOLEAN_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.INT8_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.INT16_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.INT32_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.INT64_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.FLOAT_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.DOUBLE_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.STRING_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.DATE_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.DATE_DEFAULT_NULL_CONSTRUCTOR_WITH_FORMAT,
+            BuiltinFunctions.TIME_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.TIME_DEFAULT_NULL_CONSTRUCTOR_WITH_FORMAT,
+            BuiltinFunctions.DATETIME_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.DATETIME_DEFAULT_NULL_CONSTRUCTOR_WITH_FORMAT,
+            BuiltinFunctions.DURATION_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.DAY_TIME_DURATION_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.YEAR_MONTH_DURATION_DEFAULT_NULL_CONSTRUCTOR,
+            BuiltinFunctions.UUID_DEFAULT_NULL_CONSTRUCTOR, 
BuiltinFunctions.BINARY_BASE64_DEFAULT_NULL_CONSTRUCTOR);
 
     public static void appendPrimaryIndexTypes(Dataset dataset, IAType 
itemType, IAType metaItemType,
             List<Object> target) throws AlgebricksException {
@@ -179,10 +188,12 @@ public class AccessMethodUtils {
 
     public static boolean 
analyzeFuncExprArgsForOneConstAndVarAndUpdateAnalysisCtx(
             AbstractFunctionCallExpression funcExpr, 
AccessMethodAnalysisContext analysisCtx,
-            IOptimizationContext context, IVariableTypeEnvironment 
typeEnvironment) throws AlgebricksException {
+            IOptimizationContext context, IVariableTypeEnvironment 
typeEnvironment, boolean allowFunctionExprArg)
+            throws AlgebricksException {
         ILogicalExpression constExpression = null;
         IAType constantExpressionType = null;
         LogicalVariable fieldVar = null;
+        int varIndex;
         ILogicalExpression arg1 = funcExpr.getArguments().get(0).getValue();
         ILogicalExpression arg2 = funcExpr.getArguments().get(1).getValue();
         // One of the args must be a runtime constant, and the other arg must 
be a variable.
@@ -206,6 +217,7 @@ public class AccessMethodUtils {
             constExpression = arg1;
             VariableReferenceExpression varExpr = 
(VariableReferenceExpression) arg2;
             fieldVar = varExpr.getVariableReference();
+            varIndex = 1;
         } else if (arg1.getExpressionTag() == LogicalExpressionTag.VARIABLE) {
             IAType expressionType = constantRuntimeResultType(arg2, context, 
typeEnvironment);
             if (expressionType == null) {
@@ -225,27 +237,96 @@ public class AccessMethodUtils {
 
             VariableReferenceExpression varExpr = 
(VariableReferenceExpression) arg1;
             fieldVar = varExpr.getVariableReference();
+            varIndex = 0;
         } else {
-            return false;
+            if (!allowFunctionExprArg) {
+                return false;
+            }
+            // extract the variable argument.
+            if (acceptExpressionArg(arg1, context, typeEnvironment)) {
+                // arg1 = expr, arg2 should be a constant
+                Pair<LogicalVariable, IAType> varConstType =
+                        getVarAndConstExprType(arg1, arg2, context, 
typeEnvironment);
+                if (varConstType == null) {
+                    return false;
+                }
+                fieldVar = varConstType.first;
+                constantExpressionType = varConstType.second;
+                constExpression = arg2;
+                varIndex = 0;
+            } else if (acceptExpressionArg(arg2, context, typeEnvironment)) {
+                // arg2 = expr, arg1 should be a constant
+                Pair<LogicalVariable, IAType> varConstType =
+                        getVarAndConstExprType(arg2, arg1, context, 
typeEnvironment);
+                if (varConstType == null) {
+                    return false;
+                }
+                fieldVar = varConstType.first;
+                constantExpressionType = varConstType.second;
+                constExpression = arg1;
+                varIndex = 1;
+            } else {
+                return false;
+            }
         }
 
         // Updates the given Analysis Context by adding a new optimizable 
function expression.
         constructNewOptFuncExprAndAddToAnalysisCtx(funcExpr, fieldVar, 
constExpression, constantExpressionType,
-                analysisCtx);
+                analysisCtx, varIndex);
+        return true;
+    }
+
+    private static boolean acceptExpressionArg(ILogicalExpression expr, 
IOptimizationContext context,
+            IVariableTypeEnvironment typeEnvironment) throws 
AlgebricksException {
+        if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return false;
+        }
+        AbstractFunctionCallExpression funExpr = 
(AbstractFunctionCallExpression) expr;
+        List<Mutable<ILogicalExpression>> funArgs = funExpr.getArguments();
+        if (funArgs.size() <= 0) {
+            return false;
+        }
+        // first arg must be a variable and the rest are constants
+        if (funArgs.get(0).getValue().getExpressionTag() != 
LogicalExpressionTag.VARIABLE) {
+            return false;
+        }
+        for (int i = 1; i < funArgs.size(); i++) {
+            IAType constExprType = 
constantRuntimeResultType(funArgs.get(i).getValue(), context, typeEnvironment);
+            if (constExprType == null) {
+                // not constant at runtime
+                return false;
+            }
+        }
         return true;
     }
 
+    private static Pair<LogicalVariable, IAType> 
getVarAndConstExprType(ILogicalExpression exprWithVar,
+            ILogicalExpression constExpr, IOptimizationContext context, 
IVariableTypeEnvironment typeEnvironment)
+            throws AlgebricksException {
+        IAType constExprType = constantRuntimeResultType(constExpr, context, 
typeEnvironment);
+        if (constExprType == null) {
+            // not constant at runtime
+            return null;
+        }
+        AbstractFunctionCallExpression funExpr = 
(AbstractFunctionCallExpression) exprWithVar;
+        LogicalVariable varFromExpr =
+                ((VariableReferenceExpression) 
funExpr.getArguments().get(0).getValue()).getVariableReference();
+        return new Pair<>(varFromExpr, constExprType);
+    }
+
     private static void 
constructNewOptFuncExprAndAddToAnalysisCtx(AbstractFunctionCallExpression 
funcExpr,
             LogicalVariable fieldVar, ILogicalExpression expression, IAType 
expressionType,
-            AccessMethodAnalysisContext analysisCtx) {
-        OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, 
fieldVar, expression, expressionType);
+            AccessMethodAnalysisContext analysisCtx, int varIndex) {
+        OptimizableFuncExpr newOptFuncExpr =
+                new OptimizableFuncExpr(funcExpr, fieldVar, expression, 
expressionType, varIndex);
         addNewOptFuncExprToAnalysisCtx(funcExpr, newOptFuncExpr, analysisCtx);
     }
 
     private static void 
constructNewOptFuncExprAndAddToAnalysisCtx(AbstractFunctionCallExpression 
funcExpr,
-            LogicalVariable[] fieldVars, ILogicalExpression[] expressions, 
IAType[] expressionTypes,
-            AccessMethodAnalysisContext analysisCtx) {
-        OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, 
fieldVars, expressions, expressionTypes);
+            LogicalVariable[] fieldVars, int[] fieldVarsIdxes, 
ILogicalExpression[] expressions,
+            IAType[] expressionTypes, AccessMethodAnalysisContext analysisCtx) 
{
+        OptimizableFuncExpr newOptFuncExpr =
+                new OptimizableFuncExpr(funcExpr, fieldVars, fieldVarsIdxes, 
expressions, expressionTypes);
         addNewOptFuncExprToAnalysisCtx(funcExpr, newOptFuncExpr, analysisCtx);
 
     }
@@ -332,7 +413,7 @@ public class AccessMethodUtils {
 
         // Updates the given Analysis Context by adding a new optimizable 
function expression.
         constructNewOptFuncExprAndAddToAnalysisCtx(funcExpr, new 
LogicalVariable[] { fieldVar1, fieldVar2 },
-                new ILogicalExpression[0], new IAType[0], analysisCtx);
+                new int[] { 0, 1 }, new ILogicalExpression[0], new IAType[0], 
analysisCtx);
         return true;
     }
 
@@ -2781,6 +2862,19 @@ public class AccessMethodUtils {
         return ann == null ? null : ann.getIndexNames();
     }
 
+    public static List<String> 
getFieldNameSetStepsFromSubTree(IOptimizableFuncExpr optFuncExpr,
+            OptimizableOperatorSubTree subTree, int opIndex, int 
assignVarIndex, ARecordType recordType,
+            int funcVarIndex, ILogicalExpression parentFuncExpr, ARecordType 
metaType, LogicalVariable metaVar,
+            MutableInt fieldSource, boolean isUnnestOverVarAllowed) throws 
AlgebricksException {
+        if (optFuncExpr != null) {
+            if (parentFuncExpr.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+                optFuncExpr.addStepExpr(funcVarIndex, 
((AbstractFunctionCallExpression) parentFuncExpr));
+            }
+        }
+        return getFieldNameAndStepsFromSubTree(optFuncExpr, subTree, opIndex, 
assignVarIndex, recordType, funcVarIndex,
+                parentFuncExpr, metaType, metaVar, fieldSource, 
isUnnestOverVarAllowed);
+    }
+
     /**
      * Returns the field name corresponding to the assigned variable at
      * varIndex. Returns Collections.emptyList() if the expr at varIndex does 
not yield to a field
@@ -2788,7 +2882,7 @@ public class AccessMethodUtils {
      *
      * @throws AlgebricksException
      */
-    public static List<String> getFieldNameFromSubTree(IOptimizableFuncExpr 
optFuncExpr,
+    private static List<String> 
getFieldNameAndStepsFromSubTree(IOptimizableFuncExpr optFuncExpr,
             OptimizableOperatorSubTree subTree, int opIndex, int 
assignVarIndex, ARecordType recordType,
             int funcVarIndex, ILogicalExpression parentFuncExpr, ARecordType 
metaType, LogicalVariable metaVar,
             MutableInt fieldSource, boolean isUnnestOverVarAllowed) throws 
AlgebricksException {
@@ -2800,7 +2894,7 @@ public class AccessMethodUtils {
             AssignOperator assignOp = (AssignOperator) op;
             expr = (AbstractLogicalExpression) 
assignOp.getExpressions().get(assignVarIndex).getValue();
             // Can't get a field name from a constant expression. So, return 
null.
-            if (expr.getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+            if (expr.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) 
{
                 return Collections.emptyList();
             }
             childFuncExpr = (AbstractFunctionCallExpression) expr;
@@ -2866,6 +2960,7 @@ public class AccessMethodUtils {
             }
             if (optFuncExpr != null) {
                 optFuncExpr.setLogicalExpr(funcVarIndex, parentFuncExpr);
+                optFuncExpr.addStepExpr(funcVarIndex, funcExpr);
             }
             int[] assignAndExpressionIndexes = null;
 
@@ -2888,7 +2983,7 @@ public class AccessMethodUtils {
                 for (int varIndex = 0; varIndex < varList.size(); varIndex++) {
                     LogicalVariable var = varList.get(varIndex);
                     ArrayList<LogicalVariable> parentVars = new ArrayList<>();
-                    expr.getUsedVariables(parentVars);
+                    funcExpr.getUsedVariables(parentVars);
 
                     if (parentVars.contains(var)) {
                         //Found the variable we are looking for.
@@ -2902,7 +2997,7 @@ public class AccessMethodUtils {
                 //We found the nested assign
 
                 //Recursive call on nested assign
-                List<String> parentFieldNames = 
getFieldNameFromSubTree(optFuncExpr, subTree,
+                List<String> parentFieldNames = 
getFieldNameAndStepsFromSubTree(optFuncExpr, subTree,
                         assignAndExpressionIndexes[0], 
assignAndExpressionIndexes[1], recordType, funcVarIndex,
                         parentFuncExpr, metaType, metaVar, fieldSource, 
isUnnestOverVarAllowed);
 
@@ -2963,20 +3058,29 @@ public class AccessMethodUtils {
 
         }
 
-        if (!funcIDSetThatRetainFieldName.contains(funcIdent)) {
-            return Collections.emptyList();
-        }
         // We use a part of the field in edit distance computation
         if (optFuncExpr != null
                 && optFuncExpr.getFuncExpr().getFunctionIdentifier() == 
BuiltinFunctions.EDIT_DISTANCE_CHECK) {
             optFuncExpr.setPartialField(true);
         }
+        List<Mutable<ILogicalExpression>> funcArgs = funcExpr.getArguments();
+        if (funcArgs.isEmpty()) {
+            return Collections.emptyList();
+        }
         // We expect the function's argument to be a variable, otherwise we
         // cannot apply an index.
-        ILogicalExpression argExpr = funcExpr.getArguments().get(0).getValue();
+        ILogicalExpression argExpr = funcArgs.get(0).getValue();
         if (argExpr.getExpressionTag() != LogicalExpressionTag.VARIABLE) {
             return Collections.emptyList();
         }
+        for (int i = 1; i < funcArgs.size(); i++) {
+            if (funcArgs.get(i).getValue().getExpressionTag() != 
LogicalExpressionTag.CONSTANT) {
+                return Collections.emptyList();
+            }
+        }
+        if (optFuncExpr != null) {
+            optFuncExpr.addStepExpr(funcVarIndex, funcExpr);
+        }
         LogicalVariable curVar = ((VariableReferenceExpression) 
argExpr).getVariableReference();
         // We look for the assign or unnest operator that produces curVar below
         // the current operator
@@ -2990,16 +3094,17 @@ public class AccessMethodUtils {
                     LogicalVariable var = varList.get(varIndex);
                     if (var.equals(curVar) && optFuncExpr != null) {
                         optFuncExpr.setSourceVar(funcVarIndex, var);
-                        return getFieldNameFromSubTree(optFuncExpr, subTree, 
assignOrUnnestIndex, varIndex, recordType,
-                                funcVarIndex, childFuncExpr, metaType, 
metaVar, fieldSource, isUnnestOverVarAllowed);
+                        return getFieldNameAndStepsFromSubTree(optFuncExpr, 
subTree, assignOrUnnestIndex, varIndex,
+                                recordType, funcVarIndex, childFuncExpr, 
metaType, metaVar, fieldSource,
+                                isUnnestOverVarAllowed);
                     }
                 }
             } else {
                 UnnestOperator unnestOp = (UnnestOperator) curOp;
                 LogicalVariable var = unnestOp.getVariable();
                 if (var.equals(curVar)) {
-                    getFieldNameFromSubTree(optFuncExpr, subTree, 
assignOrUnnestIndex, 0, recordType, funcVarIndex,
-                            childFuncExpr, metaType, metaVar, fieldSource, 
isUnnestOverVarAllowed);
+                    getFieldNameAndStepsFromSubTree(optFuncExpr, subTree, 
assignOrUnnestIndex, 0, recordType,
+                            funcVarIndex, childFuncExpr, metaType, metaVar, 
fieldSource, isUnnestOverVarAllowed);
                 }
             }
         }
@@ -3014,8 +3119,10 @@ public class AccessMethodUtils {
         if (lastMatchedDataSourceVar < 0) {
             return null;
         }
-        final ILogicalExpression optVarExpr =
-                
optFuncExpr.getFuncExpr().getArguments().get(lastMatchedDataSourceVar).getValue();
+        final ILogicalExpression optVarExpr = 
optFuncExpr.getArgument(lastMatchedDataSourceVar).getValue();
+        if (optVarExpr.getExpressionTag() == 
LogicalExpressionTag.FUNCTION_CALL) {
+            optFuncExpr.addStepExpr(lastMatchedDataSourceVar, 
((AbstractFunctionCallExpression) optVarExpr));
+        }
         optFuncExpr.setLogicalExpr(lastMatchedDataSourceVar, optVarExpr);
 
         for (Index index : datasetIndexes) {
@@ -3066,4 +3173,9 @@ public class AccessMethodUtils {
         }
         return null;
     }
+
+    public static boolean isFieldAccess(FunctionIdentifier funId) {
+        return funId.equals(FIELD_ACCESS_BY_NAME) || 
funId.equals(FIELD_ACCESS_BY_INDEX)
+                || funId.equals(FIELD_ACCESS_NESTED);
+    }
 }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
index 8d79c7d..1274620 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/ArrayBTreeAccessMethod.java
@@ -250,8 +250,21 @@ public class ArrayBTreeAccessMethod extends 
BTreeAccessMethod {
     }
 
     @Override
+    public boolean acceptsFunction(AbstractFunctionCallExpression 
functionExpr, IAType indexedFieldType,
+            boolean defaultNull, boolean finalStep) throws 
CompilationException {
+        if (defaultNull) {
+            throw new 
CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, "CAST modifier not 
allowed");
+        }
+        return 
AccessMethodUtils.isFieldAccess(functionExpr.getFunctionIdentifier());
+    }
+
+    @Override
     public int compareTo(IAccessMethod o) {
         return this.getName().compareTo(o.getName());
     }
 
+    @Override
+    protected boolean allowFunctionExpressionArg() {
+        return false;
+    }
 }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
index c21c21b..02557fe 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/BTreeAccessMethod.java
@@ -19,6 +19,8 @@
 
 package org.apache.asterix.optimizer.rules.am;
 
+import static 
org.apache.asterix.optimizer.rules.am.AccessMethodUtils.CAST_NULL_TYPE_CONSTRUCTORS;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -39,6 +41,7 @@ import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Index;
+import org.apache.asterix.metadata.utils.TypeUtil;
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.types.ARecordType;
 import org.apache.asterix.om.types.AUnionType;
@@ -117,13 +120,17 @@ public class BTreeAccessMethod implements IAccessMethod {
             List<AbstractLogicalOperator> assignsAndUnnests, 
AccessMethodAnalysisContext analysisCtx,
             IOptimizationContext context, IVariableTypeEnvironment 
typeEnvironment) throws AlgebricksException {
         boolean matches = 
AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVarAndUpdateAnalysisCtx(funcExpr,
-                analysisCtx, context, typeEnvironment);
+                analysisCtx, context, typeEnvironment, 
allowFunctionExpressionArg());
         if (!matches) {
             matches = 
AccessMethodUtils.analyzeFuncExprArgsForTwoVarsAndUpdateAnalysisCtx(funcExpr, 
analysisCtx);
         }
         return matches;
     }
 
+    protected boolean allowFunctionExpressionArg() {
+        return true;
+    }
+
     @Override
     public boolean matchAllIndexExprs(Index index) {
         return false;
@@ -961,7 +968,7 @@ public class BTreeAccessMethod implements IAccessMethod {
                 return optFuncExpr.getLogicalExpr(0) == null;
             }
             // We are optimizing a selection query. Search key is a constant. 
Return true if constant is on lhs.
-            return optFuncExpr.getFuncExpr().getArguments().get(0) == 
optFuncExpr.getConstantExpr(0);
+            return optFuncExpr.getArgument(0) == 
optFuncExpr.getConstantExpr(0);
         } else {
             // We are optimizing a join query. Determine whether the feeding 
variable is on the lhs.
             return (optFuncExpr.getOperatorSubTree(0) == null || 
optFuncExpr.getOperatorSubTree(0) == probeSubTree);
@@ -1033,6 +1040,25 @@ public class BTreeAccessMethod implements IAccessMethod {
     }
 
     @Override
+    public boolean acceptsFunction(AbstractFunctionCallExpression 
functionExpr, IAType indexedFieldType,
+            boolean defaultNull, boolean finalStep) throws 
CompilationException {
+        FunctionIdentifier funId = functionExpr.getFunctionIdentifier();
+        if (!finalStep) {
+            return AccessMethodUtils.isFieldAccess(funId);
+        }
+        if (AccessMethodUtils.isFieldAccess(funId)) {
+            return !defaultNull;
+        } else if (defaultNull && CAST_NULL_TYPE_CONSTRUCTORS.contains(funId)) 
{
+            IAType nonNullableType = 
Index.getNonNullableType(indexedFieldType).first;
+            FunctionIdentifier indexedFieldConstructor = 
TypeUtil.getTypeConstructorDefaultNull(nonNullableType);
+            // index should have CAST (DEFAULT NULL) and the applied function 
should be the same as the indexed field
+            return funId.equals(indexedFieldConstructor);
+        } else {
+            return false;
+        }
+    }
+
+    @Override
     public int compareTo(IAccessMethod o) {
         return this.getName().compareTo(o.getName());
     }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
index b21cf12..8ea2d37 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IAccessMethod.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.asterix.common.config.DatasetConfig.IndexType;
 import org.apache.asterix.metadata.entities.Index;
+import org.apache.asterix.om.types.IAType;
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
 import org.apache.hyracks.algebricks.common.utils.Pair;
@@ -130,4 +131,16 @@ public interface IAccessMethod extends 
Comparable<IAccessMethod> {
 
     public String getName();
 
+    /**
+     * Checks whether the function applied to an indexed field is acceptable 
by the access method.
+     *
+     * @param functionExpr applied function
+     * @param indexedFieldType the type of the indexed field in the index 
definition
+     * @param defaultNull true if the candidate index has CAST (DEFAULT NULL) 
modifier
+     * @param finalStep true if the functionExpr is the final function applied
+     *
+     * @return true if the access method accepts the argument function. False, 
otherwise.
+     */
+    public boolean acceptsFunction(AbstractFunctionCallExpression 
functionExpr, IAType indexedFieldType,
+            boolean defaultNull, boolean finalStep) throws AlgebricksException;
 }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
index 6278865..ae8c8c5 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IOptimizableFuncExpr.java
@@ -21,6 +21,7 @@ package org.apache.asterix.optimizer.rules.am;
 import java.util.List;
 
 import org.apache.asterix.om.types.IAType;
+import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
@@ -80,4 +81,17 @@ public interface IOptimizableFuncExpr {
     void setConstantExpr(int index, ILogicalExpression expr);
 
     ILogicalExpression[] getConstantExpressions();
+
+    void addStepExpr(int index, AbstractFunctionCallExpression funcExpr);
+
+    List<AbstractFunctionCallExpression> getStepsExprs(int index);
+
+    /**
+     * Returns the argument expression from which the logical variable is 
originating in the optimizable function.
+     *
+     * @param index the index of the logical variable for which to return the 
expression argument
+     *
+     * @return the argument expression
+     */
+    Mutable<ILogicalExpression> getArgument(int index);
 }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
index ab0ae5f..fc8c3e9 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/IntroduceLSMComponentFilterRule.java
@@ -497,7 +497,7 @@ public class IntroduceLSMComponentFilterRule implements 
IAlgebraicRewriteRule {
                 || funcIdent == AlgebricksBuiltinFunctions.LT || funcIdent == 
AlgebricksBuiltinFunctions.GT
                 || funcIdent == AlgebricksBuiltinFunctions.EQ) {
             
AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVarAndUpdateAnalysisCtx(funcExpr,
 analysisCtx, context,
-                    typeEnvironment);
+                    typeEnvironment, false);
         }
     }
 
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
index 8530dee..6fd1290 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/InvertedIndexAccessMethod.java
@@ -149,7 +149,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
                 || funcExpr.getFunctionIdentifier() == 
BuiltinFunctions.FULLTEXT_CONTAINS
                 || funcExpr.getFunctionIdentifier() == 
BuiltinFunctions.FULLTEXT_CONTAINS_WO_OPTION) {
             boolean matches = 
AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVarAndUpdateAnalysisCtx(funcExpr,
-                    analysisCtx, context, typeEnvironment);
+                    analysisCtx, context, typeEnvironment, false);
             if (!matches) {
                 matches = 
AccessMethodUtils.analyzeFuncExprArgsForTwoVarsAndUpdateAnalysisCtx(funcExpr, 
analysisCtx);
             }
@@ -279,9 +279,10 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
         if (fieldVarExpr2 == null) {
             return false;
         }
-        OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr,
-                new LogicalVariable[] { fieldVarExpr1, fieldVarExpr2 }, new 
ILogicalExpression[] { arg3 },
-                new IAType[] { (IAType) 
ExpressionTypeComputer.INSTANCE.getType(arg3, null, null) });
+        OptimizableFuncExpr newOptFuncExpr =
+                new OptimizableFuncExpr(funcExpr, new LogicalVariable[] { 
fieldVarExpr1, fieldVarExpr2 },
+                        new int[] { 0, 1 }, new ILogicalExpression[] { arg3 },
+                        new IAType[] { (IAType) 
ExpressionTypeComputer.INSTANCE.getType(arg3, null, null) });
         for (IOptimizableFuncExpr optFuncExpr : 
analysisCtx.getMatchedFuncExprs()) {
             //avoid additional optFuncExpressions in case of a join
             if (optFuncExpr.getFuncExpr().equals(funcExpr)) {
@@ -306,6 +307,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
         // Determine whether one arg is constant, and the other is 
non-constant.
         ILogicalExpression constArg;
         ILogicalExpression nonConstArg;
+        int nonConstArgIdx;
         if (arg1.getExpressionTag() == LogicalExpressionTag.CONSTANT
                 && arg2.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
             // The arguments of edit-distance-contains() function are 
asymmetrical, we can only use index if it is on
@@ -315,10 +317,12 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
             }
             constArg = arg1;
             nonConstArg = arg2;
+            nonConstArgIdx = 1;
         } else if (arg2.getExpressionTag() == LogicalExpressionTag.CONSTANT
                 && arg1.getExpressionTag() != LogicalExpressionTag.CONSTANT) {
             constArg = arg2;
             nonConstArg = arg1;
+            nonConstArgIdx = 0;
         } else {
             return false;
         }
@@ -329,7 +333,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
         }
 
         OptimizableFuncExpr newOptFuncExpr = new OptimizableFuncExpr(funcExpr, 
new LogicalVariable[] { fieldVarExpr },
-                new ILogicalExpression[] { constArg, arg3 },
+                new int[] { nonConstArgIdx }, new ILogicalExpression[] { 
constArg, arg3 },
                 new IAType[] { (IAType) 
ExpressionTypeComputer.INSTANCE.getType(constArg, null, null),
                         (IAType) ExpressionTypeComputer.INSTANCE.getType(arg3, 
null, null) });
         for (IOptimizableFuncExpr optFuncExpr : 
analysisCtx.getMatchedFuncExprs()) {
@@ -1088,7 +1092,7 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
             if (targetVar == null) {
                 continue;
             }
-            return 
isJaccardFuncCompatible(optFuncExpr.getFuncExpr().getArguments().get(i).getValue(),
+            return 
isJaccardFuncCompatible(optFuncExpr.getArgument(i).getValue(),
                     optFuncExpr.getFieldType(i).getTypeTag(), 
index.getIndexType());
         }
 
@@ -1346,6 +1350,18 @@ public class InvertedIndexAccessMethod implements 
IAccessMethod {
     }
 
     @Override
+    public boolean acceptsFunction(AbstractFunctionCallExpression 
functionExpr, IAType indexedFieldType,
+            boolean defaultNull, boolean finalStep) throws 
CompilationException {
+        if (defaultNull) {
+            throw new 
CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, "CAST modifier not 
allowed");
+        }
+        FunctionIdentifier funId = functionExpr.getFunctionIdentifier();
+        return AccessMethodUtils.isFieldAccess(funId) || 
funId.equals(BuiltinFunctions.GRAM_TOKENS)
+                || funId.equals(BuiltinFunctions.WORD_TOKENS) || 
funId.equals(BuiltinFunctions.SUBSTRING)
+                || funId.equals(BuiltinFunctions.SUBSTRING_BEFORE) || 
funId.equals(BuiltinFunctions.SUBSTRING_AFTER);
+    }
+
+    @Override
     public int compareTo(IAccessMethod o) {
         return this.getName().compareTo(o.getName());
     }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
index 7b04340..9c3ba68 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/OptimizableFuncExpr.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.asterix.om.functions.BuiltinFunctions;
 import org.apache.asterix.om.types.IAType;
+import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.hyracks.algebricks.core.algebra.base.ILogicalExpression;
 import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
 import 
org.apache.hyracks.algebricks.core.algebra.expressions.AbstractFunctionCallExpression;
@@ -35,7 +36,9 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
     protected final AbstractFunctionCallExpression funcExpr;
     protected final LogicalVariable[] logicalVars;
     protected final LogicalVariable[] sourceVars;
+    protected final int[] logicalVarsExprsIndexes;
     protected final ILogicalExpression[] logicalExprs;
+    protected final List<List<AbstractFunctionCallExpression>> stepsExprs; // 
all the transformations of a logical var
     protected final List<List<String>> fieldNames;
     protected final int[] fieldSources;
     protected final IAType[] fieldTypes;
@@ -45,17 +48,22 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
     protected boolean partialField;
 
     public OptimizableFuncExpr(AbstractFunctionCallExpression funcExpr, 
LogicalVariable[] logicalVars,
-            ILogicalExpression[] constantExpressions, IAType[] 
constantExpressionTypes) {
+            int[] logicalVarsExprsIndexes, ILogicalExpression[] 
constantExpressions, IAType[] constantExpressionTypes) {
         this.funcExpr = funcExpr;
         this.logicalVars = logicalVars;
+        this.logicalVarsExprsIndexes = logicalVarsExprsIndexes;
         this.sourceVars = new LogicalVariable[logicalVars.length];
         this.logicalExprs = new ILogicalExpression[logicalVars.length];
         this.constantExpressionTypes = constantExpressionTypes;
         this.constantExpressions = constantExpressions;
         this.fieldSources = new int[logicalVars.length];
-        this.fieldNames = new ArrayList<List<String>>();
+        this.fieldNames = new ArrayList<>();
         for (int i = 0; i < logicalVars.length; i++) {
-            fieldNames.add(new ArrayList<String>());
+            fieldNames.add(new ArrayList<>());
+        }
+        this.stepsExprs = new ArrayList<>();
+        for (int i = 0; i < logicalVars.length; i++) {
+            stepsExprs.add(new ArrayList<>());
         }
         this.fieldTypes = new IAType[logicalVars.length];
         this.subTrees = new OptimizableOperatorSubTree[logicalVars.length];
@@ -69,7 +77,7 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
 
     // Special, more convenient c'tor for simple binary functions.
     public OptimizableFuncExpr(AbstractFunctionCallExpression funcExpr, 
LogicalVariable logicalVar,
-            ILogicalExpression constantExpression, IAType 
constantExpressionType) {
+            ILogicalExpression constantExpression, IAType 
constantExpressionType, int varIndexInOptFunExpr) {
         this.funcExpr = funcExpr;
         this.logicalVars = new LogicalVariable[] { logicalVar };
         this.sourceVars = new LogicalVariable[1];
@@ -77,10 +85,15 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
         this.constantExpressions = new ILogicalExpression[] { 
constantExpression };
         this.constantExpressionTypes = new IAType[] { constantExpressionType };
         this.fieldSources = new int[logicalVars.length];
-        this.fieldNames = new ArrayList<List<String>>();
+        this.fieldNames = new ArrayList<>();
+        for (int i = 0; i < logicalVars.length; i++) {
+            fieldNames.add(new ArrayList<>());
+        }
+        this.stepsExprs = new ArrayList<>();
         for (int i = 0; i < logicalVars.length; i++) {
-            fieldNames.add(new ArrayList<String>());
+            stepsExprs.add(new ArrayList<>());
         }
+        this.logicalVarsExprsIndexes = new int[] { varIndexInOptFunExpr };
         this.fieldTypes = new IAType[logicalVars.length];
         this.subTrees = new OptimizableOperatorSubTree[logicalVars.length];
         if (funcExpr.getFunctionIdentifier() == 
BuiltinFunctions.EDIT_DISTANCE_CONTAINS) {
@@ -157,6 +170,21 @@ public class OptimizableFuncExpr implements 
IOptimizableFuncExpr {
     }
 
     @Override
+    public void addStepExpr(int index, AbstractFunctionCallExpression 
funcExpr) {
+        stepsExprs.get(index).add(funcExpr);
+    }
+
+    @Override
+    public List<AbstractFunctionCallExpression> getStepsExprs(int index) {
+        return stepsExprs.get(index);
+    }
+
+    @Override
+    public Mutable<ILogicalExpression> getArgument(int index) {
+        return funcExpr.getArguments().get(logicalVarsExprsIndexes[index]);
+    }
+
+    @Override
     public void setConstType(int index, IAType fieldType) {
         constantExpressionTypes[index] = fieldType;
     }
diff --git 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
index 381cfd2..a61738e 100644
--- 
a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
+++ 
b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/RTreeAccessMethod.java
@@ -27,6 +27,8 @@ import java.util.List;
 import 
org.apache.asterix.common.annotations.SecondaryIndexSearchPreferenceAnnotation;
 import org.apache.asterix.common.config.DatasetConfig.DatasetType;
 import org.apache.asterix.common.config.DatasetConfig.IndexType;
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.exceptions.ErrorCode;
 import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.metadata.entities.Dataset;
 import org.apache.asterix.metadata.entities.Index;
@@ -97,7 +99,7 @@ public class RTreeAccessMethod implements IAccessMethod {
             List<AbstractLogicalOperator> assignsAndUnnests, 
AccessMethodAnalysisContext analysisCtx,
             IOptimizationContext context, IVariableTypeEnvironment 
typeEnvironment) throws AlgebricksException {
         boolean matches = 
AccessMethodUtils.analyzeFuncExprArgsForOneConstAndVarAndUpdateAnalysisCtx(funcExpr,
-                analysisCtx, context, typeEnvironment);
+                analysisCtx, context, typeEnvironment, false);
         if (!matches) {
             matches = 
AccessMethodUtils.analyzeFuncExprArgsForTwoVarsAndUpdateAnalysisCtx(funcExpr, 
analysisCtx);
         }
@@ -395,6 +397,15 @@ public class RTreeAccessMethod implements IAccessMethod {
     }
 
     @Override
+    public boolean acceptsFunction(AbstractFunctionCallExpression 
functionExpr, IAType indexedFieldType,
+            boolean defaultNull, boolean finalStep) throws 
CompilationException {
+        if (defaultNull) {
+            throw new 
CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, "CAST modifier not 
allowed");
+        }
+        return 
AccessMethodUtils.isFieldAccess(functionExpr.getFunctionIdentifier());
+    }
+
+    @Override
     public int compareTo(IAccessMethod o) {
         return this.getName().compareTo(o.getName());
     }
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-01.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-01.sqlpp
new file mode 100644
index 0000000..9721183
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-01.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds1(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE INDEX idx1 ON ds1(x: int);
+CREATE VIEW view1(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds1;
+
+// test that idx1 on x is not used since idx1 does not have the CAST modifier 
and the field x has cast
+SELECT id, x, y FROM view1 WHERE x <= 1 ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-02.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-02.sqlpp
new file mode 100644
index 0000000..969a769
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-02.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds2(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE INDEX idx2 ON ds2(x: int) CAST (DEFAULT NULL);
+CREATE VIEW view2(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds2;
+
+// test that idx2 on x is used since idx2 has the CAST modifier and the field 
x has cast
+SELECT id, x, y FROM view2 WHERE x <= 1 ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-03.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-03.sqlpp
new file mode 100644
index 0000000..2d3fa85
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-03.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds3(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE INDEX idx3 ON ds3(x: int) CAST (DEFAULT NULL);
+CREATE VIEW view3(id int, x string, y int) DEFAULT NULL AS SELECT id, x, y 
FROM ds3;
+
+// test that idx3 on x is not used since idx3 has the CAST modifier on int and 
the field x has cast as string
+SELECT id, x, y FROM view3 WHERE x <= "1" ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-04.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-04.sqlpp
new file mode 100644
index 0000000..f3d2ecc
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-04.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds3(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE INDEX idx3 ON ds3(x: int) CAST (DEFAULT NULL);
+CREATE VIEW view3(id int, x string, y int) DEFAULT NULL AS SELECT id, x, y 
FROM ds3;
+
+// test that idx3 on x is not used since idx3 has the CAST modifier and the 
field x does not have cast
+SELECT id, x, y FROM ds3 WHERE x <= 1 ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-05.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-05.sqlpp
new file mode 100644
index 0000000..cc050e4
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-05.sqlpp
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds2(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds4(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+CREATE INDEX idx2 ON ds2(x: int) CAST (DEFAULT NULL);
+
+CREATE VIEW view2(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds2;
+CREATE VIEW view4(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds4;
+
+
+USE test;
+// test that idx2 on view2(x) is used. both v4.x and v2.x are int and idx2 is 
on x as int.
+SELECT v4.x AS v4x, v2.x AS v2x
+FROM view4 AS v4, view2 AS v2
+WHERE v4.x /*+ indexnl */ = v2.x ORDER BY v4x, v2x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-06.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-06.sqlpp
new file mode 100644
index 0000000..514c920
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-06.sqlpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds3(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds4(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+CREATE INDEX idx3 ON ds3(x: int) CAST (DEFAULT NULL);
+
+CREATE VIEW view3(id int, x string, y int) DEFAULT NULL AS SELECT id, x, y 
FROM ds3;
+CREATE VIEW view4(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds4;
+
+USE test;
+// test that idx3 on view3(x) is not used since v4.x is int, v3.x is string
+SELECT v4.x AS v4x, v3.x AS v3x
+FROM view4 AS v4, view3 AS v3
+WHERE v4.x /*+ indexnl */ = v3.x ORDER BY v4x, v3x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-07.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-07.sqlpp
new file mode 100644
index 0000000..3b9ed4b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-07.sqlpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds1(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds4(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+CREATE INDEX idx1 ON ds1(x: int);
+
+CREATE VIEW view1(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds1;
+CREATE VIEW view4(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds4;
+
+USE test;
+// test that idx1 is not used even though v4.x is int, v1.x is int because 
idx1 does not have CAST modifier.
+SELECT v4.x AS v4x, v1.x AS v1x
+FROM view4 AS v4, view1 AS v1
+WHERE v4.x /*+ indexnl */ = v1.x ORDER BY v4x, v1x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-08.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-08.sqlpp
new file mode 100644
index 0000000..3b9ed4b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-08.sqlpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds1(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds4(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+CREATE INDEX idx1 ON ds1(x: int);
+
+CREATE VIEW view1(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds1;
+CREATE VIEW view4(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds4;
+
+USE test;
+// test that idx1 is not used even though v4.x is int, v1.x is int because 
idx1 does not have CAST modifier.
+SELECT v4.x AS v4x, v1.x AS v1x
+FROM view4 AS v4, view1 AS v1
+WHERE v4.x /*+ indexnl */ = v1.x ORDER BY v4x, v1x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-09.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-09.sqlpp
new file mode 100644
index 0000000..e8eddb2
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/cast-default-null/cast-default-null-09.sqlpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds2(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds4(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+CREATE INDEX idx2 ON ds2(x: int) CAST (DEFAULT NULL);
+
+CREATE VIEW view4(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds4;
+
+USE test;
+// test that idx2 is not used because v4.x is int-default-null and ds2.x is 
int.
+SELECT v4.x AS v4x, ds2.x AS ds2x
+FROM view4 AS v4, ds2 AS ds2
+WHERE v4.x /*+ indexnl */ = ds2.x ORDER BY v4x, ds2x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/function-on-pk/function-on-pk-01.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/function-on-pk/function-on-pk-01.sqlpp
new file mode 100644
index 0000000..0f4c817
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/function-on-pk/function-on-pk-01.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds1(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+// test that primary index lookup is not performed and a dataset scan is 
performed
+SELECT a, b FROM ds1 WHERE id + 1 = 3;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/function-on-pk/function-on-pk-02.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/function-on-pk/function-on-pk-02.sqlpp
new file mode 100644
index 0000000..ce195ec
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/queries/btree-index-selection/function-on-pk/function-on-pk-02.sqlpp
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds1(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+// test that primary index lookup is not performed and a dataset scan is 
performed
+SELECT a, b FROM ds1 WHERE 3 = id + 1;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-01.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-01.plan
new file mode 100644
index 0000000..0dcfc44
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-01.plan
@@ -0,0 +1,16 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$66(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$66(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ASSIGN  |PARTITIONED|
+                  -- STREAM_SELECT  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds1)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-02.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-02.plan
new file mode 100644
index 0000000..7997aad
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-02.plan
@@ -0,0 +1,23 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$66(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$66(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ASSIGN  |PARTITIONED|
+                  -- STREAM_SELECT  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- BTREE_SEARCH (test.ds2.ds2)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- STABLE_SORT [$$72(ASC)]  |PARTITIONED|
+                                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                  -- STREAM_PROJECT  |PARTITIONED|
+                                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                      -- BTREE_SEARCH (test.ds2.idx2)  
|PARTITIONED|
+                                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                          -- ASSIGN  |PARTITIONED|
+                                            -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-03.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-03.plan
new file mode 100644
index 0000000..d1264cb
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-03.plan
@@ -0,0 +1,16 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$66(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$66(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STREAM_PROJECT  |PARTITIONED|
+                -- ASSIGN  |PARTITIONED|
+                  -- STREAM_SELECT  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ASSIGN  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds3)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-04.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-04.plan
new file mode 100644
index 0000000..3582cf3
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-04.plan
@@ -0,0 +1,12 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$21(ASC) ]  |PARTITIONED|
+          -- STREAM_SELECT  |PARTITIONED|
+            -- STREAM_PROJECT  |PARTITIONED|
+              -- ASSIGN  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- DATASOURCE_SCAN (test.ds3)  |PARTITIONED|
+                    -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                      -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-05.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-05.plan
new file mode 100644
index 0000000..6285f16
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-05.plan
@@ -0,0 +1,27 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$122(ASC), $$123(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$122(ASC), $$123(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- STREAM_SELECT  |PARTITIONED|
+                -- STREAM_PROJECT  |PARTITIONED|
+                  -- ASSIGN  |PARTITIONED|
+                    -- STREAM_PROJECT  |PARTITIONED|
+                      -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                        -- BTREE_SEARCH (test.ds2.ds2)  |PARTITIONED|
+                          -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                            -- STABLE_SORT [$$139(ASC)]  |PARTITIONED|
+                              -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                -- STREAM_PROJECT  |PARTITIONED|
+                                  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                                    -- BTREE_SEARCH (test.ds2.idx2)  
|PARTITIONED|
+                                      -- BROADCAST_EXCHANGE  |PARTITIONED|
+                                        -- STREAM_PROJECT  |PARTITIONED|
+                                          -- ASSIGN  |PARTITIONED|
+                                            -- STREAM_PROJECT  |PARTITIONED|
+                                              -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
+                                                -- DATASOURCE_SCAN (test.ds4)  
|PARTITIONED|
+                                                  -- ONE_TO_ONE_EXCHANGE  
|PARTITIONED|
+                                                    -- EMPTY_TUPLE_SOURCE  
|PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-06.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-06.plan
new file mode 100644
index 0000000..510ccca
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-06.plan
@@ -0,0 +1,24 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$122(ASC), $$123(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$122(ASC), $$123(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- HYBRID_HASH_JOIN [$$122][$$123]  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$122]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds4)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$123]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds3)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-07.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-07.plan
new file mode 100644
index 0000000..1577585
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-07.plan
@@ -0,0 +1,24 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$122(ASC), $$123(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$122(ASC), $$123(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- HYBRID_HASH_JOIN [$$122][$$123]  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$122]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds4)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$123]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds1)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-08.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-08.plan
new file mode 100644
index 0000000..1577585
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-08.plan
@@ -0,0 +1,24 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$122(ASC), $$123(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$122(ASC), $$123(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- HYBRID_HASH_JOIN [$$122][$$123]  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$122]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds4)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$123]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds1)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-09.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-09.plan
new file mode 100644
index 0000000..d60ee1e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/cast-default-null/cast-default-null-09.plan
@@ -0,0 +1,24 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- SORT_MERGE_EXCHANGE [$$84(ASC), $$85(ASC) ]  |PARTITIONED|
+          -- STABLE_SORT [$$84(ASC), $$85(ASC)]  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- HYBRID_HASH_JOIN [$$84][$$85]  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$84]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds4)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
+                -- HASH_PARTITION_EXCHANGE [$$85]  |PARTITIONED|
+                  -- STREAM_PROJECT  |PARTITIONED|
+                    -- ASSIGN  |PARTITIONED|
+                      -- STREAM_PROJECT  |PARTITIONED|
+                        -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                          -- DATASOURCE_SCAN (test.ds2)  |PARTITIONED|
+                            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                              -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/function-on-pk/function-on-pk-01.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/function-on-pk/function-on-pk-01.plan
new file mode 100644
index 0000000..f621777
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/function-on-pk/function-on-pk-01.plan
@@ -0,0 +1,10 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- STREAM_SELECT  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- DATASOURCE_SCAN (test.ds1)  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/function-on-pk/function-on-pk-02.plan
 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/function-on-pk/function-on-pk-02.plan
new file mode 100644
index 0000000..f621777
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/optimizerts/results/btree-index-selection/function-on-pk/function-on-pk-02.plan
@@ -0,0 +1,10 @@
+-- DISTRIBUTE_RESULT  |PARTITIONED|
+  -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+    -- STREAM_PROJECT  |PARTITIONED|
+      -- ASSIGN  |PARTITIONED|
+        -- STREAM_PROJECT  |PARTITIONED|
+          -- STREAM_SELECT  |PARTITIONED|
+            -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+              -- DATASOURCE_SCAN (test.ds1)  |PARTITIONED|
+                -- ONE_TO_ONE_EXCHANGE  |PARTITIONED|
+                  -- EMPTY_TUPLE_SOURCE  |PARTITIONED|
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.01.ddl.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.01.ddl.sqlpp
new file mode 100644
index 0000000..e354d1d
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.01.ddl.sqlpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+DROP DATAVERSE test IF EXISTS;
+CREATE DATAVERSE test;
+USE test;
+
+CREATE DATASET ds1(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds2(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds3(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds4(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+CREATE DATASET ds5(id int not unknown, a string, b int) OPEN TYPE PRIMARY KEY 
id;
+
+CREATE INDEX idx1 ON ds1(x: int);
+CREATE INDEX idx2 ON ds2(x: int) CAST (DEFAULT NULL);
+CREATE INDEX idx3 ON ds3(x: int) CAST (DEFAULT NULL);
+
+
+CREATE VIEW view1(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds1;
+CREATE VIEW view2(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds2;
+CREATE VIEW view3(id int, x string, y int) DEFAULT NULL AS SELECT id, x, y 
FROM ds3;
+CREATE VIEW view4(id int, x int, y int) DEFAULT NULL AS SELECT id, x, y FROM 
ds4;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.02.update.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.02.update.sqlpp
new file mode 100644
index 0000000..d47aa46
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.02.update.sqlpp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+USE test;
+
+INSERT INTO ds1 [
+{"id": 1, "a": "s1", "b": 1, "x": 1, "y": 2},
+{"id": 2, "a": "s2", "b": 2, "x": 2, "y": 1},
+{"id": 3, "a": "s3", "b": 3, "x": 1.1, "y": 2.1},
+{"id": 4, "a": "s4", "b": 4, "x": 2.1, "y": 1.1},
+{"id": 5, "a": "s5", "b": 5,           "y": 1.1},
+{"id": 6, "a": "s6", "b": 6, "x": 3, "y": 3}
+];
+
+INSERT INTO ds2 [
+{"id": 1, "a": "s1", "b": 1, "x": 1, "y": 2},
+{"id": 2, "a": "s2", "b": 2, "x": 2, "y": 1},
+{"id": 3, "a": "s3", "b": 3, "x": 1.1, "y": 2.1},
+{"id": 4, "a": "s4", "b": 4, "x": 2.1, "y": 1.1},
+{"id": 5, "a": "s5", "b": 5,           "y": 1.1},
+{"id": 6, "a": "s6", "b": 6, "x": 33, "y": 3}
+];
+
+INSERT INTO ds3 [
+{"id": 1, "a": "s1", "b": 1, "x": 1, "y": 2},
+{"id": 2, "a": "s2", "b": 2, "x": 2, "y": 1},
+{"id": 3, "a": "s3", "b": 3, "x": 1.1, "y": 2.1},
+{"id": 4, "a": "s4", "b": 4, "x": 2.1, "y": 1.1},
+{"id": 5, "a": "s5", "b": 5,           "y": 1.1},
+{"id": 6, "a": "s6", "b": 6, "x": 333, "y": 3}
+];
+
+INSERT INTO ds4 [
+{"id": 1, "a": "s1", "b": 1, "x": 1, "y": 2},
+{"id": 2, "a": "s2", "b": 2, "x": 2, "y": 1},
+{"id": 3, "a": "s3", "b": 3, "x": 1.1, "y": 2.1},
+{"id": 4, "a": "s4", "b": 4, "x": 2.1, "y": 1.1},
+{"id": 5, "a": "s5", "b": 5,           "y": 1.1},
+{"id": 6, "a": "s6", "b": 6, "x": 3333, "y": 3}
+];
+
+INSERT INTO ds5 [
+{"id": 1, "a": "s1", "b": 1, "x": 1, "y": 2},
+{"id": 2, "a": "s2", "b": 2, "x": 2, "y": 1},
+{"id": 3, "a": "s3", "b": 3, "x": 1.1, "y": 2.1},
+{"id": 4, "a": "s4", "b": 4, "x": 2.1, "y": 1.1},
+{"id": 5, "a": "s5", "b": 5,           "y": 1.1},
+{"id": 6, "a": "s6", "b": 6, "x": 33333, "y": 3}
+];
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.03.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.03.query.sqlpp
new file mode 100644
index 0000000..56ad29e
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.03.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx1 on x is not used since idx1 does not have the CAST modifier 
and the field x has cast
+SELECT id, x, y FROM view1 WHERE x <= 1 ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.04.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.04.query.sqlpp
new file mode 100644
index 0000000..f9db494
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.04.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx2 on x is used since idx2 has the CAST modifier and the field 
x has cast
+SELECT id, x, y FROM view2 WHERE x <= 1 ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.05.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.05.query.sqlpp
new file mode 100644
index 0000000..5180871
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.05.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx3 on x is not used since idx3 has the CAST modifier on int and 
the field x has cast as string
+SELECT id, x, y FROM view3 WHERE x <= "1" ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.06.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.06.query.sqlpp
new file mode 100644
index 0000000..9508ece
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.06.query.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx3 on x is not used since idx3 has the CAST modifier and the 
field x does not have cast
+SELECT id, x, y FROM ds3 WHERE x <= 1 ORDER BY id;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.07.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.07.query.sqlpp
new file mode 100644
index 0000000..103b285
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.07.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx2 on view2(x) is used. both v4.x and v2.x are int and idx2 is 
on x as int.
+SELECT v4.x AS v4x, v2.x AS v2x
+FROM view4 AS v4, view2 AS v2
+WHERE v4.x /*+ indexnl */ = v2.x ORDER BY v4x, v2x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.08.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.08.query.sqlpp
new file mode 100644
index 0000000..f818b2b
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.08.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx3 on view3(x) is not used since v4.x is int, v3.x is string
+SELECT v4.x AS v4x, v3.x AS v3x
+FROM view4 AS v4, view3 AS v3
+WHERE v4.x /*+ indexnl */ = v3.x ORDER BY v4x, v3x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.09.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.09.query.sqlpp
new file mode 100644
index 0000000..3aef10a
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.09.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx1 is not used even though v4.x is int, v1.x is int because 
idx1 does not have CAST modifier.
+SELECT v4.x AS v4x, v1.x AS v1x
+FROM view4 AS v4, view1 AS v1
+WHERE v4.x /*+ indexnl */ = v1.x ORDER BY v4x, v1x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.10.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.10.query.sqlpp
new file mode 100644
index 0000000..3aef10a
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.10.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx1 is not used even though v4.x is int, v1.x is int because 
idx1 does not have CAST modifier.
+SELECT v4.x AS v4x, v1.x AS v1x
+FROM view4 AS v4, view1 AS v1
+WHERE v4.x /*+ indexnl */ = v1.x ORDER BY v4x, v1x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.11.query.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.11.query.sqlpp
new file mode 100644
index 0000000..4da0b66
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/index-selection/cast-default-null/cast-default-null.11.query.sqlpp
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+USE test;
+// test that idx2 is not used because v4.x is int-default-null and ds2.x is 
int.
+SELECT v4.x AS v4x, ds2.x AS ds2x
+FROM view4 AS v4, ds2 AS ds2
+WHERE v4.x /*+ indexnl */ = ds2.x ORDER BY v4x, ds2x;
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.03.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.03.adm
new file mode 100644
index 0000000..6b56041
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.03.adm
@@ -0,0 +1,2 @@
+{ "id": 1, "x": 1, "y": 2 }
+{ "id": 3, "x": 1, "y": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.04.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.04.adm
new file mode 100644
index 0000000..6b56041
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.04.adm
@@ -0,0 +1,2 @@
+{ "id": 1, "x": 1, "y": 2 }
+{ "id": 3, "x": 1, "y": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.05.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.05.adm
new file mode 100644
index 0000000..140eea9
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.05.adm
@@ -0,0 +1 @@
+{ "id": 1, "x": "1", "y": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.06.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.06.adm
new file mode 100644
index 0000000..38e6954
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.06.adm
@@ -0,0 +1 @@
+{ "id": 1, "x": 1, "y": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.07.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.07.adm
new file mode 100644
index 0000000..a975f87
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.07.adm
@@ -0,0 +1,8 @@
+{ "v4x": 1, "v2x": 1 }
+{ "v4x": 1, "v2x": 1 }
+{ "v4x": 1, "v2x": 1 }
+{ "v4x": 1, "v2x": 1 }
+{ "v4x": 2, "v2x": 2 }
+{ "v4x": 2, "v2x": 2 }
+{ "v4x": 2, "v2x": 2 }
+{ "v4x": 2, "v2x": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.08.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.08.adm
new file mode 100644
index 0000000..e69de29
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.09.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.09.adm
new file mode 100644
index 0000000..e2015b1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.09.adm
@@ -0,0 +1,8 @@
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 2, "v1x": 2 }
+{ "v4x": 2, "v1x": 2 }
+{ "v4x": 2, "v1x": 2 }
+{ "v4x": 2, "v1x": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.10.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.10.adm
new file mode 100644
index 0000000..e2015b1
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.10.adm
@@ -0,0 +1,8 @@
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 1, "v1x": 1 }
+{ "v4x": 2, "v1x": 2 }
+{ "v4x": 2, "v1x": 2 }
+{ "v4x": 2, "v1x": 2 }
+{ "v4x": 2, "v1x": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.11.adm
 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.11.adm
new file mode 100644
index 0000000..8d727bf
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/results/index-selection/cast-default-null/cast-default-null.11.adm
@@ -0,0 +1,4 @@
+{ "v4x": 1, "ds2x": 1 }
+{ "v4x": 1, "ds2x": 1 }
+{ "v4x": 2, "ds2x": 2 }
+{ "v4x": 2, "ds2x": 2 }
\ No newline at end of file
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index a79bbf5..b992c4c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -6529,6 +6529,11 @@
         <output-dir compare="Text">word-jaccard-inline</output-dir>
       </compilation-unit>
     </test-case>
+    <test-case FilePath="index-selection">
+      <compilation-unit name="cast-default-null">
+        <output-dir compare="Text">cast-default-null</output-dir>
+      </compilation-unit>
+    </test-case>
   </test-group>
   <test-group name="inverted-index-join-noeqjoin">
     <test-case FilePath="inverted-index-join-noeqjoin">

Reply via email to