Example #1
0
        private static ExprNode[] GetInNodeSetExpressions(ExprInNode inNode)
        {
            var setExpressions = new ExprNode[inNode.ChildNodes.Length - 1];
            var count = 0;
            for (var i = 1; i < inNode.ChildNodes.Length; i++) {
                setExpressions[count++] = inNode.ChildNodes[i];
            }

            return setExpressions;
        }
Example #2
0
        private static void AnalyzeInNodeSingleIndex(ExprInNode inNode, QueryGraph queryGraph)
        {
            if (!(inNode.ChildNodes[0] is ExprIdentNode))
            {
                return;
            }
            var testIdent      = (ExprIdentNode)inNode.ChildNodes[0];
            var testIdentClass = TypeHelper.GetBoxedType(testIdent.ExprEvaluator.ReturnType);
            int indexedStream  = testIdent.StreamId;

            ExprNode[] setExpressions = GetInNodeSetExpressions(inNode);
            if (setExpressions.Length == 0)
            {
                return;
            }

            var perStreamExprs = new LinkedHashMap <int?, IList <ExprNode> >();

            foreach (ExprNode exprNodeSet in setExpressions)
            {
                if (exprNodeSet.ExprEvaluator.ReturnType.GetBoxedType() != testIdentClass)
                {
                    continue;
                }
                if (exprNodeSet is ExprIdentNode)
                {
                    var setIdent = (ExprIdentNode)exprNodeSet;
                    AddToList(setIdent.StreamId, setIdent, perStreamExprs);
                }
                else
                {
                    EligibilityDesc eligibility = EligibilityUtil.VerifyInputStream(exprNodeSet, indexedStream);
                    if (!eligibility.Eligibility.IsEligible())
                    {
                        continue;
                    }
                    AddToList(eligibility.StreamNum, exprNodeSet, perStreamExprs);
                }
            }

            foreach (var entry in perStreamExprs)
            {
                ExprNode[] exprNodes = ExprNodeUtility.ToArray(entry.Value);
                if (entry.Key == null)
                {
                    queryGraph.AddInSetSingleIndexUnkeyed(testIdent.StreamId, testIdent, exprNodes);
                    continue;
                }
                if (entry.Key.Value != indexedStream)
                {
                    queryGraph.AddInSetSingleIndex(testIdent.StreamId, testIdent, entry.Key.Value, exprNodes);
                }
            }
        }
Example #3
0
 private void TryInvalidValidate(ExprInNode exprInNode)
 {
     try {
         exprInNode.Validate(SupportExprValidationContextFactory.MakeEmpty(_container));
         Assert.Fail();
     }
     catch (ExprValidationException)
     {
         // expected
     }
 }
Example #4
0
        private static ExprNode[] GetInNodeSetExpressions(ExprInNode inNode)
        {
            var setExpressions = new ExprNode[inNode.ChildNodes.Count - 1];
            var count          = 0;

            for (int i = 1; i < inNode.ChildNodes.Count; i++)
            {
                setExpressions[count++] = inNode.ChildNodes[i];
            }
            return(setExpressions);
        }
Example #5
0
        private static void AnalyzeInNode(ExprInNode inNode, QueryGraph queryGraph)
        {
            if (inNode.IsNotIn)
            {
                return;
            }

            // direction of lookup is value-set (keys) to single-expression (single index)
            AnalyzeInNodeSingleIndex(inNode, queryGraph);

            // direction of lookup is single-expression (key) to value-set  (multi index)
            AnalyzeInNodeMultiIndex(inNode, queryGraph);
        }
Example #6
0
        public void TestEquals()
        {
            ExprInNode otherInNodeNormal = SupportExprNodeFactory.MakeInSetNode(false);
            ExprInNode otherInNodeNotIn  = SupportExprNodeFactory.MakeInSetNode(true);

            Assert.IsTrue(_inNodeNormal.EqualsNode(otherInNodeNormal, false));
            Assert.IsTrue(_inNodeNotIn.EqualsNode(otherInNodeNotIn, false));

            Assert.IsFalse(_inNodeNormal.EqualsNode(otherInNodeNotIn, false));
            Assert.IsFalse(_inNodeNotIn.EqualsNode(otherInNodeNormal, false));
            Assert.IsFalse(_inNodeNotIn.EqualsNode(SupportExprNodeFactory.MakeCaseSyntax1Node(), false));
            Assert.IsFalse(_inNodeNormal.EqualsNode(SupportExprNodeFactory.MakeCaseSyntax1Node(), false));
        }
        public void TestEquals()
        {
            ExprInNode       otherInNode   = SupportExprNodeFactory.MakeInSetNode(false);
            ExprVariableNode otherVarOne   = new ExprVariableNodeImpl(_variableService.GetVariableMetaData("dummy"), null);
            ExprVariableNode otherVarTwo   = new ExprVariableNodeImpl(_variableService.GetVariableMetaData("var1"), null);
            ExprVariableNode otherVarThree = new ExprVariableNodeImpl(_variableService.GetVariableMetaData("var1"), "abc");

            Assert.IsTrue(_varNode.EqualsNode(_varNode));
            Assert.IsTrue(_varNode.EqualsNode(otherVarTwo));
            Assert.IsFalse(_varNode.EqualsNode(otherVarOne));
            Assert.IsFalse(_varNode.EqualsNode(otherInNode));
            Assert.IsFalse(otherVarTwo.EqualsNode(otherVarThree));
        }
Example #8
0
 /// <summary>
 /// Analyzes filter expression to build query graph model.
 /// </summary>
 /// <param name="topNode">filter top node</param>
 /// <param name="queryGraph">model containing relationships between streams, to be written to</param>
 /// <param name="isOuterJoin">if set to <c>true</c> [is outer join].</param>
 public static void Analyze(ExprNode topNode, QueryGraph queryGraph, bool isOuterJoin)
 {
     // Analyze relationships between streams. Relationships are properties in AND and EQUALS nodes of joins.
     if (topNode is ExprEqualsNode)
     {
         var equalsNode = (ExprEqualsNode)topNode;
         if (!equalsNode.IsNotEquals)
         {
             AnalyzeEqualsNode(equalsNode, queryGraph, isOuterJoin);
         }
     }
     else if (topNode is ExprAndNode)
     {
         var andNode = (ExprAndNode)topNode;
         AnalyzeAndNode(andNode, queryGraph, isOuterJoin);
     }
     else if (topNode is ExprBetweenNode)
     {
         var betweenNode = (ExprBetweenNode)topNode;
         AnalyzeBetweenNode(betweenNode, queryGraph);
     }
     else if (topNode is ExprRelationalOpNode)
     {
         var relNode = (ExprRelationalOpNode)topNode;
         AnalyzeRelationalOpNode(relNode, queryGraph);
     }
     else if (topNode is ExprDotNode && !isOuterJoin)
     {
         var dotNode = (ExprDotNode)topNode;
         AnalyzeDotNode(dotNode, queryGraph);
     }
     else if (topNode is ExprInNode)
     {
         ExprInNode inNode = (ExprInNode)topNode;
         AnalyzeInNode(inNode, queryGraph);
     }
     else if (topNode is ExprOrNode)
     {
         ExprNode rewritten = FilterSpecCompilerMakeParamUtil.RewriteOrToInIfApplicable(topNode);
         if (rewritten is ExprInNode)
         {
             var inNode = (ExprInNode)rewritten;
             AnalyzeInNode(inNode, queryGraph);
         }
     }
 }
Example #9
0
        public void TestValidate()
        {
            _inNodeNormal = SupportExprNodeFactory.MakeInSetNode(true);
            _inNodeNormal.Validate(SupportExprValidationContextFactory.MakeEmpty(_container));

            // No subnodes: Exception is thrown.
            TryInvalidValidate(new ExprInNodeImpl(true));

            // singe child node not possible, must be 2 at least
            _inNodeNormal = new ExprInNodeImpl(true);
            _inNodeNormal.AddChildNode(new SupportExprNode(4));
            TryInvalidValidate(_inNodeNormal);

            // test a type mismatch
            _inNodeNormal = new ExprInNodeImpl(true);
            _inNodeNormal.AddChildNode(new SupportExprNode("sx"));
            _inNodeNormal.AddChildNode(new SupportExprNode(4));
            TryInvalidValidate(_inNodeNormal);
        }
Example #10
0
        private static void AnalyzeInNodeMultiIndex(ExprInNode inNode, QueryGraph queryGraph)
        {
            ExprNode[] setExpressions = GetInNodeSetExpressions(inNode);
            if (setExpressions.Length == 0)
            {
                return;
            }

            var perStreamExprs = new LinkedHashMap <int?, IList <ExprNode> >();

            foreach (ExprNode exprNodeSet in setExpressions)
            {
                if (!(exprNodeSet is ExprIdentNode))
                {
                    continue;
                }
                var setIdent = (ExprIdentNode)exprNodeSet;
                AddToList(setIdent.StreamId, setIdent, perStreamExprs);
            }
            if (perStreamExprs.IsEmpty())
            {
                return;
            }

            var testExpr     = inNode.ChildNodes[0];
            var testExprType = testExpr.ExprEvaluator.ReturnType.GetBoxedType();

            if (perStreamExprs.Count > 1)
            {
                return;
            }
            var entry = perStreamExprs.First();

            ExprNode[] exprNodes = ExprNodeUtility.ToArray(entry.Value);
            foreach (ExprNode node in exprNodes)
            {
                var exprType = node.ExprEvaluator.ReturnType;
                if (exprType.GetBoxedType() != testExprType)
                {
                    return;
                }
            }

            int?testStreamNum;
            int setStream = entry.Key.Value;

            if (!(testExpr is ExprIdentNode))
            {
                EligibilityDesc eligibility = EligibilityUtil.VerifyInputStream(testExpr, setStream);
                if (!eligibility.Eligibility.IsEligible())
                {
                    return;
                }
                if (eligibility.Eligibility == Eligibility.REQUIRE_ONE && setStream == eligibility.StreamNum)
                {
                    return;
                }
                testStreamNum = eligibility.StreamNum;
            }
            else
            {
                testStreamNum = ((ExprIdentNode)testExpr).StreamId;
            }

            if (testStreamNum == null)
            {
                queryGraph.AddInSetMultiIndexUnkeyed(testExpr, setStream, exprNodes);
            }
            else
            {
                if (testStreamNum.Equals(entry.Key))
                {
                    return;
                }
                queryGraph.AddInSetMultiIndex(testStreamNum.Value, testExpr, setStream, exprNodes);
            }
        }
Example #11
0
 public void SetUp()
 {
     _container    = SupportContainer.Reset();
     _inNodeNormal = SupportExprNodeFactory.MakeInSetNode(false);
     _inNodeNotIn  = SupportExprNodeFactory.MakeInSetNode(true);
 }
        private static FilterSpecParam HandleInSetNode(
            ExprInNode constituent,
            IDictionary<string, Pair<EventType, string>> arrayEventTypes,
            ExprEvaluatorContext exprEvaluatorContext,
            string statementName)

        {
            var left = constituent.ChildNodes[0];
            if (!(left is ExprFilterOptimizableNode))
            {
                return null;
            }

            var filterOptimizableNode = (ExprFilterOptimizableNode) left;
            var lookupable = filterOptimizableNode.FilterLookupable;
            var op = FilterOperator.IN_LIST_OF_VALUES;
            if (constituent.IsNotIn)
            {
                op = FilterOperator.NOT_IN_LIST_OF_VALUES;
            }

            var expectedNumberOfConstants = constituent.ChildNodes.Length - 1;
            IList<FilterSpecParamInValue> listofValues = new List<FilterSpecParamInValue>();
            foreach (var subNode in constituent.ChildNodes.Skip(1)) // ignore the first node as it's the identifier
            {
                if (ExprNodeUtility.IsConstantValueExpr(subNode))
                {
                    var constantNode = (ExprConstantNode) subNode;
                    var constant = constantNode.GetConstantValue(exprEvaluatorContext);
                    if (constant != null && !constant.GetType().IsArray)
                    {
                        var constantType = constant.GetType();
                        if (constantType.IsGenericCollection())
                            return null;
                        if (constantType.IsGenericDictionary())
                            return null;
                    }

                    var asArray = constant as Array;
                    if (asArray != null)
                    {
                        for (var i = 0; i < asArray.Length; i++)
                        {
                            var arrayElement = asArray.GetValue(i);
                            var arrayElementCoerced = HandleConstantsCoercion(lookupable, arrayElement);
                            listofValues.Add(new InSetOfValuesConstant(arrayElementCoerced));
                            if (i > 0)
                            {
                                expectedNumberOfConstants++;
                            }
                        }
                    }
                    else
                    {
                        constant = HandleConstantsCoercion(lookupable, constant);
                        listofValues.Add(new InSetOfValuesConstant(constant));
                    }
                }
                if (subNode is ExprContextPropertyNode)
                {
                    var contextPropertyNode = (ExprContextPropertyNode) subNode;
                    var returnType = contextPropertyNode.ReturnType;
                    if (contextPropertyNode.ReturnType.IsImplementsInterface(typeof (ICollection<>)) ||
                        contextPropertyNode.ReturnType.IsImplementsInterface(typeof (IDictionary<,>)))
                    {
                        return null;
                    }
                    if ((returnType != null) && (returnType.GetType().IsArray))
                    {
                        return null;
                    }
                    var coercer = GetNumberCoercer(
                        left.ExprEvaluator.ReturnType, contextPropertyNode.ReturnType, lookupable.Expression);
                    listofValues.Add(
                        new InSetOfValuesContextProp(
                            contextPropertyNode.PropertyName, contextPropertyNode.Getter, coercer));
                }
                if (subNode is ExprIdentNode)
                {
                    var identNodeInner = (ExprIdentNode) subNode;
                    if (identNodeInner.StreamId == 0)
                    {
                        break; // for same event evals use the boolean expression, via count compare failing below
                    }

                    var isMustCoerce = false;
                    var numericCoercionType = lookupable.ReturnType.GetBoxedType();
                    if (identNodeInner.ExprEvaluator.ReturnType != lookupable.ReturnType)
                    {
                        if (lookupable.ReturnType.IsNumeric())
                        {
                            if (!identNodeInner.ExprEvaluator.ReturnType.CanCoerce(lookupable.ReturnType))
                            {
                                ThrowConversionError(
                                    identNodeInner.ExprEvaluator.ReturnType, lookupable.ReturnType,
                                    lookupable.Expression);
                            }
                            isMustCoerce = true;
                        }
                        else
                        {
                            break; // assumed not compatible
                        }
                    }

                    FilterSpecParamInValue inValue;
                    var streamName = identNodeInner.ResolvedStreamName;
                    if (arrayEventTypes != null && !arrayEventTypes.IsEmpty() && arrayEventTypes.ContainsKey(streamName))
                    {
                        var indexAndProp = GetStreamIndex(identNodeInner.ResolvedPropertyName);
                        inValue = new InSetOfValuesEventPropIndexed(
                            identNodeInner.ResolvedStreamName, indexAndProp.First.Value,
                            indexAndProp.Second, isMustCoerce, numericCoercionType, statementName);
                    }
                    else
                    {
                        inValue = new InSetOfValuesEventProp(
                            identNodeInner.ResolvedStreamName, identNodeInner.ResolvedPropertyName, isMustCoerce,
                            numericCoercionType);
                    }

                    listofValues.Add(inValue);
                }
            }

            // Fallback if not all values in the in-node can be resolved to properties or constants
            if (listofValues.Count == expectedNumberOfConstants)
            {
                return new FilterSpecParamIn(lookupable, op, listofValues);
            }
            return null;
        }
Example #13
0
        internal static FilterSpecParamForge HandleInSetNode(
            ExprInNode constituent,
            IDictionary <string, Pair <EventType, string> > taggedEventTypes,
            IDictionary <string, Pair <EventType, string> > arrayEventTypes,
            ISet <string> allTagNamesOrdered,
            StatementRawInfo raw,
            StatementCompileTimeServices services)
        {
            var left = constituent.ChildNodes[0];
            ExprFilterSpecLookupableForge lookupable = null;

            if (left is ExprFilterOptimizableNode)
            {
                var filterOptimizableNode = (ExprFilterOptimizableNode)left;
                lookupable = filterOptimizableNode.FilterLookupable;
            }
            else if (FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.LKUPCOMPOSITE, raw, services) &&
                     IsLimitedLookupableExpression(left))
            {
                lookupable = MakeLimitedLookupableForgeMayNull(left, raw, services);
            }

            if (lookupable == null)
            {
                return(null);
            }

            var op = FilterOperator.IN_LIST_OF_VALUES;

            if (constituent.IsNotIn)
            {
                op = FilterOperator.NOT_IN_LIST_OF_VALUES;
            }

            var expectedNumberOfConstants = constituent.ChildNodes.Length - 1;
            IList <FilterSpecParamInValueForge> listofValues = new List <FilterSpecParamInValueForge>();
            var it = Arrays.AsList(constituent.ChildNodes).GetEnumerator();

            it.MoveNext();             // ignore the first node as it's the identifier
            while (it.MoveNext())
            {
                var subNode = it.Current;
                if (subNode.Forge.ForgeConstantType.IsCompileTimeConstant)
                {
                    var constant = subNode.Forge.ExprEvaluator.Evaluate(null, true, null);
                    if (constant is ICollection <object> )
                    {
                        return(null);
                    }

                    if (constant is IDictionary <object, object> )
                    {
                        return(null);
                    }

                    if ((constant != null) && (constant is Array arrayConstant))
                    {
                        for (var i = 0; i < arrayConstant.Length; i++)
                        {
                            var arrayElement        = arrayConstant.GetValue(i);
                            var arrayElementCoerced = HandleConstantsCoercion(lookupable, arrayElement);
                            listofValues.Add(new FilterForEvalConstantAnyTypeForge(arrayElementCoerced));
                            if (i > 0)
                            {
                                expectedNumberOfConstants++;
                            }
                        }
                    }
                    else
                    {
                        constant = HandleConstantsCoercion(lookupable, constant);
                        listofValues.Add(new FilterForEvalConstantAnyTypeForge(constant));
                    }
                }
                else if (subNode is ExprContextPropertyNode)
                {
                    var     contextPropertyNode = (ExprContextPropertyNode)subNode;
                    var     returnType          = contextPropertyNode.Type;
                    Coercer coercer;
                    if (TypeHelper.IsCollectionMapOrArray(returnType))
                    {
                        CheckArrayCoercion(returnType, lookupable.ReturnType, lookupable.Expression);
                        coercer = null;
                    }
                    else
                    {
                        coercer = GetNumberCoercer(left.Forge.EvaluationType, contextPropertyNode.Type, lookupable.Expression);
                    }

                    var finalReturnType = coercer != null ? coercer.ReturnType : returnType;
                    listofValues.Add(new FilterForEvalContextPropForge(contextPropertyNode.PropertyName, contextPropertyNode.Getter, coercer, finalReturnType));
                }
                else if (subNode.Forge.ForgeConstantType.IsDeployTimeTimeConstant && subNode is ExprNodeDeployTimeConst)
                {
                    var     deployTimeConst = (ExprNodeDeployTimeConst)subNode;
                    var     returnType      = subNode.Forge.EvaluationType;
                    Coercer coercer;
                    if (TypeHelper.IsCollectionMapOrArray(returnType))
                    {
                        CheckArrayCoercion(returnType, lookupable.ReturnType, lookupable.Expression);
                        coercer = null;
                    }
                    else
                    {
                        coercer = GetNumberCoercer(left.Forge.EvaluationType, returnType, lookupable.Expression);
                    }

                    listofValues.Add(new FilterForEvalDeployTimeConstForge(deployTimeConst, coercer, returnType));
                }
                else if (subNode is ExprIdentNode)
                {
                    var identNodeInner = (ExprIdentNode)subNode;
                    if (identNodeInner.StreamId == 0)
                    {
                        break;                         // for same event evals use the boolean expression, via count compare failing below
                    }

                    var isMustCoerce    = false;
                    var coerceToType    = Boxing.GetBoxedType(lookupable.ReturnType);
                    var identReturnType = identNodeInner.Forge.EvaluationType;

                    if (TypeHelper.IsCollectionMapOrArray(identReturnType))
                    {
                        CheckArrayCoercion(identReturnType, lookupable.ReturnType, lookupable.Expression);
                        coerceToType = identReturnType;
                        // no action
                    }
                    else if (identReturnType != lookupable.ReturnType)
                    {
                        if (TypeHelper.IsNumeric(lookupable.ReturnType))
                        {
                            if (!TypeHelper.CanCoerce(identReturnType, lookupable.ReturnType))
                            {
                                ThrowConversionError(identReturnType, lookupable.ReturnType, lookupable.Expression);
                            }

                            isMustCoerce = true;
                        }
                        else
                        {
                            break;                             // assumed not compatible
                        }
                    }

                    FilterSpecParamInValueForge inValue;
                    var streamName = identNodeInner.ResolvedStreamName;
                    if (arrayEventTypes != null && !arrayEventTypes.IsEmpty() && arrayEventTypes.ContainsKey(streamName))
                    {
                        var indexAndProp   = GetStreamIndex(identNodeInner.ResolvedPropertyName);
                        var innerEventType = GetArrayInnerEventType(arrayEventTypes, streamName);
                        inValue = new FilterForEvalEventPropIndexedForge(
                            identNodeInner.ResolvedStreamName,
                            indexAndProp.First,
                            indexAndProp.Second,
                            innerEventType,
                            isMustCoerce,
                            coerceToType);
                    }
                    else
                    {
                        inValue = new FilterForEvalEventPropForge(
                            identNodeInner.ResolvedStreamName,
                            identNodeInner.ResolvedPropertyName,
                            identNodeInner.ExprEvaluatorIdent,
                            isMustCoerce,
                            coerceToType);
                    }

                    listofValues.Add(inValue);
                }
                else if (FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.VALUECOMPOSITE, raw, services) &&
                         IsLimitedValueExpression(subNode))
                {
                    var convertor      = GetMatchEventConvertor(subNode, taggedEventTypes, arrayEventTypes, allTagNamesOrdered);
                    var valueType      = subNode.Forge.EvaluationType;
                    var lookupableType = lookupable.ReturnType;
                    var numberCoercer  = GetNumberCoercer(lookupableType, valueType, lookupable.Expression);
                    var forge          = new FilterForEvalLimitedExprForge(subNode, convertor, numberCoercer);
                    listofValues.Add(forge);
                }
            }

            // Fallback if not all values in the in-node can be resolved to properties or constants
            if (listofValues.Count == expectedNumberOfConstants)
            {
                return(new FilterSpecParamInForge(lookupable, op, listofValues));
            }

            return(null);
        }
Example #14
0
 public void SetUp()
 {
     _inNodeNormal = SupportExprNodeFactory.MakeInSetNode(false);
     _inNodeNotIn  = SupportExprNodeFactory.MakeInSetNode(true);
 }
        private static FilterSpecParam HandleInSetNode(
            ExprInNode constituent,
            IDictionary <string, Pair <EventType, string> > arrayEventTypes,
            ExprEvaluatorContext exprEvaluatorContext,
            string statementName)
        {
            var left = constituent.ChildNodes[0];

            if (!(left is ExprFilterOptimizableNode))
            {
                return(null);
            }

            var filterOptimizableNode = (ExprFilterOptimizableNode)left;
            var lookupable            = filterOptimizableNode.FilterLookupable;
            var op = FilterOperator.IN_LIST_OF_VALUES;

            if (constituent.IsNotIn)
            {
                op = FilterOperator.NOT_IN_LIST_OF_VALUES;
            }

            var expectedNumberOfConstants = constituent.ChildNodes.Count - 1;
            var listofValues = new List <FilterSpecParamInValue>();
            var enumerator   = constituent.ChildNodes.GetEnumerator();

            enumerator.MoveNext();  // ignore the first node as it's the identifier
            while (enumerator.MoveNext())
            {
                ExprNode subNode = enumerator.Current;
                if (ExprNodeUtility.IsConstantValueExpr(subNode))
                {
                    var constantNode = (ExprConstantNode)subNode;
                    var constant     = constantNode.GetConstantValue(exprEvaluatorContext);
                    if (constant is Array asArray)
                    {
                        for (var i = 0; i < asArray.Length; i++)
                        {
                            var arrayElement        = asArray.GetValue(i);
                            var arrayElementCoerced = HandleConstantsCoercion(lookupable, arrayElement);
                            listofValues.Add(new FilterForEvalConstantAnyType(arrayElementCoerced));
                            if (i > 0)
                            {
                                expectedNumberOfConstants++;
                            }
                        }
                    }
                    else if (constant is ICollection <object> )
                    {
                        return(null);
                    }
                    else if (constant is IDictionary <string, object> )
                    {
                        return(null);
                    }
                    else
                    {
                        constant = HandleConstantsCoercion(lookupable, constant);
                        listofValues.Add(new FilterForEvalConstantAnyType(constant));
                    }
                }
                if (subNode is ExprContextPropertyNode)
                {
                    var     contextPropertyNode = (ExprContextPropertyNode)subNode;
                    var     returnType          = contextPropertyNode.ReturnType;
                    Coercer coercer;
                    Type    coercerType;
                    if (returnType.IsCollectionMapOrArray())
                    {
                        CheckArrayCoercion(returnType, lookupable.ReturnType, lookupable.Expression);
                        coercer     = null;
                        coercerType = null;
                    }
                    else
                    {
                        coercer = GetNumberCoercer(
                            left.ExprEvaluator.ReturnType,
                            contextPropertyNode.ReturnType,
                            lookupable.Expression,
                            out coercerType);
                    }
                    var finalReturnType = coercer != null ? coercerType : returnType;
                    listofValues.Add(new FilterForEvalContextPropMayCoerce(contextPropertyNode.PropertyName, contextPropertyNode.Getter, coercer, finalReturnType));
                }
                if (subNode is ExprIdentNode)
                {
                    var identNodeInner = (ExprIdentNode)subNode;
                    if (identNodeInner.StreamId == 0)
                    {
                        break; // for same event evals use the bool expression, via count compare failing below
                    }

                    var isMustCoerce    = false;
                    var coerceToType    = lookupable.ReturnType.GetBoxedType();
                    var identReturnType = identNodeInner.ExprEvaluator.ReturnType;

                    if (identReturnType.IsCollectionMapOrArray())
                    {
                        CheckArrayCoercion(identReturnType, lookupable.ReturnType, lookupable.Expression);
                        coerceToType = identReturnType;
                        // no action
                    }
                    else if (identReturnType != lookupable.ReturnType)
                    {
                        if (lookupable.ReturnType.IsNumeric())
                        {
                            if (!identReturnType.CanCoerce(lookupable.ReturnType))
                            {
                                ThrowConversionError(identReturnType, lookupable.ReturnType, lookupable.Expression);
                            }
                            isMustCoerce = true;
                        }
                        else
                        {
                            break;  // assumed not compatible
                        }
                    }

                    FilterSpecParamInValue inValue;
                    var streamName = identNodeInner.ResolvedStreamName;
                    if (arrayEventTypes != null && !arrayEventTypes.IsEmpty() && arrayEventTypes.ContainsKey(streamName))
                    {
                        var indexAndProp = GetStreamIndex(identNodeInner.ResolvedPropertyName);
                        inValue = new FilterForEvalEventPropIndexedMayCoerce(identNodeInner.ResolvedStreamName, indexAndProp.First,
                                                                             indexAndProp.Second, isMustCoerce, coerceToType, statementName);
                    }
                    else
                    {
                        inValue = new FilterForEvalEventPropMayCoerce(identNodeInner.ResolvedStreamName, identNodeInner.ResolvedPropertyName, isMustCoerce, coerceToType);
                    }

                    listofValues.Add(inValue);
                }
            }

            // Fallback if not all values in the in-node can be resolved to properties or constants
            if (listofValues.Count == expectedNumberOfConstants)
            {
                return(new FilterSpecParamIn(lookupable, op, listofValues));
            }
            return(null);
        }