// 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"); } } }
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); }
public static void SetChildIdentNodesOptionalEvent(ExprNode exprNode) { ExprNodeIdentifierCollectVisitor visitor = new ExprNodeIdentifierCollectVisitor(); exprNode.Accept(visitor); foreach (ExprIdentNode node in visitor.ExprProperties) { node.IsOptionalEvent = true; } }
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; }
/// <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); }
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; } }
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; } }
/// <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); } }