// Special-case validation: When an on-merge query in the not-matched clause uses a subquery then
        // that subquery should not reference any of the stream's properties which are not-matched
        internal static void ValidateSubqueryExcludeOuterStream(ExprNode matchCondition)
        {
            var visitorSubselects = new ExprNodeSubselectDeclaredDotVisitor();

            matchCondition.Accept(visitorSubselects);
            if (visitorSubselects.Subselects.IsEmpty())
            {
                return;
            }
            var visitorProps = new ExprNodeIdentifierCollectVisitor();

            foreach (var node in visitorSubselects.Subselects)
            {
                if (node.StatementSpecCompiled.FilterRootNode != null)
                {
                    node.StatementSpecCompiled.FilterRootNode.Accept(visitorProps);
                }
            }
            foreach (var node in visitorProps.ExprProperties)
            {
                if (node.StreamId == 1)
                {
                    throw new ExprValidationException("On-Merge not-matched filter expression may not use properties that are provided by the named window event");
                }
            }
        }
Example #2
0
        private static ISet <string> DeterminePropertiesInitialValue(IEnumerable <OnTriggerSetAssignment> assignments)
        {
            ISet <string> props   = new HashSet <string>();
            var           visitor = new ExprNodeIdentifierCollectVisitor();

            foreach (var assignment in assignments)
            {
                if (assignment.Expression is ExprEqualsNode)
                {
                    assignment.Expression.ChildNodes[1].Accept(visitor);
                }
                else
                {
                    assignment.Expression.Accept(visitor);
                }
                foreach (var node in visitor.ExprProperties)
                {
                    if (node.StreamId == 2)
                    {
                        props.Add(node.ResolvedPropertyName);
                    }
                }
            }
            return(props);
        }
Example #3
0
 public static void SetChildIdentNodesOptionalEvent(ExprNode exprNode)
 {
     ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor();
     exprNode.Accept(visitor);
     foreach (ExprIdentNode node in visitor.ExprProperties) {
         node.IsOptionalEvent = true;
     }
 }
Example #4
0
        public static ISet<int> GetIdentStreamNumbers(ExprNode child)
        {
            ISet<int> streams = new HashSet<int>();
            var visitor = new ExprNodeIdentifierCollectVisitor();
            child.Accept(visitor);
            foreach (var node in visitor.ExprProperties) {
                streams.Add(node.StreamId);
            }

            return streams;
        }
        /// <summary>
        /// Validate the view.
        /// </summary>
        /// <param name="engineImportService">The engine import service.</param>
        /// <param name="streamTypeService">supplies the types of streams against which to validate</param>
        /// <param name="methodResolutionService">for resolving imports and classes and methods</param>
        /// <param name="timeProvider">for providing current time</param>
        /// <param name="variableService">for access to variables</param>
        /// <param name="tableService"></param>
        /// <param name="scriptingService">The scripting service.</param>
        /// <param name="exprEvaluatorContext">The expression evaluator context.</param>
        /// <param name="configSnapshot">The config snapshot.</param>
        /// <param name="schedulingService">The scheduling service.</param>
        /// <param name="engineURI">The engine URI.</param>
        /// <param name="sqlParameters">The SQL parameters.</param>
        /// <param name="eventAdapterService">The event adapter service.</param>
        /// <param name="statementName">Name of the statement.</param>
        /// <param name="statementId">The statement id.</param>
        /// <param name="annotations">The annotations.</param>
        /// <throws>  ExprValidationException is thrown to indicate an exception in validating the view </throws>
        public void Validate(
            EngineImportService engineImportService,
            StreamTypeService streamTypeService,
            MethodResolutionService methodResolutionService,
            TimeProvider timeProvider,
            VariableService variableService,
            TableService tableService,
            ScriptingService scriptingService,
            ExprEvaluatorContext exprEvaluatorContext,
            ConfigurationInformation configSnapshot,
            SchedulingService schedulingService,
            string engineURI,
            IDictionary <int, IList <ExprNode> > sqlParameters,
            EventAdapterService eventAdapterService,
            string statementName,
            string statementId,
            Attribute[] annotations)
        {
            _evaluators           = new ExprEvaluator[_inputParameters.Count];
            _subordinateStreams   = new SortedSet <int>();
            _exprEvaluatorContext = exprEvaluatorContext;

            int count             = 0;
            var validationContext = new ExprValidationContext(
                streamTypeService, methodResolutionService, null, timeProvider, variableService, tableService,
                exprEvaluatorContext, eventAdapterService, statementName, statementId, annotations, null, scriptingService,
                false, false, true, false, null, false);

            foreach (string inputParam in _inputParameters)
            {
                ExprNode raw = FindSQLExpressionNode(_myStreamNumber, count, sqlParameters);
                if (raw == null)
                {
                    throw new ExprValidationException(
                              "Internal error find expression for historical stream parameter " + count + " stream " +
                              _myStreamNumber);
                }
                ExprNode evaluator = ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.DATABASEPOLL, raw, validationContext);
                _evaluators[count++] = evaluator.ExprEvaluator;

                ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor();
                visitor.Visit(evaluator);
                foreach (ExprIdentNode identNode in visitor.ExprProperties)
                {
                    if (identNode.StreamId == _myStreamNumber)
                    {
                        throw new ExprValidationException("Invalid expression '" + inputParam +
                                                          "' resolves to the historical data itself");
                    }
                    _subordinateStreams.Add(identNode.StreamId);
                }
            }
        }
        public override IList<StmtClassForgeableFactory> Validate(
            StreamTypeService typeService,
            StatementBaseInfo @base,
            StatementCompileTimeServices services)
        {
            int count = 0;
            ExprValidationContext validationContext =
                new ExprValidationContextBuilder(typeService, @base.StatementRawInfo, services)
                    .WithAllowBindingConsumption(true)
                    .Build();
            ExprNode[] inputParamNodes = new ExprNode[inputParameters.Length];
            foreach (string inputParam in inputParameters) {
                ExprNode raw = FindSQLExpressionNode(StreamNum, count, @base.StatementSpec.Raw.SqlParameters);
                if (raw == null) {
                    throw new ExprValidationException(
                        "Internal error find expression for historical stream parameter " +
                        count +
                        " stream " +
                        StreamNum);
                }

                ExprNode evaluator = ExprNodeUtilityValidate.GetValidatedSubtree(
                    ExprNodeOrigin.DATABASEPOLL,
                    raw,
                    validationContext);
                inputParamNodes[count++] = evaluator;

                ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor();
                visitor.Visit(evaluator);
                foreach (ExprIdentNode identNode in visitor.ExprProperties) {
                    if (identNode.StreamId == StreamNum) {
                        throw new ExprValidationException(
                            "Invalid expression '" + inputParam + "' resolves to the historical data itself");
                    }

                    SubordinateStreams.Add(identNode.StreamId);
                }
            }

            InputParamEvaluators = ExprNodeUtilityQuery.GetForges(inputParamNodes);
            
            
            // plan multikey
            MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKey(InputParamEvaluators, false, @base.StatementRawInfo, services.SerdeResolver);
            MultiKeyClassRef = multiKeyPlan.ClassRef;

            return multiKeyPlan.MultiKeyForgeables;
        }
Example #7
0
        /// <summary>
        /// Returns true if all properties within the expression are witin data window'd streams.
        /// </summary>
        /// <param name="child">expression to interrogate</param>
        /// <param name="streamTypeService">streams</param>
        /// <param name="unidirectionalJoin">indicator unidirection join</param>
        /// <returns>indicator</returns>
        public static bool HasRemoveStreamForAggregations(
            ExprNode child,
            StreamTypeService streamTypeService,
            bool unidirectionalJoin)
        {
            // Determine whether all streams are istream-only or irstream
            bool[] isIStreamOnly = streamTypeService.IStreamOnly;
            bool isAllIStream = true; // all true?
            bool isAllIRStream = true; // all false?
            foreach (bool anIsIStreamOnly in isIStreamOnly) {
                if (!anIsIStreamOnly) {
                    isAllIStream = false;
                }
                else {
                    isAllIRStream = false;
                }
            }

            // determine if a data-window applies to this max function
            bool hasDataWindows = true;
            if (isAllIStream) {
                hasDataWindows = false;
            }
            else if (!isAllIRStream) {
                if (streamTypeService.EventTypes.Length > 1) {
                    if (unidirectionalJoin) {
                        return false;
                    }

                    // In a join we assume that a data window is present or implicit via unidirectional
                }
                else {
                    hasDataWindows = false;
                    // get all aggregated properties to determine if any is from a windowed stream
                    ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor();
                    child.Accept(visitor);
                    foreach (ExprIdentNode node in visitor.ExprProperties) {
                        if (!isIStreamOnly[node.StreamId]) {
                            hasDataWindows = true;
                            break;
                        }
                    }
                }
            }

            return hasDataWindows;
        }
        private static ISet <string> DeterminePropertiesInitialValue(IList <OnTriggerSetAssignment> assignments)
        {
            ISet <string> props = new HashSet <string>();
            ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor();

            foreach (OnTriggerSetAssignment assignment in assignments)
            {
                assignment.Validated.Accept(visitor);
                foreach (ExprIdentNode node in visitor.ExprProperties)
                {
                    if (node.StreamId == 2)
                    {
                        props.Add(node.ResolvedPropertyName);
                    }
                }

                visitor.Reset();
            }

            return(props);
        }
Example #9
0
        public static EligibilityDesc VerifyInputStream(
            ExprNode expression,
            int indexedStream)
        {
            var visitor = new ExprNodeIdentifierCollectVisitor();
            expression.Accept(visitor);
            var inputStreamsRequired = visitor.StreamsRequired;
            if (inputStreamsRequired.Count > 1) { // multi-stream dependency no optimization (i.e. a+b=c)
                return new EligibilityDesc(Eligibility.INELIGIBLE, null);
            }

            if (inputStreamsRequired.Count == 1 && inputStreamsRequired.First() == indexedStream) {
                // self-compared no optimization
                return new EligibilityDesc(Eligibility.INELIGIBLE, null);
            }

            if (inputStreamsRequired.IsEmpty()) {
                return new EligibilityDesc(Eligibility.REQUIRE_NONE, null);
            }

            return new EligibilityDesc(Eligibility.REQUIRE_ONE, inputStreamsRequired.First());
        }
        public void Init(
            int?streamOfProviderIfApplicable,
            EnumMethodEnum enumMethodEnum,
            String enumMethodUsedName,
            EPType typeInfo,
            IList <ExprNode> parameters,
            ExprValidationContext validationContext)
        {
            var eventTypeColl           = EPTypeHelper.GetEventTypeMultiValued(typeInfo);
            var eventTypeBean           = EPTypeHelper.GetEventTypeSingleValued(typeInfo);
            var collectionComponentType = EPTypeHelper.GetClassMultiValued(typeInfo);

            _enumMethodEnum      = enumMethodEnum;
            _enumMethodUsedName  = enumMethodUsedName;
            _streamCountIncoming = validationContext.StreamTypeService.EventTypes.Length;

            if (eventTypeColl == null && collectionComponentType == null && eventTypeBean == null)
            {
                throw new ExprValidationException(
                          "Invalid input for built-in enumeration method '" + enumMethodUsedName +
                          "', expecting collection of event-type or scalar values as input, received " +
                          EPTypeHelper.ToTypeDescriptive(typeInfo));
            }

            // compile parameter abstract for validation against available footprints
            var footprintProvided = DotMethodUtil.GetProvidedFootprint(parameters);

            // validate parameters
            DotMethodInputTypeMatcher inputTypeMatcher = new ProxyDotMethodInputTypeMatcher
            {
                ProcMatches = fp =>
                {
                    if (fp.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeBean == null && eventTypeColl == null)
                    {
                        return(false);
                    }
                    if (fp.Input == DotMethodFPInputEnum.SCALAR_ANY && collectionComponentType == null)
                    {
                        return(false);
                    }
                    return(true);
                }
            };

            var footprint = DotMethodUtil.ValidateParametersDetermineFootprint(
                enumMethodEnum.GetFootprints(), DotMethodTypeEnum.ENUM, enumMethodUsedName, footprintProvided,
                inputTypeMatcher);

            // validate input criteria met for this footprint
            if (footprint.Input != DotMethodFPInputEnum.ANY)
            {
                var message = "Invalid input for built-in enumeration method '" + enumMethodUsedName + "' and " +
                              footprint.Parameters.Length + "-parameter footprint, expecting collection of ";
                var received = " as input, received " + EPTypeHelper.ToTypeDescriptive(typeInfo);
                if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeColl == null)
                {
                    throw new ExprValidationException(message + "events" + received);
                }
                if (footprint.Input.IsScalar() && collectionComponentType == null)
                {
                    throw new ExprValidationException(message + "values (typically scalar values)" + received);
                }
                if (footprint.Input == DotMethodFPInputEnum.SCALAR_NUMERIC && !collectionComponentType.IsNumeric())
                {
                    throw new ExprValidationException(message + "numeric values" + received);
                }
            }

            // manage context of this lambda-expression in regards to outer lambda-expression that may call this one.
            ExpressionResultCacheForEnumerationMethod enumerationMethodCache = validationContext.ExprEvaluatorContext.ExpressionResultCacheService.AllocateEnumerationMethod;

            enumerationMethodCache.PushStack(this);

            var bodiesAndParameters = new List <ExprDotEvalParam>();
            var count          = 0;
            var inputEventType = eventTypeBean ?? eventTypeColl;

            foreach (var node in parameters)
            {
                var bodyAndParameter = GetBodyAndParameter(
                    enumMethodUsedName, count++, node, inputEventType, collectionComponentType, validationContext,
                    bodiesAndParameters, footprint);
                bodiesAndParameters.Add(bodyAndParameter);
            }

            _enumEval = GetEnumEval(
                validationContext.EngineImportService, validationContext.EventAdapterService,
                validationContext.StreamTypeService, validationContext.StatementId, enumMethodUsedName,
                bodiesAndParameters, inputEventType, collectionComponentType, _streamCountIncoming,
                validationContext.IsDisablePropertyExpressionEventCollCache);
            _enumEvalNumRequiredEvents = _enumEval.StreamNumSize;

            // determine the stream ids of event properties asked for in the Evaluator(s)
            var streamsRequired = new HashSet <int>();
            var visitor         = new ExprNodeIdentifierCollectVisitor();

            foreach (var desc in bodiesAndParameters)
            {
                desc.Body.Accept(visitor);
                foreach (var ident in visitor.ExprProperties)
                {
                    streamsRequired.Add(ident.StreamId);
                }
            }
            if (streamOfProviderIfApplicable != null)
            {
                streamsRequired.Add(streamOfProviderIfApplicable.Value);
            }

            // We turn on caching if the stack is not empty (we are an inner lambda) and the dependency does not include the stream.
            var isInner = !enumerationMethodCache.PopLambda();

            if (isInner)
            {
                // If none of the properties that the current lambda uses comes from the ultimate Parent(s) or subsequent streams, then cache.
                var parents = enumerationMethodCache.GetStack();
                var found   = false;
                foreach (var req in streamsRequired)
                {
                    var first          = (ExprDotEvalEnumMethodBase)parents.First;
                    var parentIncoming = first._streamCountIncoming - 1;
                    var selfAdded      = _streamCountIncoming; // the one we use ourselfs
                    if (req > parentIncoming && req < selfAdded)
                    {
                        found = true;
                    }
                }
                _cache = !found;
            }
        }
Example #11
0
        public void Init(
            int? streamOfProviderIfApplicable,
            EnumMethodDesc enumMethodDesc,
            string enumMethodUsedName,
            EPType typeInfo,
            IList<ExprNode> parameters,
            ExprValidationContext validationContext)
        {
            var eventTypeColl = typeInfo.GetEventTypeMultiValued();
            var eventTypeBean = typeInfo.GetEventTypeSingleValued();
            var collectionComponentType = typeInfo.GetClassMultiValued();

            _enumMethodDesc = enumMethodDesc;
            _enumMethodUsedName = enumMethodUsedName;
            _streamCountIncoming = validationContext.StreamTypeService.EventTypes.Length;

            if (eventTypeColl == null && collectionComponentType == null && eventTypeBean == null) {
                throw new ExprValidationException(
                    "Invalid input for built-in enumeration method '" +
                    enumMethodUsedName +
                    "', expecting collection of event-type or scalar values as input, received " +
                    typeInfo.ToTypeDescriptive());
            }

            // compile parameter abstract for validation against available footprints
            var footprintProvided = DotMethodUtil.GetProvidedFootprint(parameters);

            // validate parameters
            DotMethodInputTypeMatcher inputTypeMatcher = new ProxyDotMethodInputTypeMatcher {
                ProcMatches = footprint => {
                    if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeBean == null && eventTypeColl == null) {
                        return false;
                    }

                    if (footprint.Input == DotMethodFPInputEnum.SCALAR_ANY && collectionComponentType == null) {
                        return false;
                    }

                    return true;
                },
            };
            var footprint = DotMethodUtil.ValidateParametersDetermineFootprint(
                enumMethodDesc.Footprints,
                DotMethodTypeEnum.ENUM,
                enumMethodUsedName,
                footprintProvided,
                inputTypeMatcher);

            // validate input criteria met for this footprint
            if (footprint.Input != DotMethodFPInputEnum.ANY) {
                var message = "Invalid input for built-in enumeration method '" +
                              enumMethodUsedName +
                              "' and " +
                              footprint.Parameters.Length +
                              "-parameter footprint, expecting collection of ";
                var received = " as input, received " + typeInfo.ToTypeDescriptive();
                if (footprint.Input == DotMethodFPInputEnum.EVENTCOLL && eventTypeColl == null) {
                    throw new ExprValidationException(message + "events" + received);
                }

                if (footprint.Input.IsScalar() && collectionComponentType == null) {
                    throw new ExprValidationException(message + "values (typically scalar values)" + received);
                }

                if (footprint.Input == DotMethodFPInputEnum.SCALAR_NUMERIC && !collectionComponentType.IsNumeric()) {
                    throw new ExprValidationException(message + "numeric values" + received);
                }
            }

            // manage context of this lambda-expression in regards to outer lambda-expression that may call this one.
            var enumCallStackHelper = validationContext.EnumMethodCallStackHelper;
            enumCallStackHelper.PushStack(this);

            try {
                // initialize
                var inputEventType = eventTypeBean ?? eventTypeColl;
                Initialize(
                    footprint,
                    enumMethodDesc.EnumMethod,
                    enumMethodUsedName,
                    inputEventType,
                    collectionComponentType,
                    parameters,
                    validationContext.StreamTypeService,
                    validationContext.StatementRawInfo,
                    validationContext.StatementCompileTimeService);

                // get-forge-desc-factory
                var forgeDescFactory = GetForgeFactory(
                    footprint,
                    parameters,
                    enumMethodDesc.EnumMethod,
                    enumMethodUsedName,
                    inputEventType,
                    collectionComponentType,
                    validationContext);

                // handle body and parameter list
                var bodiesAndParameters = new List<ExprDotEvalParam>();
                var count = 0;
                foreach (var node in parameters) {
                    var bodyAndParameter = GetBodyAndParameter(forgeDescFactory, enumMethodUsedName, count++, node, validationContext, footprint);
                    bodiesAndParameters.Add(bodyAndParameter);
                }

                var forgeDesc = forgeDescFactory.MakeEnumForgeDesc(
                    bodiesAndParameters,
                    _streamCountIncoming,
                    validationContext.StatementCompileTimeService);
                EnumForge = forgeDesc.Forge;
                _typeInfo = forgeDesc.Type;
                EnumEvalNumRequiredEvents = EnumForge.StreamNumSize;

                // determine the stream ids of event properties asked for in the evaluator(s)
                var streamsRequired = new HashSet<int?>();
                var visitor = new ExprNodeIdentifierCollectVisitor();
                foreach (var desc in bodiesAndParameters) {
                    desc.Body.Accept(visitor);
                    foreach (var ident in visitor.ExprProperties) {
                        streamsRequired.Add(ident.StreamId);
                    }
                }

                if (streamOfProviderIfApplicable != null) {
                    streamsRequired.Add(streamOfProviderIfApplicable);
                }

                // We turn on caching if the stack is not empty (we are an inner lambda) and the dependency does not include the stream.
                var isInner = !enumCallStackHelper.PopLambda();
                if (isInner) {
                    // If none of the properties that the current lambda uses comes from the ultimate parent(s) or subsequent streams, then cache.
                    var parents = enumCallStackHelper.GetStack();
                    var found = false;
                    foreach (int req in streamsRequired) {
                        var first = (ExprDotForgeEnumMethodBase) parents.First;
                        var parentIncoming = first._streamCountIncoming - 1;
                        var selfAdded = _streamCountIncoming; // the one we use ourselfs
                        if (req > parentIncoming && req < selfAdded) {
                            found = true;
                        }
                    }

                    IsCache = !found;
                }
            }
            catch (ExprValidationException) {
                enumCallStackHelper.PopLambda();
                throw;
            }
        }
Example #12
0
        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="viewChain">views</param>
        /// <param name="matchRecognizeSpec">specification</param>
        /// <param name="agentInstanceContext">The agent instance context.</param>
        /// <param name="isUnbound">true for unbound stream</param>
        /// <param name="annotations">annotations</param>
        /// <exception cref="ExprValidationException">
        /// Variable ' + defineItem.Identifier + ' has already been defined
        /// or
        /// An aggregate function may not appear in a DEFINE clause
        /// or
        /// Failed to validate condition expression for variable ' + defineItem.Identifier + ':  + ex.Message
        /// or
        /// Aggregation functions in the measure-clause must only refer to properties of exactly one group variable returning multiple events
        /// or
        /// Aggregation functions in the measure-clause must refer to one or more properties of exactly one group variable returning multiple events
        /// or
        /// The measures clause requires that each expression utilizes the AS keyword to assign a column name
        /// </exception>
        /// <throws>ExprValidationException if validation fails</throws>
        public EventRowRegexNFAViewFactory(
            ViewFactoryChain viewChain,
            MatchRecognizeSpec matchRecognizeSpec,
            AgentInstanceContext agentInstanceContext,
            bool isUnbound,
            Attribute[] annotations,
            ConfigurationEngineDefaults.MatchRecognize matchRecognizeConfig)
        {
            var parentViewType = viewChain.EventType;

            _matchRecognizeSpec   = matchRecognizeSpec;
            _isUnbound            = isUnbound;
            _isIterateOnly        = HintEnum.ITERATE_ONLY.GetHint(annotations) != null;
            _matchRecognizeConfig = matchRecognizeConfig;

            var statementContext = agentInstanceContext.StatementContext;

            // Expand repeats and permutations
            _expandedPatternNode = RegexPatternExpandUtil.Expand(matchRecognizeSpec.Pattern);

            // Determine single-row and multiple-row variables
            _variablesSingle = new LinkedHashSet <string>();
            ISet <string> variablesMultiple = new LinkedHashSet <string>();

            EventRowRegexHelper.RecursiveInspectVariables(_expandedPatternNode, false, _variablesSingle, variablesMultiple);

            // each variable gets associated with a stream number (multiple-row variables as well to hold the current event for the expression).
            var streamNum = 0;

            _variableStreams = new LinkedHashMap <string, Pair <int, bool> >();
            foreach (var variableSingle in _variablesSingle)
            {
                _variableStreams.Put(variableSingle, new Pair <int, bool>(streamNum, false));
                streamNum++;
            }
            foreach (var variableMultiple in variablesMultiple)
            {
                _variableStreams.Put(variableMultiple, new Pair <int, bool>(streamNum, true));
                streamNum++;
            }

            // mapping of stream to variable
            _streamVariables = new SortedDictionary <int, string>();
            foreach (var entry in _variableStreams)
            {
                _streamVariables.Put(entry.Value.First, entry.Key);
            }

            // determine visibility rules
            var visibility = EventRowRegexHelper.DetermineVisibility(_expandedPatternNode);

            // assemble all single-row variables for expression validation
            var allStreamNames = new string[_variableStreams.Count];
            var allTypes       = new EventType[_variableStreams.Count];

            streamNum = 0;
            foreach (var variableSingle in _variablesSingle)
            {
                allStreamNames[streamNum] = variableSingle;
                allTypes[streamNum]       = parentViewType;
                streamNum++;
            }
            foreach (var variableMultiple in variablesMultiple)
            {
                allStreamNames[streamNum] = variableMultiple;
                allTypes[streamNum]       = parentViewType;
                streamNum++;
            }

            // determine type service for use with DEFINE
            // validate each DEFINE clause expression
            ISet <string>             definedVariables = new HashSet <string>();
            IList <ExprAggregateNode> aggregateNodes   = new List <ExprAggregateNode>();
            var exprEvaluatorContext = new ExprEvaluatorContextStatement(statementContext, false);

            _isExprRequiresMultimatchState = new bool[_variableStreams.Count];

            for (var defineIndex = 0; defineIndex < matchRecognizeSpec.Defines.Count; defineIndex++)
            {
                var defineItem = matchRecognizeSpec.Defines[defineIndex];
                if (definedVariables.Contains(defineItem.Identifier))
                {
                    throw new ExprValidationException("Variable '" + defineItem.Identifier + "' has already been defined");
                }
                definedVariables.Add(defineItem.Identifier);

                // stream-type visibilities handled here
                var typeServiceDefines = EventRowRegexNFAViewFactoryHelper.BuildDefineStreamTypeServiceDefine(statementContext, _variableStreams, defineItem, visibility, parentViewType);

                var exprNodeResult    = HandlePreviousFunctions(defineItem.Expression);
                var validationContext = new ExprValidationContext(
                    typeServiceDefines,
                    statementContext.MethodResolutionService, null,
                    statementContext.SchedulingService,
                    statementContext.VariableService,
                    statementContext.TableService, exprEvaluatorContext,
                    statementContext.EventAdapterService,
                    statementContext.StatementName,
                    statementContext.StatementId,
                    statementContext.Annotations,
                    statementContext.ContextDescriptor,
                    statementContext.ScriptingService,
                    true, false, true, false, null, false);

                ExprNode validated;
                try {
                    // validate
                    validated = ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.MATCHRECOGDEFINE, exprNodeResult, validationContext);

                    // check aggregates
                    defineItem.Expression = validated;
                    ExprAggregateNodeUtil.GetAggregatesBottomUp(validated, aggregateNodes);
                    if (!aggregateNodes.IsEmpty())
                    {
                        throw new ExprValidationException("An aggregate function may not appear in a DEFINE clause");
                    }
                }
                catch (ExprValidationException ex) {
                    throw new ExprValidationException("Failed to validate condition expression for variable '" + defineItem.Identifier + "': " + ex.Message, ex);
                }

                // determine access to event properties from multi-matches
                var visitor = new ExprNodeIdentifierCollectVisitor();
                validated.Accept(visitor);
                var streamsRequired = visitor.StreamsRequired;
                foreach (var streamRequired in streamsRequired)
                {
                    if (streamRequired >= _variableStreams.Count)
                    {
                        var streamNumIdent = _variableStreams.Get(defineItem.Identifier).First;
                        _isExprRequiresMultimatchState[streamNumIdent] = true;
                        break;
                    }
                }
            }
            _isDefineAsksMultimatches  = CollectionUtil.IsAnySet(_isExprRequiresMultimatchState);
            _defineMultimatchEventBean = _isDefineAsksMultimatches ? EventRowRegexNFAViewFactoryHelper.GetDefineMultimatchBean(statementContext, _variableStreams, parentViewType) : null;

            // assign "prev" node indexes
            // Since an expression such as "prior(2, price), prior(8, price)" translates into {2, 8} the relative index is {0, 1}.
            // Map the expression-supplied index to a relative index
            var countPrev = 0;

            foreach (var entry in _callbacksPerIndex)
            {
                foreach (var callback in entry.Value)
                {
                    callback.AssignedIndex = countPrev;
                }
                countPrev++;
            }

            // determine type service for use with MEASURE
            IDictionary <string, object> measureTypeDef = new LinkedHashMap <string, object>();

            foreach (var variableSingle in _variablesSingle)
            {
                measureTypeDef.Put(variableSingle, parentViewType);
            }
            foreach (var variableMultiple in variablesMultiple)
            {
                measureTypeDef.Put(variableMultiple, new EventType[] { parentViewType });
            }
            var outputEventTypeName = statementContext.StatementId + "_rowrecog";

            _compositeEventType = (ObjectArrayEventType)statementContext.EventAdapterService.CreateAnonymousObjectArrayType(outputEventTypeName, measureTypeDef);
            StreamTypeService typeServiceMeasure = new StreamTypeServiceImpl(_compositeEventType, "MATCH_RECOGNIZE", true, statementContext.EngineURI);

            // find MEASURE clause aggregations
            var measureReferencesMultivar = false;
            IList <ExprAggregateNode> measureAggregateExprNodes = new List <ExprAggregateNode>();

            foreach (var measureItem in matchRecognizeSpec.Measures)
            {
                ExprAggregateNodeUtil.GetAggregatesBottomUp(measureItem.Expr, measureAggregateExprNodes);
            }
            if (!measureAggregateExprNodes.IsEmpty())
            {
                var isIStreamOnly = new bool[allStreamNames.Length];
                CompatExtensions.Fill(isIStreamOnly, true);
                var typeServiceAggregateMeasure  = new StreamTypeServiceImpl(allTypes, allStreamNames, isIStreamOnly, statementContext.EngineURI, false);
                var measureExprAggNodesPerStream = new Dictionary <int, IList <ExprAggregateNode> >();

                foreach (var aggregateNode in measureAggregateExprNodes)
                {
                    // validate absence of group-by
                    aggregateNode.ValidatePositionals();
                    if (aggregateNode.OptionalLocalGroupBy != null)
                    {
                        throw new ExprValidationException("Match-recognize does not allow aggregation functions to specify a group-by");
                    }

                    // validate node and params
                    var count   = 0;
                    var visitor = new ExprNodeIdentifierVisitor(true);

                    var validationContext = new ExprValidationContext(
                        typeServiceAggregateMeasure,
                        statementContext.MethodResolutionService, null,
                        statementContext.SchedulingService,
                        statementContext.VariableService,
                        statementContext.TableService,
                        exprEvaluatorContext,
                        statementContext.EventAdapterService,
                        statementContext.StatementName,
                        statementContext.StatementId,
                        statementContext.Annotations,
                        statementContext.ContextDescriptor,
                        statementContext.ScriptingService,
                        false, false, true, false, null, false);
                    foreach (var child in aggregateNode.ChildNodes)
                    {
                        var validated = ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.MATCHRECOGMEASURE, child, validationContext);
                        validated.Accept(visitor);
                        aggregateNode.SetChildNode(count++, new ExprNodeValidated(validated));
                    }
                    validationContext = new ExprValidationContext(
                        typeServiceMeasure, statementContext.MethodResolutionService, null,
                        statementContext.SchedulingService,
                        statementContext.VariableService,
                        statementContext.TableService,
                        exprEvaluatorContext,
                        statementContext.EventAdapterService,
                        statementContext.StatementName,
                        statementContext.StatementId,
                        statementContext.Annotations,
                        statementContext.ContextDescriptor,
                        statementContext.ScriptingService,
                        false, false, true, false, null, false);
                    aggregateNode.Validate(validationContext);

                    // verify properties used within the aggregation
                    var aggregatedStreams = new HashSet <int>();
                    foreach (var pair in visitor.ExprProperties)
                    {
                        aggregatedStreams.Add(pair.First);
                    }

                    int?multipleVarStream = null;
                    foreach (int streamNumAggregated in aggregatedStreams)
                    {
                        var variable = _streamVariables.Get(streamNumAggregated);
                        if (variablesMultiple.Contains(variable))
                        {
                            measureReferencesMultivar = true;
                            if (multipleVarStream == null)
                            {
                                multipleVarStream = streamNumAggregated;
                                continue;
                            }
                            throw new ExprValidationException("Aggregation functions in the measure-clause must only refer to properties of exactly one group variable returning multiple events");
                        }
                    }

                    if (multipleVarStream == null)
                    {
                        throw new ExprValidationException("Aggregation functions in the measure-clause must refer to one or more properties of exactly one group variable returning multiple events");
                    }

                    var aggNodesForStream = measureExprAggNodesPerStream.Get(multipleVarStream.Value);
                    if (aggNodesForStream == null)
                    {
                        aggNodesForStream = new List <ExprAggregateNode>();
                        measureExprAggNodesPerStream.Put(multipleVarStream.Value, aggNodesForStream);
                    }
                    aggNodesForStream.Add(aggregateNode);
                }

                var factoryDesc = AggregationServiceFactoryFactory.GetServiceMatchRecognize(_streamVariables.Count, measureExprAggNodesPerStream, typeServiceAggregateMeasure.EventTypes);
                _aggregationService     = factoryDesc.AggregationServiceFactory.MakeService(agentInstanceContext);
                _aggregationExpressions = factoryDesc.Expressions;
            }
            else
            {
                _aggregationService     = null;
                _aggregationExpressions = Collections.GetEmptyList <AggregationServiceAggExpressionDesc>();
            }

            // validate each MEASURE clause expression
            IDictionary <string, object> rowTypeDef = new LinkedHashMap <string, object>();
            var streamRefVisitor = new ExprNodeStreamUseCollectVisitor();

            foreach (var measureItem in matchRecognizeSpec.Measures)
            {
                if (measureItem.Name == null)
                {
                    throw new ExprValidationException("The measures clause requires that each expression utilizes the AS keyword to assign a column name");
                }
                var validated = ValidateMeasureClause(measureItem.Expr, typeServiceMeasure, variablesMultiple, _variablesSingle, statementContext);
                measureItem.Expr = validated;
                rowTypeDef.Put(measureItem.Name, validated.ExprEvaluator.ReturnType);
                validated.Accept(streamRefVisitor);
            }

            // Determine if any of the multi-var streams are referenced in the measures (non-aggregated only)
            foreach (var @ref in streamRefVisitor.Referenced)
            {
                var rootPropName = @ref.RootPropertyNameIfAny;
                if (rootPropName != null)
                {
                    if (variablesMultiple.Contains(rootPropName))
                    {
                        measureReferencesMultivar = true;
                        break;
                    }
                }

                var streamRequired = @ref.StreamReferencedIfAny;
                if (streamRequired != null)
                {
                    var streamVariable = _streamVariables.Get(streamRequired.Value);
                    if (streamVariable != null)
                    {
                        var def = _variableStreams.Get(streamVariable);
                        if (def != null && def.Second)
                        {
                            measureReferencesMultivar = true;
                            break;
                        }
                    }
                }
            }
            _isCollectMultimatches = measureReferencesMultivar || _isDefineAsksMultimatches;

            // create rowevent type
            var rowEventTypeName = statementContext.StatementId + "_rowrecogrow";

            _rowEventType = statementContext.EventAdapterService.CreateAnonymousMapType(rowEventTypeName, rowTypeDef);

            // validate partition-by expressions, if any
            if (!matchRecognizeSpec.PartitionByExpressions.IsEmpty())
            {
                var typeServicePartition = new StreamTypeServiceImpl(parentViewType, "MATCH_RECOGNIZE_PARTITION", true, statementContext.EngineURI);
                var validated            = new List <ExprNode>();
                var validationContext    = new ExprValidationContext(
                    typeServicePartition, statementContext.MethodResolutionService, null,
                    statementContext.SchedulingService, statementContext.VariableService, statementContext.TableService,
                    exprEvaluatorContext, statementContext.EventAdapterService, statementContext.StatementName,
                    statementContext.StatementId, statementContext.Annotations, statementContext.ContextDescriptor,
                    statementContext.ScriptingService,
                    false, false, true, false, null, false);
                foreach (var partitionExpr in matchRecognizeSpec.PartitionByExpressions)
                {
                    validated.Add(ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.MATCHRECOGPARTITION, partitionExpr, validationContext));
                }
                matchRecognizeSpec.PartitionByExpressions = validated;
            }

            // validate interval if present
            if (matchRecognizeSpec.Interval != null)
            {
                var validationContext =
                    new ExprValidationContext(
                        new StreamTypeServiceImpl(statementContext.EngineURI, false),
                        statementContext.MethodResolutionService, null, statementContext.SchedulingService,
                        statementContext.VariableService, statementContext.TableService, exprEvaluatorContext,
                        statementContext.EventAdapterService, statementContext.StatementName, statementContext.StatementId,
                        statementContext.Annotations, statementContext.ContextDescriptor, statementContext.ScriptingService,
                        false, false, true, false, null, false);
                matchRecognizeSpec.Interval.Validate(validationContext);
            }
        }