private static RowRecogExprNode Replace( RowRecogExprNode optionalParent, RowRecogExprNode originalNode, IList<RowRecogExprNode> expandedRepeat) { if (optionalParent == null) { var newParentNode = new RowRecogExprNodeConcatenation(); newParentNode.ChildNodes.AddAll(expandedRepeat); return newParentNode; } // for nested nodes, use a concatenation instead if (optionalParent is RowRecogExprNodeNested || optionalParent is RowRecogExprNodeAlteration) { var concatenation = new RowRecogExprNodeConcatenation(); concatenation.ChildNodes.AddAll(expandedRepeat); optionalParent.ReplaceChildNode( originalNode, Collections.SingletonList<RowRecogExprNode>(concatenation)); } else { // concatenations are simply changed optionalParent.ReplaceChildNode(originalNode, expandedRepeat); } return null; }
/// <summary> /// Build a list of start states from the parent node. /// </summary> /// <param name="parent">to build start state for</param> /// <param name="variableDefinitions">each variable and its expressions</param> /// <param name="variableStreams">variable name and its stream number</param> /// <param name="exprRequiresMultimatchState">indicator whether multi-match state required</param> /// <returns>strand of regex state nodes</returns> protected internal static RowRecogNFAStrandResult BuildStartStates( RowRecogExprNode parent, IDictionary<string, ExprNode> variableDefinitions, IDictionary<string, Pair<int, bool>> variableStreams, bool[] exprRequiresMultimatchState ) { var nodeNumStack = new Stack<int>(); RowRecogNFAStrand strand = RecursiveBuildStatesInternal( parent, variableDefinitions, variableStreams, nodeNumStack, exprRequiresMultimatchState); // add end state var end = new RowRecogNFAStateEndForge(); end.NodeNumFlat = -1; foreach (RowRecogNFAStateForgeBase endStates in strand.EndStates) { endStates.AddState(end); } // assign node num as a counter var nodeNumberFlat = 0; foreach (RowRecogNFAStateForgeBase theBase in strand.AllStates) { theBase.NodeNumFlat = nodeNumberFlat++; } return new RowRecogNFAStrandResult(new List<RowRecogNFAStateForge>(strand.StartStates), strand.AllStates); }
public static IDictionary<string, ISet<string>> DetermineVisibility(RowRecogExprNode pattern) { IDictionary<string, ISet<string>> map = new Dictionary<string, ISet<string>>(); var path = new ArrayDeque<RowRecogExprNode>(); RecursiveFindPatternAtoms(pattern, path, map); return map; }
/// <summary> /// Inspect variables recursively. /// </summary> /// <param name="parent">parent regex expression node</param> /// <param name="isMultiple">if the variable in the stack is multiple of single</param> /// <param name="variablesSingle">single variables list</param> /// <param name="variablesMultiple">group variables list</param> public static void RecursiveInspectVariables( RowRecogExprNode parent, bool isMultiple, ISet<string> variablesSingle, ISet<string> variablesMultiple) { if (parent is RowRecogExprNodeNested) { var nested = (RowRecogExprNodeNested) parent; foreach (var child in parent.ChildNodes) { RecursiveInspectVariables( child, nested.Type.IsMultipleMatches() || isMultiple, variablesSingle, variablesMultiple); } } else if (parent is RowRecogExprNodeAlteration) { foreach (var childAlteration in parent.ChildNodes) { var singles = new LinkedHashSet<string>(); var multiples = new LinkedHashSet<string>(); RecursiveInspectVariables(childAlteration, isMultiple, singles, multiples); variablesMultiple.AddAll(multiples); variablesSingle.AddAll(singles); } variablesSingle.RemoveAll(variablesMultiple); } else if (parent is RowRecogExprNodeAtom) { var atom = (RowRecogExprNodeAtom) parent; var name = atom.Tag; if (variablesMultiple.Contains(name)) { return; } if (variablesSingle.Contains(name)) { variablesSingle.Remove(name); variablesMultiple.Add(name); return; } if (atom.Type.IsMultipleMatches()) { variablesMultiple.Add(name); return; } if (isMultiple) { variablesMultiple.Add(name); } else { variablesSingle.Add(name); } } else { foreach (var child in parent.ChildNodes) { RecursiveInspectVariables(child, isMultiple, variablesSingle, variablesMultiple); } } }
public RowRecogExprNode Copy( RowRecogExprNode nodeToCopy, RowRecogNFATypeEnum newType, ExpressionCopier expressionCopier) { var atom = (RowRecogExprNodeAtom) nodeToCopy; return new RowRecogExprNodeAtom(atom.Tag, newType, null); }
public static void RegExCollectAddSubNodesAddParentNode( RowRecogExprNode exprNode, ITree node, IDictionary<ITree, RowRecogExprNode> astRegExNodeMap) { RegExCollectAddSubNodes(exprNode, node, astRegExNodeMap); astRegExNodeMap.Put(node, exprNode); }
public RowRecogExprNode Copy( RowRecogExprNode nodeToCopy, RowRecogNFATypeEnum newType, ExpressionCopier expressionCopier) { var nested = (RowRecogExprNodeNested) nodeToCopy; var nestedCopy = new RowRecogExprNodeNested(newType, null); foreach (var inner in nested.ChildNodes) { var innerCopy = inner.CheckedCopy(expressionCopier); nestedCopy.AddChildNode(innerCopy); } return nestedCopy; }
private static void RecursiveCollectAtomsWExclude( RowRecogExprNode node, ISet<string> identifiers, string excludedTag) { if (node is RowRecogExprNodeAtom) { var atom = (RowRecogExprNodeAtom) node; if (!excludedTag.Equals(atom.Tag)) { identifiers.Add(atom.Tag); } } foreach (var child in node.ChildNodes) { RecursiveCollectAtomsWExclude(child, identifiers, excludedTag); } }
private static void RecursiveFindPatternAtoms( RowRecogExprNode parent, ArrayDeque<RowRecogExprNode> path, IDictionary<string, ISet<string>> map) { path.Add(parent); foreach (var child in parent.ChildNodes) { if (child is RowRecogExprNodeAtom) { HandleAtom((RowRecogExprNodeAtom) child, path, map); } else { RecursiveFindPatternAtoms(child, path, map); } } path.RemoveLast(); }
public static void RegExApplyActionRecursive( ITree node, IDictionary<ITree, RowRecogExprNode> astRegExNodeMap, RegExAction action) { RowRecogExprNode expr = astRegExNodeMap.Get(node); if (expr != null) { action.Invoke(expr, astRegExNodeMap, node); return; } for (int i = 0; i < node.ChildCount; i++) { RegExApplyActionRecursive(node.GetChild(i), astRegExNodeMap, action); } }
public static void RegExCollectAddSubNodes( RowRecogExprNode regexNode, ITree node, IDictionary<ITree, RowRecogExprNode> astRegExNodeMap) { if (regexNode == null) { throw ASTWalkException.From("Invalid null expression node for '" + ASTUtil.PrintNode(node) + "'"); } RegExAction action = (exprNode, astExprNodeMapX, nodeX) => { astExprNodeMapX.Remove(nodeX); regexNode.AddChildNode(exprNode); }; for (int i = 0; i < node.ChildCount; i++) { ITree childNode = node.GetChild(i); RegExApplyActionRecursive(childNode, astRegExNodeMap, action); } }
internal static void RunEquivalent( RegressionEnvironment env, string before, string after) { var hook = "@Hook(HookType=" + typeof(HookType).FullName + ".INTERNAL_COMPILE,Hook='" + SupportStatementCompileHook.ResetGetClassName() + "')"; var epl = hook + "@Name('s0') select * from SupportBean#keepall " + "match_recognize (" + " measures A as a" + " pattern (" + before + ")" + " define" + " A as A.TheString like \"A%\"" + ")"; var model = env.EplToModel(epl); env.CompileDeploy(model); env.UndeployAll(); var spec = SupportStatementCompileHook.GetSpecs()[0]; RowRecogExprNode expanded = null; try { expanded = RowRecogPatternExpandUtil.Expand( spec.Raw.MatchRecognizeSpec.Pattern, null); } catch (ExprValidationException e) { Assert.Fail(e.Message); } var writer = new StringWriter(); expanded.ToEPL(writer, RowRecogExprNodePrecedenceEnum.MINIMUM); Assert.AreEqual(after, writer.ToString()); }
public static RowRecogExprNode RegExGetRemoveTopNode( ITree node, IDictionary<ITree, RowRecogExprNode> astRowRegexNodeMap) { RowRecogExprNode regex = astRowRegexNodeMap.Get(node); if (regex != null) { astRowRegexNodeMap.Remove(node); return regex; } for (int i = 0; i < node.ChildCount; i++) { regex = RegExGetRemoveTopNode(node.GetChild(i), astRowRegexNodeMap); if (regex != null) { return regex; } } return null; }
private static IList<RowRecogExprNode> ExpandRepeat( RowRecogExprNode node, RowRecogExprRepeatDesc repeat, RowRecogNFATypeEnum type, RowRegexExprNodeCopier copier, ExpressionCopier expressionCopier) { // handle single-bounds (no ranges) IList<RowRecogExprNode> repeated = new List<RowRecogExprNode>(); if (repeat.Single != null) { ValidateExpression(repeat.Single); var numRepeated = (int) repeat.Single.Forge.ExprEvaluator.Evaluate(null, true, null); ValidateRange(numRepeated, 1, int.MaxValue); for (var i = 0; i < numRepeated; i++) { var copy = copier.Copy(node, type, expressionCopier); repeated.Add(copy); } return repeated; } // evaluate bounds int? lower = null; int? upper = null; if (repeat.Lower != null) { ValidateExpression(repeat.Lower); lower = (int?) repeat.Lower.Forge.ExprEvaluator.Evaluate(null, true, null); } if (repeat.Upper != null) { ValidateExpression(repeat.Upper); upper = (int?) repeat.Upper.Forge.ExprEvaluator.Evaluate(null, true, null); } // handle range if (lower != null && upper != null) { ValidateRange(lower.Value, 1, int.MaxValue); ValidateRange(upper.Value, 1, int.MaxValue); ValidateRange(lower.Value, 1, upper.Value); for (var i = 0; i < lower; i++) { var copy = copier.Copy(node, type, expressionCopier); repeated.Add(copy); } for (var i = lower.Value; i < upper; i++) { // makeInline type optional var newType = type; if (type == RowRecogNFATypeEnum.SINGLE) { newType = RowRecogNFATypeEnum.ONE_OPTIONAL; } else if (type == RowRecogNFATypeEnum.ONE_TO_MANY) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY; } else if (type == RowRecogNFATypeEnum.ONE_TO_MANY_RELUCTANT) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY_RELUCTANT; } var copy = copier.Copy(node, newType, expressionCopier); repeated.Add(copy); } return repeated; } // handle lower-bounds only if (upper == null) { ValidateRange(lower.Value, 1, int.MaxValue); for (var i = 0; i < lower; i++) { repeated.Add(copier.Copy(node, type, expressionCopier)); } // makeInline type optional var newType = type; if (type == RowRecogNFATypeEnum.SINGLE) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY; } else if (type == RowRecogNFATypeEnum.ONE_OPTIONAL) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY; } else if (type == RowRecogNFATypeEnum.ONE_OPTIONAL_RELUCTANT) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY_RELUCTANT; } else if (type == RowRecogNFATypeEnum.ONE_TO_MANY) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY; } else if (type == RowRecogNFATypeEnum.ONE_TO_MANY_RELUCTANT) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY_RELUCTANT; } var copy = copier.Copy(node, newType, expressionCopier); repeated.Add(copy); return repeated; } // handle upper-bounds only ValidateRange(upper.Value, 1, int.MaxValue); for (var i = 0; i < upper; i++) { // makeInline type optional var newType = type; if (type == RowRecogNFATypeEnum.SINGLE) { newType = RowRecogNFATypeEnum.ONE_OPTIONAL; } else if (type == RowRecogNFATypeEnum.ONE_TO_MANY) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY; } else if (type == RowRecogNFATypeEnum.ONE_TO_MANY_RELUCTANT) { newType = RowRecogNFATypeEnum.ZERO_TO_MANY_RELUCTANT; } var copy = copier.Copy(node, newType, expressionCopier); repeated.Add(copy); } return repeated; }
public static RowRecogExprNode Expand( RowRecogExprNode pattern, ExpressionCopier expressionCopier) { var visitor = new RowRecogExprNodeVisitorRepeat(); pattern.Accept(visitor); var newParentNode = pattern; // expand permutes var permutes = visitor.Permutes; permutes.SortInPlace( ( o1, o2) => { if (o1.Level > o2.Level) { return -1; } return o1.Level == o2.Level ? 0 : 1; }); foreach (var permute in permutes) { var alteration = ExpandPermute(permute.Permute, expressionCopier); var optionalNewParent = Replace( permute.OptionalParent, permute.Permute, Collections.SingletonList<RowRecogExprNode>(alteration)); if (optionalNewParent != null) { newParentNode = optionalNewParent; } } // expand atoms var atomPairs = visitor.Atoms; foreach (var pair in atomPairs) { var atom = pair.First; var expandedRepeat = ExpandRepeat(atom, atom.OptionalRepeat, atom.Type, ATOM_HANDLER, expressionCopier); var optionalNewParent = Replace(pair.Second, pair.First, expandedRepeat); if (optionalNewParent != null) { newParentNode = optionalNewParent; } } // expand nested var nestedPairs = visitor.Nesteds; nestedPairs.SortInPlace( ( o1, o2) => { if (o1.Level > o2.Level) { return -1; } return o1.Level == o2.Level ? 0 : 1; }); foreach (var pair in nestedPairs) { var nested = pair.Nested; var expandedRepeat = ExpandRepeat( nested, nested.OptionalRepeat, nested.Type, NESTED_HANDLER, expressionCopier); var optionalNewParent = Replace(pair.OptionalParent, pair.Nested, expandedRepeat); if (optionalNewParent != null) { newParentNode = optionalNewParent; } } return newParentNode; }
private static RowRecogNFAStrand RecursiveBuildStatesInternal( RowRecogExprNode node, IDictionary<string, ExprNode> variableDefinitions, IDictionary<string, Pair<int, bool>> variableStreams, Stack<int> nodeNumStack, bool[] exprRequiresMultimatchState ) { if (node is RowRecogExprNodeAlteration) { var nodeNum = 0; IList<RowRecogNFAStateForgeBase> cumulativeStartStates = new List<RowRecogNFAStateForgeBase>(); IList<RowRecogNFAStateForgeBase> cumulativeStates = new List<RowRecogNFAStateForgeBase>(); IList<RowRecogNFAStateForgeBase> cumulativeEndStates = new List<RowRecogNFAStateForgeBase>(); var isPassthrough = false; foreach (var child in node.ChildNodes) { nodeNumStack.Push(nodeNum); var strand = RecursiveBuildStatesInternal( child, variableDefinitions, variableStreams, nodeNumStack, exprRequiresMultimatchState); nodeNumStack.Pop(); cumulativeStartStates.AddAll(strand.StartStates); cumulativeStates.AddAll(strand.AllStates); cumulativeEndStates.AddAll(strand.EndStates); if (strand.IsPassthrough) { isPassthrough = true; } nodeNum++; } return new RowRecogNFAStrand( cumulativeStartStates, cumulativeEndStates, cumulativeStates, isPassthrough); } if (node is RowRecogExprNodeConcatenation) { var nodeNum = 0; var isPassthrough = true; IList<RowRecogNFAStateForgeBase> cumulativeStates = new List<RowRecogNFAStateForgeBase>(); var strands = new RowRecogNFAStrand[node.ChildNodes.Count]; foreach (var child in node.ChildNodes) { nodeNumStack.Push(nodeNum); strands[nodeNum] = RecursiveBuildStatesInternal( child, variableDefinitions, variableStreams, nodeNumStack, exprRequiresMultimatchState); nodeNumStack.Pop(); cumulativeStates.AddAll(strands[nodeNum].AllStates); if (!strands[nodeNum].IsPassthrough) { isPassthrough = false; } nodeNum++; } // determine start states: all states until the first non-passthrough start state IList<RowRecogNFAStateForgeBase> startStates = new List<RowRecogNFAStateForgeBase>(); for (var i = 0; i < strands.Length; i++) { startStates.AddAll(strands[i].StartStates); if (!strands[i].IsPassthrough) { break; } } // determine end states: all states from the back until the last non-passthrough end state IList<RowRecogNFAStateForgeBase> endStates = new List<RowRecogNFAStateForgeBase>(); for (var i = strands.Length - 1; i >= 0; i--) { endStates.AddAll(strands[i].EndStates); if (!strands[i].IsPassthrough) { break; } } // hook up the end state of each strand with the start states of each next strand for (var i = strands.Length - 1; i >= 1; i--) { var current = strands[i]; for (var j = i - 1; j >= 0; j--) { var prior = strands[j]; foreach (RowRecogNFAStateForgeBase endState in prior.EndStates) { foreach (RowRecogNFAStateForgeBase startState in current.StartStates) { endState.AddState(startState); } } if (!prior.IsPassthrough) { break; } } } return new RowRecogNFAStrand(startStates, endStates, cumulativeStates, isPassthrough); } if (node is RowRecogExprNodeNested) { var nested = (RowRecogExprNodeNested) node; nodeNumStack.Push(0); var strand = RecursiveBuildStatesInternal( node.ChildNodes[0], variableDefinitions, variableStreams, nodeNumStack, exprRequiresMultimatchState); nodeNumStack.Pop(); var isPassthrough = strand.IsPassthrough || nested.Type.IsOptional(); // if this is a repeating node then pipe back each end state to each begin state if (nested.Type.IsMultipleMatches()) { foreach (RowRecogNFAStateForgeBase endstate in strand.EndStates) { foreach (RowRecogNFAStateForgeBase startstate in strand.StartStates) { if (!endstate.NextStates.Contains(startstate)) { endstate.NextStates.Add(startstate); } } } } return new RowRecogNFAStrand(strand.StartStates, strand.EndStates, strand.AllStates, isPassthrough); } var atom = (RowRecogExprNodeAtom) node; // assign stream number for single-variables for most direct expression eval; multiple-variable gets -1 var streamNum = variableStreams.Get(atom.Tag).First; var multiple = variableStreams.Get(atom.Tag).Second; var expression = variableDefinitions.Get(atom.Tag); var exprRequiresMultimatch = exprRequiresMultimatchState[streamNum]; RowRecogNFAStateForgeBase nextState; if (atom.Type == RowRecogNFATypeEnum.ZERO_TO_MANY || atom.Type == RowRecogNFATypeEnum.ZERO_TO_MANY_RELUCTANT) { nextState = new RowRecogNFAStateZeroToManyForge( ToString(nodeNumStack), atom.Tag, streamNum, multiple, atom.Type.IsGreedy(), exprRequiresMultimatch, expression); } else if (atom.Type == RowRecogNFATypeEnum.ONE_TO_MANY || atom.Type == RowRecogNFATypeEnum.ONE_TO_MANY_RELUCTANT) { nextState = new RowRecogNFAStateOneToManyForge( ToString(nodeNumStack), atom.Tag, streamNum, multiple, atom.Type.IsGreedy(), exprRequiresMultimatch, expression); } else if (atom.Type == RowRecogNFATypeEnum.ONE_OPTIONAL || atom.Type == RowRecogNFATypeEnum.ONE_OPTIONAL_RELUCTANT) { nextState = new RowRecogNFAStateOneOptionalForge( ToString(nodeNumStack), atom.Tag, streamNum, multiple, atom.Type.IsGreedy(), exprRequiresMultimatch, expression); } else if (expression == null) { nextState = new RowRecogNFAStateAnyOneForge(ToString(nodeNumStack), atom.Tag, streamNum, multiple); } else { nextState = new RowRecogNFAStateFilterForge( ToString(nodeNumStack), atom.Tag, streamNum, multiple, exprRequiresMultimatch, expression); } return new RowRecogNFAStrand( Collections.SingletonList(nextState), Collections.SingletonList(nextState), Collections.SingletonList(nextState), atom.Type.IsOptional()); }
public static RowRecogPlan ValidateAndPlan( IContainer container, EventType parentEventType, bool unbound, StatementBaseInfo @base, StatementCompileTimeServices services) { var statementRawInfo = @base.StatementRawInfo; var matchRecognizeSpec = @base.StatementSpec.Raw.MatchRecognizeSpec; var annotations = statementRawInfo.Annotations; var iterateOnly = HintEnum.ITERATE_ONLY.GetHint(annotations) != null; var additionalForgeables = new List<StmtClassForgeableFactory>(); // Expanded pattern already there RowRecogExprNode expandedPatternNode = matchRecognizeSpec.Pattern; // Determine single-row and multiple-row variables var variablesSingle = new LinkedHashSet<string>(); var variablesMultiple = new LinkedHashSet<string>(); RowRecogHelper.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; var 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 var streamVariables = new OrderedListDictionary<int, string>(); foreach (var entry in variableStreams) { streamVariables.Put(entry.Value.First, entry.Key); } // determine visibility rules var visibility = RowRecogHelper.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] = parentEventType; streamNum++; } foreach (var variableMultiple in variablesMultiple) { allStreamNames[streamNum] = variableMultiple; allTypes[streamNum] = parentEventType; 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 isExprRequiresMultimatchState = new bool[variableStreams.Count]; var previousNodes = new OrderedListDictionary<int, IList<ExprPreviousMatchRecognizeNode>>(); for (var defineIndex = 0; defineIndex < matchRecognizeSpec.Defines.Count; defineIndex++) { MatchRecognizeDefineItem 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 = BuildDefineStreamTypeServiceDefine( defineIndex, variableStreams, defineItem, visibility, parentEventType, statementRawInfo, services); var exprNodeResult = HandlePreviousFunctions(defineItem.Expression, previousNodes); var validationContext = new ExprValidationContextBuilder(typeServiceDefines, statementRawInfo, services) .WithAllowBindingConsumption(true) .WithDisablePropertyExpressionEventCollCache(true) .Build(); ExprNode validated; try { // validate validated = ExprNodeUtilityValidate.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 ExprNodeStreamRequiredVisitor(); 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; } } } var defineAsksMultimatches = CollectionUtil.IsAnySet(isExprRequiresMultimatchState); // determine type service for use with MEASURE IDictionary<string, object> measureTypeDef = new LinkedHashMap<string, object>(); foreach (var variableSingle in variablesSingle) { measureTypeDef.Put(variableSingle, parentEventType); } foreach (var variableMultiple in variablesMultiple) { measureTypeDef.Put(variableMultiple, new[] {parentEventType}); } var compositeTypeName = services.EventTypeNameGeneratorStatement.AnonymousRowrecogCompositeName; var compositeTypeMetadata = new EventTypeMetadata( compositeTypeName, @base.ModuleName, EventTypeTypeClass.MATCHRECOGDERIVED, EventTypeApplicationType.OBJECTARR, NameAccessModifier.TRANSIENT, EventTypeBusModifier.NONBUS, false, EventTypeIdPair.Unassigned()); var compositeEventType = BaseNestableEventUtil.MakeOATypeCompileTime( compositeTypeMetadata, measureTypeDef, null, null, null, null, services.BeanEventTypeFactoryPrivate, services.EventTypeCompileTimeResolver); services.EventTypeCompileTimeRegistry.NewType(compositeEventType); StreamTypeService compositeTypeServiceMeasure = new StreamTypeServiceImpl(compositeEventType, "MATCH_RECOGNIZE", true); // find MEASURE clause aggregations var measureReferencesMultivar = false; IList<ExprAggregateNode> measureAggregateExprNodes = new List<ExprAggregateNode>(); foreach (var measureItem in matchRecognizeSpec.Measures) { ExprAggregateNodeUtil.GetAggregatesBottomUp(measureItem.Expr, measureAggregateExprNodes); } AggregationServiceForgeDesc[] aggregationServices = null; if (!measureAggregateExprNodes.IsEmpty()) { aggregationServices = PlanAggregations( measureAggregateExprNodes, compositeTypeServiceMeasure, allStreamNames, allTypes, streamVariables, variablesMultiple, @base, services); foreach (AggregationServiceForgeDesc svc in aggregationServices) { if (svc != null) { additionalForgeables.AddAll(svc.AdditionalForgeables); } } } // 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, compositeTypeServiceMeasure, variablesMultiple, variablesSingle, statementRawInfo, services); measureItem.Expr = validated; rowTypeDef.Put(measureItem.Name, validated.Forge.EvaluationType); 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; } } } } var collectMultimatches = measureReferencesMultivar || defineAsksMultimatches; // create rowevent type var rowTypeName = services.EventTypeNameGeneratorStatement.AnonymousRowrecogRowName; var rowTypeMetadata = new EventTypeMetadata( rowTypeName, @base.ModuleName, EventTypeTypeClass.MATCHRECOGDERIVED, EventTypeApplicationType.MAP, NameAccessModifier.TRANSIENT, EventTypeBusModifier.NONBUS, false, EventTypeIdPair.Unassigned()); var rowEventType = BaseNestableEventUtil.MakeMapTypeCompileTime( rowTypeMetadata, rowTypeDef, null, null, null, null, services.BeanEventTypeFactoryPrivate, services.EventTypeCompileTimeResolver); services.EventTypeCompileTimeRegistry.NewType(rowEventType); // validate partition-by expressions, if any ExprNode[] partitionBy; MultiKeyClassRef partitionMultiKey; if (!matchRecognizeSpec.PartitionByExpressions.IsEmpty()) { StreamTypeService typeServicePartition = new StreamTypeServiceImpl( parentEventType, "MATCH_RECOGNIZE_PARTITION", true); IList<ExprNode> validated = new List<ExprNode>(); var validationContext = new ExprValidationContextBuilder(typeServicePartition, statementRawInfo, services) .WithAllowBindingConsumption(true) .Build(); foreach (var partitionExpr in matchRecognizeSpec.PartitionByExpressions) { validated.Add( ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.MATCHRECOGPARTITION, partitionExpr, validationContext)); } matchRecognizeSpec.PartitionByExpressions = validated; partitionBy = ExprNodeUtilityQuery.ToArray(validated); MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKey(partitionBy, false, @base.StatementRawInfo, services.SerdeResolver); partitionMultiKey = multiKeyPlan.ClassRef; additionalForgeables.AddAll(multiKeyPlan.MultiKeyForgeables); } else { partitionBy = null; partitionMultiKey = null; } // validate interval if present if (matchRecognizeSpec.Interval != null) { var validationContext = new ExprValidationContextBuilder(new StreamTypeServiceImpl(false), statementRawInfo, services) .WithAllowBindingConsumption(true) .Build(); var validated = (ExprTimePeriod) ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.MATCHRECOGINTERVAL, matchRecognizeSpec.Interval.TimePeriodExpr, validationContext); matchRecognizeSpec.Interval.TimePeriodExpr = validated; } // compile variable definition expressions IDictionary<string, ExprNode> variableDefinitions = new Dictionary<string, ExprNode>(); foreach (var defineItem in matchRecognizeSpec.Defines) { variableDefinitions.Put(defineItem.Identifier, defineItem.Expression); } // create evaluators var columnNames = new string[matchRecognizeSpec.Measures.Count]; var columnForges = new ExprNode[matchRecognizeSpec.Measures.Count]; var count = 0; foreach (var measureItem in matchRecognizeSpec.Measures) { columnNames[count] = measureItem.Name; columnForges[count] = measureItem.Expr; count++; } // build states var strand = RowRecogHelper.BuildStartStates( expandedPatternNode, variableDefinitions, variableStreams, isExprRequiresMultimatchState); var startStates = strand.StartStates.ToArray(); RowRecogNFAStateForge[] allStates = strand.AllStates.ToArray(); if (Log.IsInfoEnabled) { Log.Info("NFA tree:\n" + RowRecogNFAViewUtil.Print(startStates)); } // determine names of multimatching variables string[] multimatchVariablesArray; int[] multimatchStreamNumToVariable; int[] multimatchVariableToStreamNum; if (variablesSingle.Count == variableStreams.Count) { multimatchVariablesArray = new string[0]; multimatchStreamNumToVariable = new int[0]; multimatchVariableToStreamNum = new int[0]; } else { multimatchVariablesArray = new string[variableStreams.Count - variablesSingle.Count]; multimatchVariableToStreamNum = new int[multimatchVariablesArray.Length]; multimatchStreamNumToVariable = new int[variableStreams.Count]; CompatExtensions.Fill(multimatchStreamNumToVariable, -1); count = 0; foreach (var entry in variableStreams) { if (entry.Value.Second) { var index = count; multimatchVariablesArray[index] = entry.Key; multimatchVariableToStreamNum[index] = entry.Value.First; multimatchStreamNumToVariable[entry.Value.First] = index; count++; } } } var numEventsEventsPerStreamDefine = defineAsksMultimatches ? variableStreams.Count + 1 : variableStreams.Count; // determine interval-or-terminated var orTerminated = matchRecognizeSpec.Interval != null && matchRecognizeSpec.Interval.IsOrTerminated; TimePeriodComputeForge intervalCompute = null; if (matchRecognizeSpec.Interval != null) { intervalCompute = matchRecognizeSpec.Interval.TimePeriodExpr.TimePeriodComputeForge; } EventType multimatchEventType = null; if (defineAsksMultimatches) { multimatchEventType = GetDefineMultimatchEventType(variableStreams, parentEventType, @base, services); } // determine previous-access indexes and 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 int[] previousRandomAccessIndexes = null; if (!previousNodes.IsEmpty()) { previousRandomAccessIndexes = new int[previousNodes.Count]; var countPrev = 0; foreach (var entry in previousNodes) { previousRandomAccessIndexes[countPrev] = entry.Key; foreach (var callback in entry.Value) { callback.AssignedIndex = countPrev; } countPrev++; } } RowRecogDescForge forge = new RowRecogDescForge( parentEventType, rowEventType, compositeEventType, multimatchEventType, multimatchStreamNumToVariable, multimatchVariableToStreamNum, partitionBy, partitionMultiKey, variableStreams, matchRecognizeSpec.Interval != null, iterateOnly, unbound, orTerminated, collectMultimatches, defineAsksMultimatches, numEventsEventsPerStreamDefine, multimatchVariablesArray, startStates, allStates, matchRecognizeSpec.IsAllMatches, matchRecognizeSpec.Skip.Skip, columnForges, columnNames, intervalCompute, previousRandomAccessIndexes, aggregationServices); return new RowRecogPlan(forge, additionalForgeables); }