You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@asterixdb.apache.org by AsterixDB Code Review <do...@asterix-gerrit.ics.uci.edu> on 2024/07/26 00:32:25 UTC

Change in asterixdb[master]: heterogeneous index

From Shahrzad Haji Amin Shirazi <sh...@ucr.edu>:

Shahrzad Haji Amin Shirazi has uploaded this change for review. ( https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18522 )


Change subject: heterogeneous index
......................................................................

heterogeneous index

The following commits from your working branch will be included:

commit c863b9e55a99e8d574e94874968cef79a1064bbe
Author: Shahrzad shirazi <sh...@ucr.edu>
Date:   Thu Jul 25 17:30:59 2024 -0700

    heterogeneous index

Change-Id: I03b5edfbc304cdb9f36e2b382050781811a14759
---
M asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AbstractIntroduceAccessMethodRule.java
M asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
M asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/KeyFieldTypeUtil.java
M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/am/AccessMethodUtils.java
M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/ValidateUtil.java
M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
7 files changed, 225 insertions(+), 25 deletions(-)



  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb refs/changes/22/18522/1

diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
index dd8f630..b6b2f17 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/IntroduceSecondaryIndexInsertDeleteRule.java
@@ -860,7 +860,7 @@
 
                 AbstractFunctionCallExpression theFieldAccessFunc;
                 LogicalVariable fieldVar = context.newVar();
-                if (fieldType == null) {
+                if (fieldType == null && skType != BuiltinType.ANY) {
                     // Open field. must prevent inlining to maintain the cast before the primaryOp and
                     // make handling of records with incorrect value type for this field easier and cleaner
                     context.addNotToBeInlinedVar(fieldVar);
@@ -906,6 +906,9 @@
         FunctionIdentifier skFun = null;
         IAObject fmtArg = null;
         Pair<FunctionIdentifier, IAObject> castExpr;
+        if(skType==BuiltinType.ANY) {
+            return new IndexFieldId(skSrc, skName, skType.getTypeTag(), skFun, fmtArg);
+        }
         if (fieldType == null) {
             // open field
             castExpr = getCastExpression(index, skType, srcLoc);
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 b5041f0..248ab7e 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
@@ -626,6 +626,9 @@
                 Index.getNonNullableType(type2).first.getTypeTag(), useListDomain)) {
             return true;
         }
+        if (type2 == BuiltinType.ANY) {
+            return true;
+        }
         return ATypeHierarchy.canPromote(Index.getNonNullableType(type1).first.getTypeTag(),
                 Index.getNonNullableType(type2).first.getTypeTag());
     }
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 1ff90c6..840a835 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
@@ -1132,21 +1132,202 @@
             return secondaryIndexUnnestOp;
         }
     }
+    private static void splitIntoConjuncts(ILogicalExpression condition, List<Mutable<ILogicalExpression>> conjuncts) {
+        if (condition.getExpressionTag() != LogicalExpressionTag.FUNCTION_CALL) {
+            return;
+        }
+        AbstractFunctionCallExpression funcExpr = (AbstractFunctionCallExpression) condition;
+        if (funcExpr.getFunctionIdentifier() == BuiltinFunctions.AND) {
+            for (Mutable<ILogicalExpression> arg : funcExpr.getArguments()) {
+                splitIntoConjuncts(arg.getValue(), conjuncts);
+            }
+        } else {
+            conjuncts.add(new MutableObject<>(condition));
+        }
+    }
 
-    private static AbstractUnnestMapOperator createFinalNonIndexOnlySearchPlan(Dataset dataset,
+    protected static ILogicalExpression filterCondition(ILogicalExpression condition, List<LogicalVariable> pkVarsFromSIdxUnnestMapOp) {
+        List<Mutable<ILogicalExpression>> conjuncts = new ArrayList<>();
+        List<Mutable<ILogicalExpression>> filteredConjuncts = new ArrayList<>();
+
+        if (containsOnlyAllowedVariables(condition, pkVarsFromSIdxUnnestMapOp)) {
+            return condition;
+        }
+        splitIntoConjuncts(condition, conjuncts);
+
+        for (Mutable<ILogicalExpression> conjunct : conjuncts) {
+            if (containsOnlyAllowedVariables(conjunct.getValue(), pkVarsFromSIdxUnnestMapOp)) {
+                filteredConjuncts.add(conjunct);
+            }
+        }
+
+        if (filteredConjuncts.size() == 1) {
+            return filteredConjuncts.get(0).getValue();
+        } else if (!filteredConjuncts.isEmpty()) {
+            //seems like only conditions with and will use the index search(?) if not we can get this from the original condition
+            ScalarFunctionCallExpression combinedCondition = new ScalarFunctionCallExpression(BuiltinFunctions
+                    .getBuiltinFunctionInfo(BuiltinFunctions.AND));
+            combinedCondition.getArguments().addAll(filteredConjuncts);
+            combinedCondition.setSourceLocation(condition.getSourceLocation());
+            return combinedCondition;
+        } else {
+            return null;
+        }
+    }
+
+    private static boolean containsOnlyAllowedVariables(ILogicalExpression expression, List<LogicalVariable> allowedVars) {
+        Set<LogicalVariable> usedVars = new HashSet<>();
+        expression.getUsedVariables(usedVars);
+        for (LogicalVariable var : usedVars) {
+            if (!allowedVars.contains(var)) {
+                return false;
+            }
+        }
+        return true;
+    }
+    private static AbstractUnnestMapOperator createFinalNonIndexOnlySearchPlan( Dataset dataset,
             ILogicalOperator inputOp, IOptimizationContext context, boolean sortPrimaryKeys, boolean retainInput,
             boolean retainMissing, boolean requiresBroadcast, boolean requiresDistinct,
             List<LogicalVariable> primaryKeyVars, List<LogicalVariable> primaryIndexUnnestVars,
             List<LogicalVariable> auxDistinctVars, List<Object> primaryIndexOutputTypes,
-            IAlgebricksConstantValue leftOuterMissingValue) throws AlgebricksException {
-        SourceLocation sourceLoc = inputOp.getSourceLocation();
+            IAlgebricksConstantValue leftOuterMissingValue,
+            ARecordType recordType, ARecordType metaRecordType, OptimizableOperatorSubTree subTree,
+            Index secondaryIndex, Mutable<ILogicalOperator> topOpRef, List<Mutable<ILogicalOperator>> assignsBeforeTopOpRef,
+            Mutable<ILogicalExpression> conditionRef) throws AlgebricksException {
 
+        SourceLocation sourceLoc = inputOp.getSourceLocation();
         // Sanity check: requiresDistinct and sortPrimaryKeys are mutually exclusive.
         if (requiresDistinct && sortPrimaryKeys) {
             throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE, sourceLoc,
                     "Non-index search plan " + "cannot include a DISTINCT and an ORDER.");
         }
+        ILogicalOperator op=null;
+        Index.ValueIndexDetails secondaryIndexDetails = (Index.ValueIndexDetails) secondaryIndex.getIndexDetails();
+        List<List<String>> chosenIndexFieldNames = secondaryIndexDetails.getKeyFieldNames();
+        List<IAType> secodaryKeysType = secondaryIndexDetails.getKeyFieldTypes();
+        IndexType idxType = secondaryIndex.getIndexType();
+        if(secodaryKeysType.contains(BuiltinType.ANY) && idxType != IndexType.RTREE) {
+            List<LogicalVariable> skVarsFromSIdxUnnestMap = AccessMethodUtils.getKeyVarsFromSecondaryUnnestMap(dataset,
+                    recordType, metaRecordType, inputOp, secondaryIndex, SecondaryUnnestMapOutputVarType.SECONDARY_KEY);
+            List<LogicalVariable> usedVarsInTopOp = new ArrayList<>();
+            List<LogicalVariable> uniqueUsedVarsInTopOp = new ArrayList<>();
+            List<LogicalVariable> producedVarsInAssignsBeforeTopOp = new ArrayList<>();
+            List<LogicalVariable> liveVarsInSubTreeRootOp = new ArrayList<>();
+            List<LogicalVariable> usedVarsAfterTopOp = new ArrayList<>();
+            List<LogicalVariable> varsTmpList = new ArrayList<>();
 
+            LinkedHashMap<LogicalVariable, LogicalVariable> origVarToSIdxUnnestMapOpVarMap = new LinkedHashMap<>();
+
+            VariableUtilities.getUsedVariables(topOpRef.getValue(), usedVarsInTopOp);
+            VariableUtilities.getLiveVariables(subTree.getRootRef().getValue(), liveVarsInSubTreeRootOp);
+            for (Iterator<LogicalVariable> iterator = usedVarsInTopOp.iterator(); iterator.hasNext(); ) {
+                LogicalVariable v = iterator.next();
+                if (!liveVarsInSubTreeRootOp.contains(v)) {
+                    iterator.remove();
+                }
+            }
+            copyVarsToAnotherList(usedVarsInTopOp, uniqueUsedVarsInTopOp);
+
+            if (assignsBeforeTopOpRef != null && !assignsBeforeTopOpRef.isEmpty()) {
+                for (int i = 0; i < assignsBeforeTopOpRef.size(); i++) {
+                    ILogicalOperator assignBeforeTopOp = assignsBeforeTopOpRef.get(i).getValue();
+                    varsTmpList.clear();
+                    VariableUtilities.getProducedVariables(assignBeforeTopOp, varsTmpList);
+                    copyVarsToAnotherList(varsTmpList, producedVarsInAssignsBeforeTopOp);
+                }
+            }
+
+            AssignOperator constAssignOp;
+            List<LogicalVariable> constAssignVars = new ArrayList<>();
+            List<Mutable<ILogicalExpression>> constAssignExprs = new ArrayList<>();
+
+            boolean constantAssignVarUsedInTopOp = false;
+            if (assignsBeforeTopOpRef != null && !assignsBeforeTopOpRef.isEmpty()) {
+                for (int i = assignsBeforeTopOpRef.size() - 1; i >= 0; i--) {
+                    AssignOperator tmpOp = (AssignOperator) assignsBeforeTopOpRef.get(i).getValue();
+                    List<LogicalVariable> tmpAssignVars = tmpOp.getVariables();
+                    List<Mutable<ILogicalExpression>> tmpAsssignExprs = tmpOp.getExpressions();
+                    Iterator<LogicalVariable> varIt = tmpAssignVars.iterator();
+                    Iterator<Mutable<ILogicalExpression>> exprIt = tmpAsssignExprs.iterator();
+                    while (exprIt.hasNext()) {
+                        Mutable<ILogicalExpression> tmpExpr = exprIt.next();
+                        LogicalVariable tmpVar = varIt.next();
+                        if (tmpExpr.getValue().getExpressionTag() == LogicalExpressionTag.CONSTANT) {
+                            constAssignVars.add(tmpVar);
+                            constAssignExprs.add(tmpExpr);
+                            varIt.remove();
+                            exprIt.remove();
+                        }
+                    }
+                }
+
+                if (!constAssignVars.isEmpty()) {
+                    for (LogicalVariable v : constAssignVars) {
+                        if (usedVarsInTopOp.contains(v)) {
+                            constantAssignVarUsedInTopOp = true;
+                            break;
+                        }
+                    }
+                    constAssignOp = new AssignOperator(constAssignVars, constAssignExprs);
+                    constAssignOp.setSourceLocation(sourceLoc);
+                    if (constantAssignVarUsedInTopOp) {
+                        constAssignOp.getInputs().add(new MutableObject(inputOp));
+                        constAssignOp.setExecutionMode(ExecutionMode.PARTITIONED);
+                    }
+                }
+            }
+
+            for (LogicalVariable tVar : usedVarsAfterTopOp) {
+
+                // Should be either used in the condition or a composite index field that is not used in the condition.
+                if (!usedVarsInTopOp.contains(tVar) && !producedVarsInAssignsBeforeTopOp.contains(tVar)) {
+                    continue;
+                }
+                int sIndexIdx = chosenIndexFieldNames.indexOf(subTree.getVarsToFieldNameMap().get(tVar));
+                if (sIndexIdx == -1) {
+                    continue;
+                }
+                origVarToSIdxUnnestMapOpVarMap.put(tVar, skVarsFromSIdxUnnestMap.get(sIndexIdx));
+            }
+
+            List<LogicalVariable> varsUsedInTopOpButNotAfterwards = new ArrayList<>();
+            copyVarsToAnotherList(uniqueUsedVarsInTopOp, varsUsedInTopOpButNotAfterwards);
+            varsUsedInTopOpButNotAfterwards.removeAll(usedVarsAfterTopOp);
+            if (idxType == IndexType.BTREE) {
+                for (LogicalVariable v : varsUsedInTopOpButNotAfterwards) {
+                    int sIndexIdx = chosenIndexFieldNames.indexOf(subTree.getVarsToFieldNameMap().get(v));
+                    if (sIndexIdx == -1) {
+                        continue;
+                    }
+                    origVarToSIdxUnnestMapOpVarMap.put(v, skVarsFromSIdxUnnestMap.get(sIndexIdx));
+                }
+            }
+
+            SelectOperator newSelectOpInRightPath;
+            if (uniqueUsedVarsInTopOp.size() > 1 || IndexUtil.includesUnknowns(secondaryIndex)) {
+                List<LogicalVariable> list = new ArrayList<LogicalVariable>(origVarToSIdxUnnestMapOpVarMap.keySet());
+
+                ILogicalExpression conditionRefExpr2 = filterCondition(conditionRef.getValue().cloneExpression(), list);
+                if(conditionRefExpr2 != null) {
+                    newSelectOpInRightPath =
+                            retainMissing
+                                    ? new SelectOperator(new MutableObject<>(conditionRefExpr2), leftOuterMissingValue,
+                                    null)
+                                    : new SelectOperator(new MutableObject<>(conditionRefExpr2));
+                    newSelectOpInRightPath.setSourceLocation(conditionRefExpr2.getSourceLocation());
+                    newSelectOpInRightPath.getInputs().add(new MutableObject(inputOp));
+                    VariableUtilities.substituteVariables(newSelectOpInRightPath, origVarToSIdxUnnestMapOpVarMap, context);
+                    newSelectOpInRightPath.setExecutionMode(ExecutionMode.PARTITIONED);
+                    context.computeAndSetTypeEnvironmentForOperator(newSelectOpInRightPath);
+                    op = newSelectOpInRightPath;
+
+
+                }
+            }
+        }
+        if(op == null){
+            op = inputOp;
+        }
         // If we have an array index, then we must only give unique keys to our primary-index scan.
         DistinctOperator distinct = null;
         if (requiresDistinct) {
@@ -1165,7 +1346,7 @@
             }
             distinct = new DistinctOperator(distinctExprs);
             distinct.setSourceLocation(sourceLoc);
-            distinct.getInputs().add(new MutableObject<>(inputOp));
+            distinct.getInputs().add(new MutableObject<>(op));
             distinct.setExecutionMode(ExecutionMode.LOCAL);
             context.computeAndSetTypeEnvironmentForOperator(distinct);
         }
@@ -1182,7 +1363,7 @@
                 order.getOrderExpressions().add(new Pair<>(OrderOperator.ASC_ORDER, vRef));
             }
             // The secondary-index search feeds into the sort.
-            order.getInputs().add(new MutableObject<>(inputOp));
+            order.getInputs().add(new MutableObject<>(op));
             order.setExecutionMode(ExecutionMode.LOCAL);
             context.computeAndSetTypeEnvironmentForOperator(order);
         }
@@ -1196,13 +1377,15 @@
         } else if (sortPrimaryKeys) {
             primaryIndexUnnestMapOp.getInputs().add(new MutableObject<>(order));
         } else {
-            primaryIndexUnnestMapOp.getInputs().add(new MutableObject<>(inputOp));
+            primaryIndexUnnestMapOp.getInputs().add(new MutableObject<>(op));
         }
         context.computeAndSetTypeEnvironmentForOperator(primaryIndexUnnestMapOp);
         primaryIndexUnnestMapOp.setExecutionMode(ExecutionMode.PARTITIONED);
         return primaryIndexUnnestMapOp;
     }
 
+
+
     private static ILogicalOperator createFinalIndexOnlySearchPlan(List<Mutable<ILogicalOperator>> afterTopOpRefs,
             Mutable<ILogicalOperator> topOpRef, Mutable<ILogicalExpression> conditionRef,
             List<Mutable<ILogicalOperator>> assignsBeforeTopOpRef, Dataset dataset, ARecordType recordType,
@@ -1833,7 +2016,7 @@
 
             return createFinalNonIndexOnlySearchPlan(dataset, inputOp, context, !isArrayIndex && sortPrimaryKeys,
                     retainInput, retainMissing, requiresBroadcast, isArrayIndex, pkVarsFromSIdxUnnestMapOp,
-                    primaryIndexUnnestVars, joinPKVars, primaryIndexOutputTypes, leftOuterMissingValue);
+                    primaryIndexUnnestVars, joinPKVars, primaryIndexOutputTypes, leftOuterMissingValue,recordType, metaRecordType,indexSubTree,secondaryIndex,topOpRef,assignsBeforeTopOpRef,conditionRef);
         } else if (!isArrayIndex) {
             // Index-only plan case: creates a UNIONALL operator that has two paths after the secondary unnest-map op,
             // and returns it.
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/ValidateUtil.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/ValidateUtil.java
index 34976b6..fa6d65c 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/ValidateUtil.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/util/ValidateUtil.java
@@ -276,6 +276,8 @@
                     case UUID:
                     case YEARMONTHDURATION:
                     case DAYTIMEDURATION:
+                    case ANY:
+
                         break;
                     default:
                         throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc,
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
index 0c736a2..977b41c 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/QueryTranslator.java
@@ -1510,12 +1510,6 @@
                     }
 
                     if (fieldTypePrime == null) {
-                        if (projectPath != null) {
-                            String fieldName = LogRedactionUtil.userData(RecordUtil.toFullyQualifiedName(projectPath));
-                            throw new CompilationException(ErrorCode.COMPILATION_ERROR,
-                                    indexedElement.getSourceLocation(),
-                                    "cannot find type of field '" + fieldName + "'");
-                        }
                         // projectPath == null should only be the case with array index having UNNESTs only
                         if (indexedElement.hasUnnest()) {
                             List<List<String>> unnestList = indexedElement.getUnnestList();
@@ -1525,8 +1519,7 @@
                                     indexedElement.getSourceLocation(),
                                     "cannot find type of elements of field '" + fieldName + "'");
                         }
-                        throw new CompilationException(ErrorCode.COMPILATION_ILLEGAL_STATE,
-                                indexedElement.getSourceLocation(), "cannot find type of field");
+                        fieldTypePrime = BuiltinType.ANY;
                     }
                     validateIndexFieldType(indexType, fieldTypePrime, projectPath, indexedElement.getSourceLocation());
 
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
index 453ccc1..149fa83 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/entitytupletranslators/IndexTupleTranslator.java
@@ -370,8 +370,8 @@
                         projectTypeNullable = inputTypeNullable;
                         projectTypeMissable = inputTypeMissable;
                     } else if (inputTypePrime == null ||
-                    // handle special case of the empty field name in
-                    // ExternalIndexingOperations.FILE_INDEX_FIELD_NAMES
+                            // handle special case of the empty field name in
+                            // ExternalIndexingOperations.FILE_INDEX_FIELD_NAMES
                             (projectPath.size() == 1 && projectPath.get(0).isEmpty())) {
                         projectTypePrime = null; // ANY
                         projectTypeNullable = projectTypeMissable = true;
@@ -381,16 +381,13 @@
                         }
                         Triple<IAType, Boolean, Boolean> projectTypeResult =
                                 KeyFieldTypeUtil.getKeyProjectType((ARecordType) inputTypePrime, projectPath, null);
-                        if (projectTypeResult == null) {
-                            throw new AsterixException(ErrorCode.METADATA_ERROR, projectPath.toString());
-                        }
                         projectTypePrime = projectTypeResult.first;
                         projectTypeNullable = inputTypeNullable || projectTypeResult.second;
                         projectTypeMissable = inputTypeMissable || projectTypeResult.third;
                     }
                     IAType projectType = projectTypePrime == null ? null
                             : KeyFieldTypeUtil.makeUnknownableType(projectTypePrime, projectTypeNullable,
-                                    projectTypeMissable);
+                            projectTypeMissable);
 
                     projectTypeList.add(projectType);
                 }
diff --git a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/KeyFieldTypeUtil.java b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/KeyFieldTypeUtil.java
index fd20b3c..de75d1a 100644
--- a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/KeyFieldTypeUtil.java
+++ b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/utils/KeyFieldTypeUtil.java
@@ -33,6 +33,7 @@
 import org.apache.asterix.om.types.ATypeTag;
 import org.apache.asterix.om.types.AUnionType;
 import org.apache.asterix.om.types.AbstractCollectionType;
+import org.apache.asterix.om.types.BuiltinType;
 import org.apache.asterix.om.types.IAType;
 import org.apache.asterix.om.utils.NonTaggedFormatUtil;
 import org.apache.asterix.om.utils.RecordUtil;
@@ -269,7 +270,7 @@
             }
             ARecordType itemRecordType = (ARecordType) itemType;
             Triple<IAType, Boolean, Boolean> fieldTypeResult = getKeyProjectType(itemRecordType, unnestPath, sourceLoc);
-            if (fieldTypeResult == null) {
+            if (fieldTypeResult.first == BuiltinType.ANY) {
                 return null;
             }
             IAType fieldType = fieldTypeResult.first;
@@ -279,7 +280,7 @@
             if (!fieldType.getTypeTag().isListType()) {
                 throw new CompilationException(ErrorCode.TYPE_MISMATCH_GENERIC,
                         sourceLoc, ExceptionUtil.toExpectedTypeString(new byte[] {
-                                ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG, ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG }),
+                        ATypeTag.SERIALIZED_ORDEREDLIST_TYPE_TAG, ATypeTag.SERIALIZED_UNORDEREDLIST_TYPE_TAG }),
                         fieldType);
             }
             AbstractCollectionType fieldListType = (AbstractCollectionType) fieldType;
@@ -320,7 +321,8 @@
             if (fieldType == null) {
                 if (itemRecordType.isOpen()) {
                     // open record type and we couldn't find the field -> ok.
-                    return null;
+                    itemType= BuiltinType.ANY;
+                    return new Triple<>(itemType, itemTypeNullable, itemTypeMissable);
                 } else {
                     // closed record type and we couldn't find the field -> error.
                     throw new CompilationException(ErrorCode.COMPILATION_FIELD_NOT_FOUND, sourceLoc,

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/18522
To unsubscribe, or for help writing mail filters, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Change-Id: I03b5edfbc304cdb9f36e2b382050781811a14759
Gerrit-Change-Number: 18522
Gerrit-PatchSet: 1
Gerrit-Owner: Shahrzad Haji Amin Shirazi <sh...@ucr.edu>
Gerrit-MessageType: newchange