public static FilterSpecCompiled MakeFilterSpec( EventType eventType, string eventTypeName, IList<ExprNode> filterExpessions, PropertyEvalSpec optionalPropertyEvalSpec, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, StreamTypeService streamTypeService, string optionalStreamName, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { // Validate all nodes, make sure each returns a boolean and types are good; // Also decompose all AND super nodes into individual expressions var validatedNodes = ValidateAllowSubquery( ExprNodeOrigin.FILTER, filterExpessions, streamTypeService, taggedEventTypes, arrayEventTypes, statementRawInfo, services); return Build( validatedNodes, eventType, eventTypeName, optionalPropertyEvalSpec, taggedEventTypes, arrayEventTypes, streamTypeService, optionalStreamName, statementRawInfo, services); }
public static FilterSpecParamForge HandleRangeNode( ExprBetweenNode betweenNode, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, string statementName, StatementRawInfo raw, StatementCompileTimeServices services) { var left = betweenNode.ChildNodes[0]; ExprFilterSpecLookupableForge lookupable = null; if (left is ExprFilterOptimizableNode) { var filterOptimizableNode = (ExprFilterOptimizableNode) left; lookupable = filterOptimizableNode.FilterLookupable; } else if (FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.LKUPCOMPOSITE, raw, services) && IsLimitedLookupableExpression(left)) { lookupable = MakeLimitedLookupableForgeMayNull(left, raw, services); } if (lookupable == null) { return null; } FilterOperator op = FilterOperatorExtensions.ParseRangeOperator( betweenNode.IsLowEndpointIncluded, betweenNode.IsHighEndpointIncluded, betweenNode.IsNotBetween); var low = HandleRangeNodeEndpoint(betweenNode.ChildNodes[1], taggedEventTypes, arrayEventTypes, allTagNamesOrdered, statementName, raw, services); var high = HandleRangeNodeEndpoint(betweenNode.ChildNodes[2], taggedEventTypes, arrayEventTypes, allTagNamesOrdered, statementName, raw, services); return low == null || high == null ? null : new FilterSpecParamRangeForge(lookupable, op, low, high); }
public static IList<ExprNode> ValidateAllowSubquery( ExprNodeOrigin exprNodeOrigin, IList<ExprNode> exprNodes, StreamTypeService streamTypeService, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { IList<ExprNode> validatedNodes = new List<ExprNode>(); ExprValidationContext validationContext = new ExprValidationContextBuilder(streamTypeService, statementRawInfo, services) .WithAllowBindingConsumption(true) .WithIsFilterExpression(true) .Build(); foreach (var node in exprNodes) { // Determine subselects var visitor = new ExprNodeSubselectDeclaredDotVisitor(); node.Accept(visitor); // Compile subselects if (!visitor.Subselects.IsEmpty()) { // The outer event type is the filtered-type itself foreach (var subselect in visitor.Subselects) { try { SubSelectHelperFilters.HandleSubselectSelectClauses( subselect, streamTypeService.EventTypes[0], streamTypeService.StreamNames[0], streamTypeService.StreamNames[0], taggedEventTypes, arrayEventTypes, statementRawInfo, services); } catch (ExprValidationException ex) { throw new ExprValidationException( "Failed to validate " + ExprNodeUtilityMake.GetSubqueryInfoText(subselect) + ": " + ex.Message, ex); } } } var validated = ExprNodeUtilityValidate.GetValidatedSubtree(exprNodeOrigin, node, validationContext); validatedNodes.Add(validated); if (validated.Forge.EvaluationType != typeof(bool?) && validated.Forge.EvaluationType != typeof(bool)) { throw new ExprValidationException( "Filter expression not returning a boolean value: '" + ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(validated) + "'"); } } return validatedNodes; }
public static FilterSpecCompiledDesc Build( FilterSpecValidatedDesc validatedDesc, EventType eventType, string eventTypeName, PropertyEvalSpec optionalPropertyEvalSpec, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, StreamTypeService streamTypeService, string optionalStreamName, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices) { var compiled = BuildNoStmtCtx( validatedDesc.Expressions, eventType, eventTypeName, optionalStreamName, optionalPropertyEvalSpec, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, streamTypeService, statementRawInfo, compileTimeServices); return new FilterSpecCompiledDesc(compiled, validatedDesc.AdditionalForgeables); }
private static void LogFilterPlans( IList<ExprNode> validatedNodes, FilterSpecPlanForge plan, EventType eventType, string optionalStreamName, StatementRawInfo statementRawInfo) { var buf = new StringBuilder(); buf .Append("Filter plan for statement '") .Append(statementRawInfo.StatementName) .Append("' filtering event type '") .Append(eventType.Name + "'"); if (optionalStreamName != null) { buf.Append(" alias '" + optionalStreamName + "'"); } if (validatedNodes.IsEmpty()) { buf.Append(" empty"); } else { var andNode = ExprNodeUtilityMake.ConnectExpressionsByLogicalAndWhenNeeded(validatedNodes); var expression = ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(andNode); buf .Append(" expression '") .Append(expression) .Append("' for ") .Append(plan.Paths.Length) .Append(" paths"); } buf.Append(Environment.NewLine); plan.AppendPlan(buf); Log.Info(buf.ToString()); }
public static PatternStreamSpecCompiled CompilePattern( PatternStreamSpecRaw streamSpecRaw, ISet<string> eventTypeReferences, bool isInsertInto, bool isJoin, bool isContextDeclaration, bool isOnTrigger, string optionalStreamName, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { return CompilePatternWTags( streamSpecRaw, eventTypeReferences, isInsertInto, null, null, isJoin, isContextDeclaration, isOnTrigger, streamNum, statementRawInfo, services); }
private static FilterSpecPlanPathTripletForge HandleOrAlternateExpression( ExprOrNode orNode, bool performConditionPlanning, IDictionary <string, Pair <EventType, string> > taggedEventTypes, IDictionary <string, Pair <EventType, string> > arrayEventTypes, ISet <string> allTagNamesOrdered, string statementName, StreamTypeService streamTypeService, StatementRawInfo raw, StatementCompileTimeServices services) { IList <ExprNode> valueExpressions = new List <ExprNode>(orNode.ChildNodes.Length); foreach (ExprNode child in orNode.ChildNodes) { FilterSpecExprNodeVisitorValueLimitedExpr visitor = new FilterSpecExprNodeVisitorValueLimitedExpr(); child.Accept(visitor); if (visitor.IsLimited) { valueExpressions.Add(child); } } // The or-node must have a single constituent and one or more value expressions if (orNode.ChildNodes.Length != valueExpressions.Count + 1) { return(null); } IList <ExprNode> constituents = new List <ExprNode>(orNode.ChildNodes); constituents.RemoveAll(valueExpressions); if (constituents.Count != 1) { throw new IllegalStateException("Found multiple constituents"); } ExprNode constituent = constituents[0]; FilterSpecPlanPathTripletForge triplet = MakeFilterParam( constituent, performConditionPlanning, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, statementName, streamTypeService, raw, services); if (triplet == null) { return(null); } ExprNode controlConfirm = ExprNodeUtilityMake.ConnectExpressionsByLogicalOrWhenNeeded(valueExpressions); return(new FilterSpecPlanPathTripletForge(triplet.Param, controlConfirm)); }
public static FilterSpecCompiled BuildNoStmtCtx( IList<ExprNode> validatedNodes, EventType eventType, string eventTypeName, string optionalStreamName, PropertyEvalSpec optionalPropertyEvalSpec, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, StreamTypeService streamTypeService, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices) { PropertyEvaluatorForge optionalPropertyEvaluator = null; if (optionalPropertyEvalSpec != null) { optionalPropertyEvaluator = PropertyEvaluatorForgeFactory.MakeEvaluator( optionalPropertyEvalSpec, eventType, optionalStreamName, statementRawInfo, compileTimeServices); } // unwind "and" and "or" var unwound = FilterSpecCompilerIndexPlannerUnwindAndOr.UnwindAndOr(validatedNodes); var args = new FilterSpecCompilerArgs( taggedEventTypes, arrayEventTypes, allTagNamesOrdered, streamTypeService, null, statementRawInfo, compileTimeServices); var plan = FilterSpecCompilerIndexPlanner.PlanFilterParameters(unwound, args); var hook = (FilterSpecCompileHook) ImportUtil.GetAnnotationHook( statementRawInfo.Annotations, HookType.INTERNAL_FILTERSPEC, typeof(FilterSpecCompileHook), compileTimeServices.ImportServiceCompileTime); hook?.FilterIndexPlan(eventType, unwound, plan); if (compileTimeServices.Configuration.Compiler.Logging.IsEnableFilterPlan) { LogFilterPlans(unwound, plan, eventType, optionalStreamName, statementRawInfo); } if (Log.IsDebugEnabled) { Log.Debug(".makeFilterSpec spec=" + plan); } return new FilterSpecCompiled(eventType, eventTypeName, plan, optionalPropertyEvaluator); }
public static StreamSpecCompiledDesc Compile( StreamSpecRaw spec, ISet<string> eventTypeReferences, bool isInsertInto, bool isJoin, bool isContextDeclaration, bool isOnTrigger, string optionalStreamName, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { if (spec is DBStatementStreamSpec dbStatementStreamSpec) { return new StreamSpecCompiledDesc(dbStatementStreamSpec, EmptyList<StmtClassForgeableFactory>.Instance); } if (spec is FilterStreamSpecRaw filterStreamSpecRaw) { return CompileFilter( filterStreamSpecRaw, isInsertInto, isJoin, isContextDeclaration, isOnTrigger, optionalStreamName, statementRawInfo, services); } if (spec is PatternStreamSpecRaw patternStreamSpecRaw) { return CompilePattern( patternStreamSpecRaw, eventTypeReferences, isInsertInto, isJoin, isContextDeclaration, isOnTrigger, optionalStreamName, streamNum, statementRawInfo, services); } if (spec is MethodStreamSpec methodStreamSpec) { return new StreamSpecCompiledDesc( CompileMethod(methodStreamSpec), EmptyList<StmtClassForgeableFactory>.Instance); } throw new IllegalStateException("Unrecognized stream spec " + spec); }
private static StreamTypeService GetStreamTypeService( IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, EvalForgeNode forge, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { var filterTypes = new LinkedHashMap<string, Pair<EventType, string>>(); filterTypes.PutAll(taggedEventTypes); // handle array tags (match-until clause) if (arrayEventTypes != null) { var eventTypeName = services.EventTypeNameGeneratorStatement.GetAnonymousPatternName(streamNum, forge.FactoryNodeId); var metadata = new EventTypeMetadata( eventTypeName, statementRawInfo.ModuleName, EventTypeTypeClass.PATTERNDERIVED, EventTypeApplicationType.MAP, NameAccessModifier.TRANSIENT, EventTypeBusModifier.NONBUS, false, EventTypeIdPair.Unassigned()); var mapProperties = GetMapProperties( new Dictionary<string, Pair<EventType, string>>(), arrayEventTypes); var mapEventType = BaseNestableEventUtil.MakeMapTypeCompileTime( metadata, mapProperties, null, null, null, null, services.BeanEventTypeFactoryPrivate, services.EventTypeCompileTimeResolver); services.EventTypeCompileTimeRegistry.NewType(mapEventType); EventType arrayTagCompositeEventType = mapEventType; foreach (var entry in arrayEventTypes) { var tag = entry.Key; if (!filterTypes.ContainsKey(tag)) { var pair = new Pair<EventType, string>(arrayTagCompositeEventType, tag); filterTypes.Put(tag, pair); } } } return new StreamTypeServiceImpl(filterTypes, true, false); }
internal static ExprFilterSpecLookupableForge MakeLimitedLookupableForgeMayNull( ExprNode lookupable, StatementRawInfo raw, StatementCompileTimeServices services) { if (!HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.LKUPCOMPOSITE, raw, services)) { return null; } var lookupableType = lookupable.Forge.EvaluationType; var expression = ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(lookupable); var getterForge = new FilterSpecCompilerIndexLimitedLookupableGetterForge(lookupable); var serde = services.SerdeResolver.SerdeForFilter(lookupableType, raw); return new ExprFilterSpecLookupableForge(expression, getterForge, null, lookupableType, true, serde); }
public FilterSpecCompilerArgs( IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, StreamTypeService streamTypeService, ContextCompileTimeDescriptor contextDescriptor, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices) { this.taggedEventTypes = taggedEventTypes; this.arrayEventTypes = arrayEventTypes; this.streamTypeService = streamTypeService; this.contextDescriptor = contextDescriptor; this.statementRawInfo = statementRawInfo; this.compileTimeServices = compileTimeServices; }
public static StreamSpecCompiled Compile( StreamSpecRaw spec, ISet<string> eventTypeReferences, bool isInsertInto, bool isJoin, bool isContextDeclaration, bool isOnTrigger, string optionalStreamName, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { if (spec is DBStatementStreamSpec) { return (DBStatementStreamSpec) spec; } if (spec is FilterStreamSpecRaw) { return CompileFilter( (FilterStreamSpecRaw) spec, isInsertInto, isJoin, isContextDeclaration, isOnTrigger, optionalStreamName, statementRawInfo, services); } if (spec is PatternStreamSpecRaw) { return CompilePattern( (PatternStreamSpecRaw) spec, eventTypeReferences, isInsertInto, isJoin, isContextDeclaration, isOnTrigger, optionalStreamName, streamNum, statementRawInfo, services); } if (spec is MethodStreamSpec) { return CompileMethod((MethodStreamSpec) spec); } throw new IllegalStateException("Unrecognized stream spec " + spec); }
internal static FilterSpecParamForge HandleBooleanLimited( ExprNode constituent, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, StreamTypeService streamTypeService, StatementRawInfo raw, StatementCompileTimeServices services) { if (!HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.BOOLCOMPOSITE, raw, services)) { return null; } // prequalify var prequalified = Prequalify(constituent); if (!prequalified) { return null; } // determine rewrite var desc = FindRewrite(constituent); if (desc == null) { return null; } // there is no value expression, i.e. "select * from SupportBean(theString = intPrimitive)" if (desc is RewriteDescriptorNoValueExpr) { var reboolExpression = ExprNodeUtilityPrint.ToExpressionStringMinPrecedence(constituent, new ExprNodeRenderableFlags(false)); var lookupable = new ExprFilterSpecLookupableForge(reboolExpression, null, constituent.Forge, null, true, null); return new FilterSpecParamValueNullForge(lookupable, FilterOperator.REBOOL); } // there is no value expression, i.e. "select * from SupportBean(theString regexp 'abc')" var withValueExpr = (RewriteDescriptorWithValueExpr) desc; ExprNode valueExpression = withValueExpr.ValueExpression; var valueExpressionType = valueExpression.Forge.EvaluationType; var replacement = new ExprFilterReboolValueNode(valueExpressionType); ExprNodeUtilityModify.ReplaceChildNode(withValueExpr.ValueExpressionParent, valueExpression, replacement); var validationContext = new ExprValidationContextBuilder(streamTypeService, raw, services).WithIsFilterExpression(true).Build(); var rebool = ExprNodeUtilityValidate.GetValidatedSubtree(ExprNodeOrigin.FILTER, constituent, validationContext); DataInputOutputSerdeForge serde = services.SerdeResolver.SerdeForFilter(valueExpressionType, raw); var convertor = GetMatchEventConvertor(valueExpression, taggedEventTypes, arrayEventTypes, allTagNamesOrdered); var reboolExpressionX = ExprNodeUtilityPrint.ToExpressionStringMinPrecedence(constituent, new ExprNodeRenderableFlags(false)); var lookupableX = new ExprFilterSpecLookupableForge(reboolExpressionX, null, rebool.Forge, valueExpressionType, true, serde); return new FilterSpecParamValueLimitedExprForge(lookupableX, FilterOperator.REBOOL, valueExpression, convertor, null); }
private static FilterSpecParamForge HandleLimitedExpr( FilterOperator op, ExprNode lookupable, ExprNode value, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, StatementRawInfo raw, StatementCompileTimeServices services) { ExprFilterSpecLookupableForge lookupableForge; var lookupableType = lookupable.Forge.EvaluationType; var valueType = value.Forge.EvaluationType; if (lookupable is ExprIdentNode) { if (!FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.VALUECOMPOSITE, raw, services)) { return null; } var identNode = (ExprIdentNode) lookupable; if (!identNode.FilterLookupEligible) { return null; } lookupableForge = identNode.FilterLookupable; } else { if (!FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.LKUPCOMPOSITE, raw, services)) { return null; } lookupableForge = MakeLimitedLookupableForgeMayNull(lookupable, raw, services); if (lookupableForge == null) { return null; } } var convertor = GetMatchEventConvertor(value, taggedEventTypes, arrayEventTypes, allTagNamesOrdered); var numberCoercer = GetNumberCoercer(lookupableType, valueType, lookupableForge.Expression); return new FilterSpecParamValueLimitedExprForge(lookupableForge, op, value, convertor, numberCoercer); }
public static FilterSpecCompiled BuildNoStmtCtx( IList<ExprNode> validatedNodes, EventType eventType, string eventTypeName, string optionalStreamName, PropertyEvalSpec optionalPropertyEvalSpec, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, StreamTypeService streamTypeService, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices ) { PropertyEvaluatorForge optionalPropertyEvaluator = null; if (optionalPropertyEvalSpec != null) { optionalPropertyEvaluator = PropertyEvaluatorForgeFactory.MakeEvaluator( optionalPropertyEvalSpec, eventType, optionalStreamName, statementRawInfo, compileTimeServices); } var args = new FilterSpecCompilerArgs( taggedEventTypes, arrayEventTypes, streamTypeService, null, statementRawInfo, compileTimeServices); IList<FilterSpecParamForge>[] spec = FilterSpecCompilerPlanner.PlanFilterParameters(validatedNodes, args); if (Log.IsDebugEnabled) { Log.Debug(".makeFilterSpec spec=" + spec); } return new FilterSpecCompiled(eventType, eventTypeName, spec, optionalPropertyEvaluator); }
internal static bool HasLevelOrHint( FilterSpecCompilerIndexPlannerHint requiredHint, StatementRawInfo raw, StatementCompileTimeServices services) { var config = services.Configuration.Compiler.Execution.FilterIndexPlanning; if (config == ConfigurationCompilerExecution.FilterIndexPlanningEnum.ADVANCED) { return true; } var hints = HintEnum.FILTERINDEX.GetHintAssignedValues(raw.Annotations); if (hints == null) { return false; } foreach (var hint in hints) { var hintAtoms = HintEnumExtensions.SplitCommaUnlessInParen(hint); for (var i = 0; i < hintAtoms.Length; i++) { var hintAtom = hintAtoms[i]; var hintLowercase = hintAtom.ToLowerInvariant().Trim(); FilterSpecCompilerIndexPlannerHint? found = null; foreach (var available in EnumHelper.GetValues<FilterSpecCompilerIndexPlannerHint>()) { if (hintLowercase.Equals(available.GetNameInvariant())) { found = available; if (requiredHint == available) { return true; } } } if (found == null) { throw new ExprValidationException("Unrecognized filterindex hint value '" + hintAtom + "'"); } } } return false; }
public static FilterSpecCompiled Build( IList<ExprNode> validatedNodes, EventType eventType, string eventTypeName, PropertyEvalSpec optionalPropertyEvalSpec, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, StreamTypeService streamTypeService, string optionalStreamName, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices) { return BuildNoStmtCtx( validatedNodes, eventType, eventTypeName, optionalStreamName, optionalPropertyEvalSpec, taggedEventTypes, arrayEventTypes, streamTypeService, statementRawInfo, compileTimeServices); }
private static void RecursiveCompile( EvalForgeNode evalNode, ISet<string> eventTypeReferences, bool isInsertInto, MatchEventSpec tags, Stack<EvalForgeNode> parentNodeStack, ISet<string> allTagNamesOrdered, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { parentNodeStack.Push(evalNode); foreach (var child in evalNode.ChildNodes) { RecursiveCompile( child, eventTypeReferences, isInsertInto, tags, parentNodeStack, allTagNamesOrdered, streamNum, statementRawInfo, services); } parentNodeStack.Pop(); IDictionary<string, Pair<EventType, string>> newTaggedEventTypes = null; IDictionary<string, Pair<EventType, string>> newArrayEventTypes = null; if (evalNode is EvalFilterForgeNode) { var filterNode = (EvalFilterForgeNode) evalNode; var eventName = filterNode.RawFilterSpec.EventTypeName; if (services.TableCompileTimeResolver.Resolve(eventName) != null) { throw new ExprValidationException("Tables cannot be used in pattern filter atoms"); } var resolvedEventType = ResolveTypeName(eventName, services.EventTypeCompileTimeResolver); var finalEventType = resolvedEventType; var optionalTag = filterNode.EventAsName; var isPropertyEvaluation = false; var isParentMatchUntil = IsParentMatchUntil(evalNode, parentNodeStack); // obtain property event type, if final event type is properties if (filterNode.RawFilterSpec.OptionalPropertyEvalSpec != null) { var optionalPropertyEvaluator = PropertyEvaluatorForgeFactory.MakeEvaluator( filterNode.RawFilterSpec.OptionalPropertyEvalSpec, resolvedEventType, filterNode.EventAsName, statementRawInfo, services); finalEventType = optionalPropertyEvaluator.FragmentEventType; isPropertyEvaluation = true; } // If a tag was supplied for the type, the tags must stay with this type, i.e. a=BeanA -> b=BeanA -> a=BeanB is a no if (optionalTag != null) { var pair = tags.TaggedEventTypes.Get(optionalTag); EventType existingType = null; if (pair != null) { existingType = pair.First; } if (existingType == null) { pair = tags.ArrayEventTypes.Get(optionalTag); if (pair != null) { throw new ExprValidationException( "Tag '" + optionalTag + "' for event '" + eventName + "' used in the repeat-until operator cannot also appear in other filter expressions"); } } if (existingType != null && existingType != finalEventType) { throw new ExprValidationException( "Tag '" + optionalTag + "' for event '" + eventName + "' has already been declared for events of type " + existingType.UnderlyingType.Name); } pair = new Pair<EventType, string>(finalEventType, eventName); // add tagged type if (isPropertyEvaluation || isParentMatchUntil) { newArrayEventTypes = new LinkedHashMap<string, Pair<EventType, string>>(); newArrayEventTypes.Put(optionalTag, pair); } else { newTaggedEventTypes = new LinkedHashMap<string, Pair<EventType, string>>(); newTaggedEventTypes.Put(optionalTag, pair); } } // For this filter, filter types are all known tags at this time, // and additionally stream 0 (self) is our event type. // Stream type service allows resolution by property name event if that name appears in other tags. // by defaulting to stream zero. // Stream zero is always the current event type, all others follow the order of the map (stream 1 to N). var selfStreamName = optionalTag; if (selfStreamName == null) { selfStreamName = "s_" + UuidGenerator.Generate(); } var filterTypes = new LinkedHashMap<string, Pair<EventType, string>>(); var typePair = new Pair<EventType, string>(finalEventType, eventName); filterTypes.Put(selfStreamName, typePair); filterTypes.PutAll(tags.TaggedEventTypes); // for the filter, specify all tags used var filterTaggedEventTypes = new LinkedHashMap<string, Pair<EventType, string>>(tags.TaggedEventTypes); filterTaggedEventTypes.Remove(optionalTag); // handle array tags (match-until clause) IDictionary<string, Pair<EventType, string>> arrayCompositeEventTypes = null; if (tags.ArrayEventTypes != null && !tags.ArrayEventTypes.IsEmpty()) { arrayCompositeEventTypes = new LinkedHashMap<string, Pair<EventType, string>>(); foreach (var entry in tags.ArrayEventTypes) { var specificArrayType = new LinkedHashMap<string, Pair<EventType, string>>(); specificArrayType.Put(entry.Key, entry.Value); var eventTypeName = services.EventTypeNameGeneratorStatement.GetAnonymousPatternNameWTag( streamNum, evalNode.FactoryNodeId, entry.Key); var mapProps = GetMapProperties( Collections.GetEmptyMap<string, Pair<EventType, string>>(), specificArrayType); var metadata = new EventTypeMetadata( eventTypeName, statementRawInfo.ModuleName, EventTypeTypeClass.PATTERNDERIVED, EventTypeApplicationType.MAP, NameAccessModifier.TRANSIENT, EventTypeBusModifier.NONBUS, false, EventTypeIdPair.Unassigned()); var mapEventType = BaseNestableEventUtil.MakeMapTypeCompileTime( metadata, mapProps, null, null, null, null, services.BeanEventTypeFactoryPrivate, services.EventTypeCompileTimeResolver); services.EventTypeCompileTimeRegistry.NewType(mapEventType); var tag = entry.Key; if (!filterTypes.ContainsKey(tag)) { var pair = new Pair<EventType, string>(mapEventType, tag); filterTypes.Put(tag, pair); arrayCompositeEventTypes.Put(tag, pair); } } } StreamTypeService streamTypeService = new StreamTypeServiceImpl(filterTypes, true, false); var exprNodes = filterNode.RawFilterSpec.FilterExpressions; var spec = FilterSpecCompiler.MakeFilterSpec( resolvedEventType, eventName, exprNodes, filterNode.RawFilterSpec.OptionalPropertyEvalSpec, filterTaggedEventTypes, arrayCompositeEventTypes, streamTypeService, null, statementRawInfo, services); filterNode.FilterSpec = spec; } else if (evalNode is EvalObserverForgeNode) { var observerNode = (EvalObserverForgeNode) evalNode; try { var observerForge = services.PatternResolutionService.Create(observerNode.PatternObserverSpec); var streamTypeService = GetStreamTypeService( tags.TaggedEventTypes, tags.ArrayEventTypes, observerNode, streamNum, statementRawInfo, services); var validationContext = new ExprValidationContextBuilder( streamTypeService, statementRawInfo, services).Build(); var validated = ValidateExpressions( ExprNodeOrigin.PATTERNOBSERVER, observerNode.PatternObserverSpec.ObjectParameters, validationContext); var convertor = new MatchedEventConvertorForge( tags.TaggedEventTypes, tags.ArrayEventTypes, allTagNamesOrdered); observerNode.ObserverFactory = observerForge; observerForge.SetObserverParameters(validated, convertor, validationContext); } catch (ObserverParameterException e) { throw new ExprValidationException( "Invalid parameter for pattern observer '" + observerNode.ToPrecedenceFreeEPL() + "': " + e.Message, e); } catch (PatternObjectException e) { throw new ExprValidationException( "Failed to resolve pattern observer '" + observerNode.ToPrecedenceFreeEPL() + "': " + e.Message, e); } } else if (evalNode is EvalGuardForgeNode) { var guardNode = (EvalGuardForgeNode) evalNode; try { var guardForge = services.PatternResolutionService.Create(guardNode.PatternGuardSpec); var streamTypeService = GetStreamTypeService( tags.TaggedEventTypes, tags.ArrayEventTypes, guardNode, streamNum, statementRawInfo, services); var validationContext = new ExprValidationContextBuilder( streamTypeService, statementRawInfo, services).Build(); var validated = ValidateExpressions( ExprNodeOrigin.PATTERNGUARD, guardNode.PatternGuardSpec.ObjectParameters, validationContext); var convertor = new MatchedEventConvertorForge( tags.TaggedEventTypes, tags.ArrayEventTypes, allTagNamesOrdered); guardNode.GuardForge = guardForge; guardForge.SetGuardParameters(validated, convertor, services); } catch (GuardParameterException e) { throw new ExprValidationException( "Invalid parameter for pattern guard '" + guardNode.ToPrecedenceFreeEPL() + "': " + e.Message, e); } catch (PatternObjectException e) { throw new ExprValidationException( "Failed to resolve pattern guard '" + guardNode.ToPrecedenceFreeEPL() + "': " + e.Message, e); } } else if (evalNode is EvalEveryDistinctForgeNode) { var distinctNode = (EvalEveryDistinctForgeNode) evalNode; var matchEventFromChildNodes = AnalyzeMatchEvent(distinctNode); var streamTypeService = GetStreamTypeService( matchEventFromChildNodes.TaggedEventTypes, matchEventFromChildNodes.ArrayEventTypes, distinctNode, streamNum, statementRawInfo, services); var validationContext = new ExprValidationContextBuilder(streamTypeService, statementRawInfo, services).Build(); IList<ExprNode> validated; try { validated = ValidateExpressions( ExprNodeOrigin.PATTERNEVERYDISTINCT, distinctNode.Expressions, validationContext); } catch (ExprValidationPropertyException ex) { throw new ExprValidationPropertyException( ex.Message + ", every-distinct requires that all properties resolve from sub-expressions to the every-distinct", ex.InnerException); } var convertor = new MatchedEventConvertorForge( matchEventFromChildNodes.TaggedEventTypes, matchEventFromChildNodes.ArrayEventTypes, allTagNamesOrdered); distinctNode.Convertor = convertor; // Determine whether some expressions are constants or time period IList<ExprNode> distinctExpressions = new List<ExprNode>(); TimePeriodComputeForge timePeriodComputeForge = null; ExprNode expiryTimeExp = null; var count = -1; var last = validated.Count - 1; foreach (var expr in validated) { count++; if (count == last && expr is ExprTimePeriod) { expiryTimeExp = expr; var timePeriodExpr = (ExprTimePeriod) expiryTimeExp; timePeriodComputeForge = timePeriodExpr.TimePeriodComputeForge; } else if (expr.Forge.ForgeConstantType.IsCompileTimeConstant) { if (count == last) { var value = expr.Forge.ExprEvaluator.Evaluate(null, true, null); if (!value.IsNumber()) { throw new ExprValidationException( "Invalid parameter for every-distinct, expected number of seconds constant (constant not considered for distinct)"); } var secondsExpire = expr.Forge.ExprEvaluator.Evaluate(null, true, null); var timeExpire = secondsExpire == null ? (long?) null : (long?) services.ImportServiceCompileTime.TimeAbacus.DeltaForSecondsNumber( secondsExpire); if (timeExpire != null && timeExpire > 0) { timePeriodComputeForge = new TimePeriodComputeConstGivenDeltaForge(timeExpire.Value); expiryTimeExp = expr; } else { Log.Warn( "Invalid seconds-expire " + timeExpire + " for " + ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(expr)); } } else { Log.Warn( "Every-distinct node utilizes an expression returning a constant value, please check expression '" + ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(expr) + "', not adding expression to distinct-value expression list"); } } else { distinctExpressions.Add(expr); } } if (distinctExpressions.IsEmpty()) { throw new ExprValidationException( "Every-distinct node requires one or more distinct-value expressions that each return non-constant result values"); } distinctNode.SetDistinctExpressions(distinctExpressions, timePeriodComputeForge, expiryTimeExp); } else if (evalNode is EvalMatchUntilForgeNode) { var matchUntilNode = (EvalMatchUntilForgeNode) evalNode; // compile bounds expressions, if any var untilMatchEventSpec = new MatchEventSpec(tags.TaggedEventTypes, tags.ArrayEventTypes); var streamTypeService = GetStreamTypeService( untilMatchEventSpec.TaggedEventTypes, untilMatchEventSpec.ArrayEventTypes, matchUntilNode, streamNum, statementRawInfo, services); var validationContext = new ExprValidationContextBuilder(streamTypeService, statementRawInfo, services).Build(); var lower = ValidateBounds(matchUntilNode.LowerBounds, validationContext); matchUntilNode.LowerBounds = lower; var upper = ValidateBounds(matchUntilNode.UpperBounds, validationContext); matchUntilNode.UpperBounds = upper; var single = ValidateBounds(matchUntilNode.SingleBound, validationContext); matchUntilNode.SingleBound = single; bool tightlyBound; if (matchUntilNode.SingleBound != null) { ValidateMatchUntil(matchUntilNode.SingleBound, matchUntilNode.SingleBound, false); tightlyBound = true; } else { var allowZeroLowerBounds = matchUntilNode.LowerBounds != null && matchUntilNode.UpperBounds != null; tightlyBound = ValidateMatchUntil( matchUntilNode.LowerBounds, matchUntilNode.UpperBounds, allowZeroLowerBounds); } if (matchUntilNode.SingleBound == null && !tightlyBound && matchUntilNode.ChildNodes.Count < 2) { throw new ExprValidationException("Variable bounds repeat operator requires an until-expression"); } var convertor = new MatchedEventConvertorForge( untilMatchEventSpec.TaggedEventTypes, untilMatchEventSpec.ArrayEventTypes, allTagNamesOrdered); matchUntilNode.Convertor = convertor; // compile new tag lists ISet<string> arrayTags = null; var matchUntilAnalysisResult = EvalNodeUtil.RecursiveAnalyzeChildNodes(matchUntilNode.ChildNodes[0]); foreach (var filterNode in matchUntilAnalysisResult.FilterNodes) { var optionalTag = filterNode.EventAsName; if (optionalTag != null) { if (arrayTags == null) { arrayTags = new HashSet<string>(); } arrayTags.Add(optionalTag); } } if (arrayTags != null) { foreach (var arrayTag in arrayTags) { if (!tags.ArrayEventTypes.ContainsKey(arrayTag)) { tags.ArrayEventTypes.Put(arrayTag, tags.TaggedEventTypes.Get(arrayTag)); tags.TaggedEventTypes.Remove(arrayTag); } } } matchUntilNode.TagsArrayedSet = GetIndexesForTags(allTagNamesOrdered, arrayTags); } else if (evalNode is EvalFollowedByForgeNode) { var followedByNode = (EvalFollowedByForgeNode) evalNode; StreamTypeService streamTypeService = new StreamTypeServiceImpl(false); var validationContext = new ExprValidationContextBuilder(streamTypeService, statementRawInfo, services).Build(); if (followedByNode.OptionalMaxExpressions != null) { IList<ExprNode> validated = new List<ExprNode>(); foreach (var maxExpr in followedByNode.OptionalMaxExpressions) { if (maxExpr == null) { validated.Add(null); } else { var visitor = new ExprNodeSummaryVisitor(); maxExpr.Accept(visitor); if (!visitor.IsPlain) { var errorMessage = "Invalid maximum expression in followed-by, " + visitor.Message + " are not allowed within the expression"; Log.Error(errorMessage); throw new ExprValidationException(errorMessage); } var validatedExpr = ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.FOLLOWEDBYMAX, maxExpr, validationContext); validated.Add(validatedExpr); var returnType = validatedExpr.Forge.EvaluationType; if (returnType == null || !returnType.IsNumeric()) { var message = "Invalid maximum expression in followed-by, the expression must return an integer value"; throw new ExprValidationException(message); } } } followedByNode.OptionalMaxExpressions = validated; } } if (newTaggedEventTypes != null) { tags.TaggedEventTypes.PutAll(newTaggedEventTypes); } if (newArrayEventTypes != null) { tags.ArrayEventTypes.PutAll(newArrayEventTypes); } }
public static PatternStreamSpecCompiled CompilePatternWTags( PatternStreamSpecRaw streamSpecRaw, ISet<string> eventTypeReferences, bool isInsertInto, MatchEventSpec tags, ISet<string> priorAllTags, bool isJoin, bool isContextDeclaration, bool isOnTrigger, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { // validate if ((streamSpecRaw.IsSuppressSameEventMatches || streamSpecRaw.IsDiscardPartialsOnMatch) && (isJoin || isContextDeclaration || isOnTrigger)) { throw new ExprValidationException( "Discard-partials and suppress-matches is not supported in a joins, context declaration and on-action"); } if (tags == null) { tags = new MatchEventSpec(); } var nodeStack = new Stack<EvalForgeNode>(); // detemine ordered tags var allTagNamesOrdered = new LinkedHashSet<string>(); var filterFactoryNodes = EvalNodeUtil.RecursiveGetChildNodes( streamSpecRaw.EvalForgeNode, FilterForFilterFactoryNodes.INSTANCE); if (priorAllTags != null) { allTagNamesOrdered.AddAll(priorAllTags); } foreach (var filterNode in filterFactoryNodes) { var forge = (EvalFilterForgeNode) filterNode; int tagNumber; if (forge.EventAsName != null) { if (!allTagNamesOrdered.Contains(forge.EventAsName)) { allTagNamesOrdered.Add(forge.EventAsName); tagNumber = allTagNamesOrdered.Count - 1; } else { tagNumber = FindTagNumber(forge.EventAsName, allTagNamesOrdered); } forge.EventAsTagNumber = tagNumber; } } // construct root : assigns factory node ids var top = streamSpecRaw.EvalForgeNode; var root = new EvalRootForgeNode(top, statementRawInfo.Annotations); RecursiveCompile( top, eventTypeReferences, isInsertInto, tags, nodeStack, allTagNamesOrdered, streamNum, statementRawInfo, services); var hook = (PatternCompileHook) ImportUtil.GetAnnotationHook( statementRawInfo.Annotations, HookType.INTERNAL_PATTERNCOMPILE, typeof(PatternCompileHook), services.ImportServiceCompileTime); if (hook != null) { hook.Pattern(root); } return new PatternStreamSpecCompiled( root, tags.TaggedEventTypes, tags.ArrayEventTypes, allTagNamesOrdered, streamSpecRaw.ViewSpecs, streamSpecRaw.OptionalStreamName, streamSpecRaw.Options, streamSpecRaw.IsSuppressSameEventMatches, streamSpecRaw.IsDiscardPartialsOnMatch); }
public static StatementSpecCompiled Compile( StatementSpecRaw spec, Compilable compilable, bool isSubquery, bool isOnDemandQuery, Attribute[] annotations, IList<ExprSubselectNode> subselectNodes, IList<ExprTableAccessNode> tableAccessNodes, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices) { IList<StreamSpecCompiled> compiledStreams; ISet<string> eventTypeReferences = new HashSet<string>(); if (!isOnDemandQuery && spec.FireAndForgetSpec != null) { throw new StatementSpecCompileException( "Provided EPL expression is an on-demand query expression (not a continuous query)", compilable.ToEPL()); } // If not using a join and not specifying a data window, make the where-clause, if present, the filter of the stream // if selecting using filter spec, and not subquery in where clause if (spec.StreamSpecs.Count == 1 && spec.StreamSpecs[0] is FilterStreamSpecRaw && spec.StreamSpecs[0].ViewSpecs.Length == 0 && spec.WhereClause != null && spec.OnTriggerDesc == null && !isSubquery && !isOnDemandQuery && (tableAccessNodes == null || tableAccessNodes.IsEmpty())) { bool disqualified; ExprNode whereClause = spec.WhereClause; var visitorX = new ExprNodeSubselectDeclaredDotVisitor(); whereClause.Accept(visitorX); disqualified = visitorX.Subselects.Count > 0 || HintEnum.DISABLE_WHEREEXPR_MOVETO_FILTER.GetHint(annotations) != null; if (!disqualified) { var viewResourceVisitor = new ExprNodeViewResourceVisitor(); whereClause.Accept(viewResourceVisitor); disqualified = viewResourceVisitor.ExprNodes.Count > 0; } if (!disqualified) { spec.WhereClause = null; var streamSpec = (FilterStreamSpecRaw) spec.StreamSpecs[0]; streamSpec.RawFilterSpec.FilterExpressions.Add(whereClause); } } // compile select-clause var selectClauseCompiled = CompileSelectClause(spec.SelectClauseSpec); // Determine subselects in filter streams, these may need special handling for locking var visitor = new ExprNodeSubselectDeclaredDotVisitor(); try { StatementSpecRawWalkerSubselectAndDeclaredDot.WalkStreamSpecs(spec, visitor); } catch (ExprValidationException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } foreach (var subselectNode in visitor.Subselects) { subselectNode.IsFilterStreamSubselect = true; } // Determine subselects for compilation, and lambda-expression shortcut syntax for named windows visitor.Reset(); GroupByClauseExpressions groupByRollupExpressions; try { StatementSpecRawWalkerSubselectAndDeclaredDot.WalkSubselectAndDeclaredDotExpr(spec, visitor); var expressionCopier = new ExpressionCopier( spec, statementRawInfo.OptionalContextDescriptor, compileTimeServices, visitor); groupByRollupExpressions = GroupByExpressionHelper.GetGroupByRollupExpressions( spec.GroupByExpressions, spec.SelectClauseSpec, spec.HavingClause, spec.OrderByList, expressionCopier); } catch (ExprValidationException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } if (isSubquery && !visitor.Subselects.IsEmpty()) { throw new StatementSpecCompileException( "Invalid nested subquery, subquery-within-subquery is not supported", compilable.ToEPL()); } if (isOnDemandQuery && !visitor.Subselects.IsEmpty()) { throw new StatementSpecCompileException( "Subqueries are not a supported feature of on-demand queries", compilable.ToEPL()); } foreach (var subselectNode in visitor.Subselects) { if (!subselectNodes.Contains(subselectNode)) { subselectNodes.Add(subselectNode); } } // Compile subselects found var subselectNumber = 0; foreach (var subselect in subselectNodes) { StatementSpecRaw raw = subselect.StatementSpecRaw; var compiled = Compile( raw, compilable, true, isOnDemandQuery, annotations, Collections.GetEmptyList<ExprSubselectNode>(), Collections.GetEmptyList<ExprTableAccessNode>(), statementRawInfo, compileTimeServices); subselect.SetStatementSpecCompiled(compiled, subselectNumber); subselectNumber++; } // Set table-access number var tableAccessNumber = 0; foreach (var tableAccess in tableAccessNodes) { tableAccess.TableAccessNumber = tableAccessNumber; tableAccessNumber++; } // compile each stream used try { compiledStreams = new List<StreamSpecCompiled>(spec.StreamSpecs.Count); var streamNum = 0; foreach (var rawSpec in spec.StreamSpecs) { streamNum++; var compiled = StreamSpecCompiler.Compile( rawSpec, eventTypeReferences, spec.InsertIntoDesc != null, spec.StreamSpecs.Count > 1, false, spec.OnTriggerDesc != null, rawSpec.OptionalStreamName, streamNum, statementRawInfo, compileTimeServices); compiledStreams.Add(compiled); } } catch (ExprValidationException ex) { if (ex.Message == null) { throw new StatementSpecCompileException( "Unexpected exception compiling statement, please consult the log file and report the exception", ex, compilable.ToEPL()); } throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } catch (EPException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } catch (Exception ex) { var text = "Unexpected error compiling statement"; Log.Error(text, ex); throw new StatementSpecCompileException( text + ": " + ex.GetType().Name + ":" + ex.Message, ex, compilable.ToEPL()); } return new StatementSpecCompiled( spec, compiledStreams.ToArray(), selectClauseCompiled, annotations, groupByRollupExpressions, subselectNodes, visitor.DeclaredExpressions, tableAccessNodes); }
internal static FilterSpecParamForge HandleEqualsAndRelOp( ExprNode constituent, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, string statementName, StatementRawInfo raw, StatementCompileTimeServices services) { FilterOperator op; if (constituent is ExprEqualsNode) { var equalsNode = (ExprEqualsNode) constituent; if (!equalsNode.IsIs) { op = FilterOperator.EQUAL; if (equalsNode.IsNotEquals) { op = FilterOperator.NOT_EQUAL; } } else { op = FilterOperator.IS; if (equalsNode.IsNotEquals) { op = FilterOperator.IS_NOT; } } } else { var relNode = (ExprRelationalOpNode) constituent; if (relNode.RelationalOpEnum == RelationalOpEnum.GT) { op = FilterOperator.GREATER; } else if (relNode.RelationalOpEnum == RelationalOpEnum.LT) { op = FilterOperator.LESS; } else if (relNode.RelationalOpEnum == RelationalOpEnum.LE) { op = FilterOperator.LESS_OR_EQUAL; } else if (relNode.RelationalOpEnum == RelationalOpEnum.GE) { op = FilterOperator.GREATER_OR_EQUAL; } else { throw new IllegalStateException("Opertor '" + relNode.RelationalOpEnum + "' not mapped"); } } var left = constituent.ChildNodes[0]; var right = constituent.ChildNodes[1]; // check identifier and constant combination if (right.Forge.ForgeConstantType.IsCompileTimeConstant && left is ExprFilterOptimizableNode) { var filterOptimizableNode = (ExprFilterOptimizableNode) left; if (filterOptimizableNode.FilterLookupEligible) { var lookupableX = filterOptimizableNode.FilterLookupable; var constant = right.Forge.ExprEvaluator.Evaluate(null, true, null); constant = HandleConstantsCoercion(lookupableX, constant); return new FilterSpecParamConstantForge(lookupableX, op, constant); } } if (left.Forge.ForgeConstantType.IsCompileTimeConstant && right is ExprFilterOptimizableNode) { var filterOptimizableNode = (ExprFilterOptimizableNode) right; if (filterOptimizableNode.FilterLookupEligible) { var lookupableX = filterOptimizableNode.FilterLookupable; var constant = left.Forge.ExprEvaluator.Evaluate(null, true, null); constant = HandleConstantsCoercion(lookupableX, constant); var opReversed = op.IsComparisonOperator() ? op.ReversedRelationalOp() : op; return new FilterSpecParamConstantForge(lookupableX, opReversed, constant); } } // check identifier and expression containing other streams if (left is ExprIdentNode && right is ExprIdentNode) { var identNodeLeft = (ExprIdentNode) left; var identNodeRight = (ExprIdentNode) right; if (identNodeLeft.StreamId == 0 && identNodeLeft.FilterLookupEligible && identNodeRight.StreamId != 0) { return HandleProperty(op, identNodeLeft, identNodeRight, arrayEventTypes, statementName); } if (identNodeRight.StreamId == 0 && identNodeRight.FilterLookupEligible && identNodeLeft.StreamId != 0) { op = GetReversedOperator(constituent, op); // reverse operators, as the expression is "stream1.prop xyz stream0.prop" return HandleProperty(op, identNodeRight, identNodeLeft, arrayEventTypes, statementName); } } if (left is ExprFilterOptimizableNode && right is ExprContextPropertyNode) { var filterOptimizableNode = (ExprFilterOptimizableNode) left; var ctxNode = (ExprContextPropertyNode) right; var lookupableX = filterOptimizableNode.FilterLookupable; if (filterOptimizableNode.FilterLookupEligible) { var numberCoercer = GetNumberCoercer(lookupableX.ReturnType, ctxNode.Type, lookupableX.Expression); return new FilterSpecParamContextPropForge(lookupableX, op, ctxNode.PropertyName, ctxNode.Getter, numberCoercer); } } if (left is ExprContextPropertyNode && right is ExprFilterOptimizableNode) { var filterOptimizableNode = (ExprFilterOptimizableNode) right; var ctxNode = (ExprContextPropertyNode) left; var lookupableX = filterOptimizableNode.FilterLookupable; if (filterOptimizableNode.FilterLookupEligible) { op = GetReversedOperator(constituent, op); // reverse operators, as the expression is "stream1.prop xyz stream0.prop" var numberCoercer = GetNumberCoercer(lookupableX.ReturnType, ctxNode.Type, lookupableX.Expression); return new FilterSpecParamContextPropForge(lookupableX, op, ctxNode.PropertyName, ctxNode.Getter, numberCoercer); } } if (left is ExprFilterOptimizableNode && right.Forge.ForgeConstantType.IsDeployTimeTimeConstant && right is ExprNodeDeployTimeConst) { var filterOptimizableNode = (ExprFilterOptimizableNode) left; var deployTimeConst = (ExprNodeDeployTimeConst) right; var lookupableX = filterOptimizableNode.FilterLookupable; if (filterOptimizableNode.FilterLookupEligible) { var returnType = right.Forge.EvaluationType; var numberCoercer = GetNumberCoercer(lookupableX.ReturnType, returnType, lookupableX.Expression); return new FilterSpecParamDeployTimeConstParamForge(lookupableX, op, deployTimeConst, returnType, numberCoercer); } } if (left.Forge.ForgeConstantType.IsDeployTimeTimeConstant && left is ExprNodeDeployTimeConst && right is ExprFilterOptimizableNode) { var filterOptimizableNode = (ExprFilterOptimizableNode) right; var deployTimeConst = (ExprNodeDeployTimeConst) left; var lookupableX = filterOptimizableNode.FilterLookupable; if (filterOptimizableNode.FilterLookupEligible) { var returnType = left.Forge.EvaluationType; op = GetReversedOperator(constituent, op); // reverse operators, as the expression is "stream1.prop xyz stream0.prop" var numberCoercer = GetNumberCoercer(lookupableX.ReturnType, returnType, lookupableX.Expression); return new FilterSpecParamDeployTimeConstParamForge(lookupableX, op, deployTimeConst, returnType, numberCoercer); } } // check lookable-limited and value-limited expression ExprNode lookupable = null; ExprNode value = null; var opWReverse = op; if (IsLimitedLookupableExpression(left) && IsLimitedValueExpression(right)) { lookupable = left; value = right; } else if (IsLimitedLookupableExpression(right) && IsLimitedValueExpression(left)) { lookupable = right; value = left; opWReverse = GetReversedOperator(constituent, op); } if (lookupable != null) { return HandleLimitedExpr(opWReverse, lookupable, value, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, raw, services); } return null; }
internal static FilterSpecParamForge HandleInSetNode( ExprInNode constituent, IDictionary <string, Pair <EventType, string> > taggedEventTypes, IDictionary <string, Pair <EventType, string> > arrayEventTypes, ISet <string> allTagNamesOrdered, StatementRawInfo raw, StatementCompileTimeServices services) { var left = constituent.ChildNodes[0]; ExprFilterSpecLookupableForge lookupable = null; if (left is ExprFilterOptimizableNode) { var filterOptimizableNode = (ExprFilterOptimizableNode)left; lookupable = filterOptimizableNode.FilterLookupable; } else if (FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.LKUPCOMPOSITE, raw, services) && IsLimitedLookupableExpression(left)) { lookupable = MakeLimitedLookupableForgeMayNull(left, raw, services); } if (lookupable == null) { return(null); } var op = FilterOperator.IN_LIST_OF_VALUES; if (constituent.IsNotIn) { op = FilterOperator.NOT_IN_LIST_OF_VALUES; } var expectedNumberOfConstants = constituent.ChildNodes.Length - 1; IList <FilterSpecParamInValueForge> listofValues = new List <FilterSpecParamInValueForge>(); var it = Arrays.AsList(constituent.ChildNodes).GetEnumerator(); it.MoveNext(); // ignore the first node as it's the identifier while (it.MoveNext()) { var subNode = it.Current; if (subNode.Forge.ForgeConstantType.IsCompileTimeConstant) { var constant = subNode.Forge.ExprEvaluator.Evaluate(null, true, null); if (constant is ICollection <object> ) { return(null); } if (constant is IDictionary <object, object> ) { return(null); } if ((constant != null) && (constant is Array arrayConstant)) { for (var i = 0; i < arrayConstant.Length; i++) { var arrayElement = arrayConstant.GetValue(i); var arrayElementCoerced = HandleConstantsCoercion(lookupable, arrayElement); listofValues.Add(new FilterForEvalConstantAnyTypeForge(arrayElementCoerced)); if (i > 0) { expectedNumberOfConstants++; } } } else { constant = HandleConstantsCoercion(lookupable, constant); listofValues.Add(new FilterForEvalConstantAnyTypeForge(constant)); } } else if (subNode is ExprContextPropertyNode) { var contextPropertyNode = (ExprContextPropertyNode)subNode; var returnType = contextPropertyNode.Type; Coercer coercer; if (TypeHelper.IsCollectionMapOrArray(returnType)) { CheckArrayCoercion(returnType, lookupable.ReturnType, lookupable.Expression); coercer = null; } else { coercer = GetNumberCoercer(left.Forge.EvaluationType, contextPropertyNode.Type, lookupable.Expression); } var finalReturnType = coercer != null ? coercer.ReturnType : returnType; listofValues.Add(new FilterForEvalContextPropForge(contextPropertyNode.PropertyName, contextPropertyNode.Getter, coercer, finalReturnType)); } else if (subNode.Forge.ForgeConstantType.IsDeployTimeTimeConstant && subNode is ExprNodeDeployTimeConst) { var deployTimeConst = (ExprNodeDeployTimeConst)subNode; var returnType = subNode.Forge.EvaluationType; Coercer coercer; if (TypeHelper.IsCollectionMapOrArray(returnType)) { CheckArrayCoercion(returnType, lookupable.ReturnType, lookupable.Expression); coercer = null; } else { coercer = GetNumberCoercer(left.Forge.EvaluationType, returnType, lookupable.Expression); } listofValues.Add(new FilterForEvalDeployTimeConstForge(deployTimeConst, coercer, returnType)); } else if (subNode is ExprIdentNode) { var identNodeInner = (ExprIdentNode)subNode; if (identNodeInner.StreamId == 0) { break; // for same event evals use the boolean expression, via count compare failing below } var isMustCoerce = false; var coerceToType = Boxing.GetBoxedType(lookupable.ReturnType); var identReturnType = identNodeInner.Forge.EvaluationType; if (TypeHelper.IsCollectionMapOrArray(identReturnType)) { CheckArrayCoercion(identReturnType, lookupable.ReturnType, lookupable.Expression); coerceToType = identReturnType; // no action } else if (identReturnType != lookupable.ReturnType) { if (TypeHelper.IsNumeric(lookupable.ReturnType)) { if (!TypeHelper.CanCoerce(identReturnType, lookupable.ReturnType)) { ThrowConversionError(identReturnType, lookupable.ReturnType, lookupable.Expression); } isMustCoerce = true; } else { break; // assumed not compatible } } FilterSpecParamInValueForge inValue; var streamName = identNodeInner.ResolvedStreamName; if (arrayEventTypes != null && !arrayEventTypes.IsEmpty() && arrayEventTypes.ContainsKey(streamName)) { var indexAndProp = GetStreamIndex(identNodeInner.ResolvedPropertyName); var innerEventType = GetArrayInnerEventType(arrayEventTypes, streamName); inValue = new FilterForEvalEventPropIndexedForge( identNodeInner.ResolvedStreamName, indexAndProp.First, indexAndProp.Second, innerEventType, isMustCoerce, coerceToType); } else { inValue = new FilterForEvalEventPropForge( identNodeInner.ResolvedStreamName, identNodeInner.ResolvedPropertyName, identNodeInner.ExprEvaluatorIdent, isMustCoerce, coerceToType); } listofValues.Add(inValue); } else if (FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.VALUECOMPOSITE, raw, services) && IsLimitedValueExpression(subNode)) { var convertor = GetMatchEventConvertor(subNode, taggedEventTypes, arrayEventTypes, allTagNamesOrdered); var valueType = subNode.Forge.EvaluationType; var lookupableType = lookupable.ReturnType; var numberCoercer = GetNumberCoercer(lookupableType, valueType, lookupable.Expression); var forge = new FilterForEvalLimitedExprForge(subNode, convertor, numberCoercer); listofValues.Add(forge); } } // Fallback if not all values in the in-node can be resolved to properties or constants if (listofValues.Count == expectedNumberOfConstants) { return(new FilterSpecParamInForge(lookupable, op, listofValues)); } return(null); }
public static StreamSpecCompiled CompileFilter( FilterStreamSpecRaw streamSpec, bool isInsertInto, bool isJoin, bool isContextDeclaration, bool isOnTrigger, string optionalStreamName, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { // Determine the event type var rawFilterSpec = streamSpec.RawFilterSpec; var eventTypeName = rawFilterSpec.EventTypeName; var table = services.TableCompileTimeResolver.Resolve(eventTypeName); if (table != null) { if (streamSpec.ViewSpecs != null && streamSpec.ViewSpecs.Length > 0) { throw new ExprValidationException("Views are not supported with tables"); } if (streamSpec.RawFilterSpec.OptionalPropertyEvalSpec != null) { throw new ExprValidationException("Contained-event expressions are not supported with tables"); } StreamTypeService streamTypeService = new StreamTypeServiceImpl( new[] {table.InternalEventType}, new[] {optionalStreamName}, new[] {true}, false, false); var validatedNodes = FilterSpecCompiler.ValidateAllowSubquery( ExprNodeOrigin.FILTER, rawFilterSpec.FilterExpressions, streamTypeService, null, null, statementRawInfo, services); return new TableQueryStreamSpec( streamSpec.OptionalStreamName, streamSpec.ViewSpecs, streamSpec.Options, table, validatedNodes); } // Could be a named window var namedWindowInfo = services.NamedWindowCompileTimeResolver.Resolve(eventTypeName); if (namedWindowInfo != null) { StreamTypeService streamTypeService = new StreamTypeServiceImpl( new[] {namedWindowInfo.EventType}, new[] {optionalStreamName}, new[] {true}, false, false); var validatedNodes = FilterSpecCompiler.ValidateAllowSubquery( ExprNodeOrigin.FILTER, rawFilterSpec.FilterExpressions, streamTypeService, null, null, statementRawInfo, services); PropertyEvaluatorForge optionalPropertyEvaluator = null; if (rawFilterSpec.OptionalPropertyEvalSpec != null) { optionalPropertyEvaluator = PropertyEvaluatorForgeFactory.MakeEvaluator( rawFilterSpec.OptionalPropertyEvalSpec, namedWindowInfo.EventType, streamSpec.OptionalStreamName, statementRawInfo, services); } return new NamedWindowConsumerStreamSpec( namedWindowInfo, streamSpec.OptionalStreamName, streamSpec.ViewSpecs, validatedNodes, streamSpec.Options, optionalPropertyEvaluator); } var eventType = ResolveTypeName(eventTypeName, services.EventTypeCompileTimeResolver); // Validate all nodes, make sure each returns a boolean and types are good; // Also decompose all AND super nodes into individual expressions StreamTypeService streamTypeServiceX = new StreamTypeServiceImpl( new[] {eventType}, new[] {streamSpec.OptionalStreamName}, new[] {true}, false, false); var spec = FilterSpecCompiler.MakeFilterSpec( eventType, eventTypeName, rawFilterSpec.FilterExpressions, rawFilterSpec.OptionalPropertyEvalSpec, null, null, // no tags streamTypeServiceX, streamSpec.OptionalStreamName, statementRawInfo, services); return new FilterStreamSpecCompiled( spec, streamSpec.ViewSpecs, streamSpec.OptionalStreamName, streamSpec.Options); }
/// <summary> /// For a given expression determine if this is optimizable and create the filter parameter /// representing the expression, or null if not optimizable. /// </summary> /// <param name="constituent">is the expression to look at</param> /// <param name="performConditionPlanning"></param> /// <param name="taggedEventTypes">event types that provide non-array values</param> /// <param name="arrayEventTypes">event types that provide array values</param> /// <param name="statementName">statement name</param> /// <param name="streamTypeService">stream type service</param> /// <returns>filter parameter representing the expression, or null</returns> /// <throws>ExprValidationException if the expression is invalid</throws> internal static FilterSpecPlanPathTripletForge MakeFilterParam( ExprNode constituent, bool performConditionPlanning, IDictionary <string, Pair <EventType, string> > taggedEventTypes, IDictionary <string, Pair <EventType, string> > arrayEventTypes, ISet <string> allTagNamesOrdered, string statementName, StreamTypeService streamTypeService, StatementRawInfo raw, StatementCompileTimeServices services) { // Is this expression node a simple compare, i.e. a=5 or b<4; these can be indexed if ((constituent is ExprEqualsNode) || (constituent is ExprRelationalOpNode)) { FilterSpecParamForge param = HandleEqualsAndRelOp( constituent, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, statementName, raw, services); if (param != null) { return(new FilterSpecPlanPathTripletForge(param, null)); } } constituent = RewriteOrToInIfApplicable(constituent, false); // Is this expression node a simple compare, i.e. a=5 or b<4; these can be indexed if (constituent is ExprInNode) { FilterSpecParamForge param = HandleInSetNode((ExprInNode)constituent, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, raw, services); if (param != null) { return(new FilterSpecPlanPathTripletForge(param, null)); } } if (constituent is ExprBetweenNode) { FilterSpecParamForge param = HandleRangeNode( (ExprBetweenNode)constituent, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, statementName, raw, services); if (param != null) { return(new FilterSpecPlanPathTripletForge(param, null)); } } if (constituent is ExprPlugInSingleRowNode) { FilterSpecParamForge param = HandlePlugInSingleRow((ExprPlugInSingleRowNode)constituent); if (param != null) { return(new FilterSpecPlanPathTripletForge(param, null)); } } if (constituent is FilterSpecCompilerAdvIndexDescProvider) { FilterSpecParamForge param = HandleAdvancedIndexDescProvider( (FilterSpecCompilerAdvIndexDescProvider)constituent, arrayEventTypes, statementName); if (param != null) { return(new FilterSpecPlanPathTripletForge(param, null)); } } if (constituent is ExprOrNode && performConditionPlanning) { return(HandleOrAlternateExpression( (ExprOrNode)constituent, performConditionPlanning, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, statementName, streamTypeService, raw, services)); } FilterSpecParamForge paramX = HandleBooleanLimited( constituent, taggedEventTypes, arrayEventTypes, allTagNamesOrdered, streamTypeService, raw, services); if (paramX != null) { return(new FilterSpecPlanPathTripletForge(paramX, null)); } return(null); }
private static FilterSpecParamFilterForEvalForge HandleRangeNodeEndpoint( ExprNode endpoint, IDictionary<string, Pair<EventType, string>> taggedEventTypes, IDictionary<string, Pair<EventType, string>> arrayEventTypes, ISet<string> allTagNamesOrdered, string statementName, StatementRawInfo raw, StatementCompileTimeServices services) { // constant if (endpoint.Forge.ForgeConstantType.IsCompileTimeConstant) { var value = endpoint.Forge.ExprEvaluator.Evaluate(null, true, null); if (value == null) { return null; } if (value is string) { return new FilterForEvalConstantStringForge((string) value); } return new FilterForEvalConstantDoubleForge(value.AsDouble()); } if (endpoint is ExprContextPropertyNode) { var node = (ExprContextPropertyNode) endpoint; if (node.Type == typeof(string)) { return new FilterForEvalContextPropStringForge(node.Getter, node.PropertyName); } return new FilterForEvalContextPropDoubleForge(node.Getter, node.PropertyName); } if (endpoint.Forge.ForgeConstantType.IsDeployTimeTimeConstant && endpoint is ExprNodeDeployTimeConst) { var node = (ExprNodeDeployTimeConst) endpoint; if (endpoint.Forge.EvaluationType == typeof(string)) { return new FilterForEvalDeployTimeConstStringForge(node); } return new FilterForEvalDeployTimeConstDoubleForge(node); } // or property if (endpoint is ExprIdentNode) { return GetIdentNodeDoubleEval((ExprIdentNode) endpoint, arrayEventTypes, statementName); } // or limited expression if (FilterSpecCompilerIndexPlannerHelper.HasLevelOrHint(FilterSpecCompilerIndexPlannerHint.VALUECOMPOSITE, raw, services) && IsLimitedValueExpression(endpoint)) { var returnType = endpoint.Forge.EvaluationType; MatchedEventConvertorForge convertor = GetMatchEventConvertor(endpoint, taggedEventTypes, arrayEventTypes, allTagNamesOrdered); if (returnType == typeof(string)) { return new FilterForEvalLimitedExprForge(endpoint, convertor, null); } var coercer = SimpleNumberCoercerFactory.GetCoercer(returnType, typeof(double?)); return new FilterForEvalLimitedExprForge(endpoint, convertor, coercer); } return null; }
public static StreamSpecCompiledDesc CompilePatternWTags( PatternStreamSpecRaw streamSpecRaw, ISet<string> eventTypeReferences, bool isInsertInto, MatchEventSpec tags, ISet<string> priorAllTags, bool isJoin, bool isContextDeclaration, bool isOnTrigger, int streamNum, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { // validate if ((streamSpecRaw.IsSuppressSameEventMatches || streamSpecRaw.IsDiscardPartialsOnMatch) && (isJoin || isContextDeclaration || isOnTrigger)) { throw new ExprValidationException( "Discard-partials and suppress-matches is not supported in a joins, context declaration and on-action"); } if (tags == null) { tags = new MatchEventSpec(); } var nodeStack = new Stack<EvalForgeNode>(); // determine ordered tags ISet<string> allTagNamesOrdered = FilterSpecCompilerTagUtil.AssignEventAsTagNumber(priorAllTags, streamSpecRaw.EvalForgeNode); // construct root : assigns factory node ids var top = streamSpecRaw.EvalForgeNode; var root = new EvalRootForgeNode(services.IsAttachPatternText, top, statementRawInfo.Annotations); var additionalForgeables = new List<StmtClassForgeableFactory>(); RecursiveCompile( top, tags, nodeStack, allTagNamesOrdered, streamNum, additionalForgeables, statementRawInfo, services); var hook = (PatternCompileHook) ImportUtil.GetAnnotationHook( statementRawInfo.Annotations, HookType.INTERNAL_PATTERNCOMPILE, typeof(PatternCompileHook), services.ImportServiceCompileTime); hook?.Pattern(root); PatternStreamSpecCompiled compiled = new PatternStreamSpecCompiled( root, tags.TaggedEventTypes, tags.ArrayEventTypes, allTagNamesOrdered, streamSpecRaw.ViewSpecs, streamSpecRaw.OptionalStreamName, streamSpecRaw.Options, streamSpecRaw.IsSuppressSameEventMatches, streamSpecRaw.IsDiscardPartialsOnMatch); return new StreamSpecCompiledDesc(compiled, additionalForgeables); }