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">