private IList<StmtClassForgeableFactory> ValidateContextDetail( ContextSpec contextSpec, int nestingLevel, CreateContextValidationEnv validationEnv) { ISet<string> eventTypesReferenced = new HashSet<string>(); IList<StmtClassForgeableFactory> additionalForgeables = new List<StmtClassForgeableFactory>(); if (contextSpec is ContextSpecKeyed) { var segmented = (ContextSpecKeyed) contextSpec; IDictionary<string, EventType> asNames = new Dictionary<string, EventType>(); var partitionHasNameAssignment = false; Type[] getterTypes = null; foreach (var partition in segmented.Items) { Pair<FilterSpecCompiled, IList<StmtClassForgeableFactory>> pair = CompilePartitionedFilterSpec( partition.FilterSpecRaw, eventTypesReferenced, validationEnv); FilterSpecCompiled filterSpecCompiled = pair.First; additionalForgeables.AddAll(pair.Second); partition.FilterSpecCompiled = filterSpecCompiled; var getters = new EventPropertyGetterSPI[partition.PropertyNames.Count]; var serdes = new DataInputOutputSerdeForge[partition.PropertyNames.Count]; var eventType = (EventTypeSPI) filterSpecCompiled.FilterForEventType; getterTypes = new Type[partition.PropertyNames.Count]; for (var i = 0; i < partition.PropertyNames.Count; i++) { var propertyName = partition.PropertyNames[i]; var getter = eventType.GetGetterSPI(propertyName); if (getter == null) { throw new ExprValidationException( "For context '" + validationEnv.ContextName + "' property name '" + propertyName + "' not found on type " + eventType.Name); } getters[i] = getter; getterTypes[i] = eventType.GetPropertyType(propertyName); serdes[i] = validationEnv.Services.SerdeResolver.SerdeForFilter( getterTypes[i], validationEnv.StatementRawInfo); } partition.Getters = getters; partition.LookupableSerdes = serdes; if (partition.AliasName != null) { partitionHasNameAssignment = true; ValidateAsName(asNames, partition.AliasName, filterSpecCompiled.FilterForEventType); } } // plan multi-key, make sure we use the same multikey for all items MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKey( getterTypes, false, @base.StatementRawInfo, validationEnv.Services.SerdeResolver); additionalForgeables.AddAll(multiKeyPlan.MultiKeyForgeables); foreach (ContextSpecKeyedItem partition in segmented.Items) { partition.KeyMultiKey = multiKeyPlan.ClassRef; } segmented.MultiKeyClassRef = multiKeyPlan.ClassRef; if (segmented.OptionalInit != null) { asNames.Clear(); foreach (var initCondition in segmented.OptionalInit) { ContextDetailMatchPair pair = ValidateRewriteContextCondition( true, nestingLevel, initCondition, eventTypesReferenced, new MatchEventSpec(), new EmptySet<string>(), validationEnv); additionalForgeables.AddAll(pair.AdditionalForgeables); var filterForType = initCondition.FilterSpecCompiled.FilterForEventType; var found = false; foreach (var partition in segmented.Items) { if (partition.FilterSpecCompiled.FilterForEventType == filterForType) { found = true; break; } } if (!found) { throw new ExprValidationException( "Segmented context '" + validationEnv.ContextName + "' requires that all of the event types that are listed in the initialized-by also appear in the partition-by, type '" + filterForType.Name + "' is not one of the types listed in partition-by"); } if (initCondition.OptionalFilterAsName != null) { if (partitionHasNameAssignment) { throw new ExprValidationException( "Segmented context '" + validationEnv.ContextName + "' requires that either partition-by or initialized-by assign stream names, but not both"); } ValidateAsName(asNames, initCondition.OptionalFilterAsName, filterForType); } } } if (segmented.OptionalTermination != null) { var matchEventSpec = new MatchEventSpec(); var allTags = new LinkedHashSet<string>(); foreach (var partition in segmented.Items) { if (partition.AliasName != null) { allTags.Add(partition.AliasName); var eventType = partition.FilterSpecCompiled.FilterForEventType; matchEventSpec.TaggedEventTypes[partition.AliasName] = new Pair<EventType,string>( eventType, partition.FilterSpecRaw.EventTypeName); var serdeForgeables = SerdeEventTypeUtility.Plan( eventType, validationEnv.StatementRawInfo, validationEnv.Services.SerdeEventTypeRegistry, validationEnv.Services.SerdeResolver); additionalForgeables.AddAll(serdeForgeables); } } if (segmented.OptionalInit != null) { foreach (var initCondition in segmented.OptionalInit) { if (initCondition.OptionalFilterAsName != null) { allTags.Add(initCondition.OptionalFilterAsName); matchEventSpec.TaggedEventTypes.Put( initCondition.OptionalFilterAsName, new Pair<EventType, string>( initCondition.FilterSpecCompiled.FilterForEventType, initCondition.FilterSpecRaw.EventTypeName)); } } } var endCondition = ValidateRewriteContextCondition( false, nestingLevel, segmented.OptionalTermination, eventTypesReferenced, matchEventSpec, allTags, validationEnv); additionalForgeables.AddAll(endCondition.AdditionalForgeables); segmented.OptionalTermination = endCondition.Condition; } } else if (contextSpec is ContextSpecCategory) { // compile filter var category = (ContextSpecCategory) contextSpec; ValidateNotTable(category.FilterSpecRaw.EventTypeName, validationEnv.Services); var raw = new FilterStreamSpecRaw( category.FilterSpecRaw, ViewSpec.EMPTY_VIEWSPEC_ARRAY, null, StreamSpecOptions.DEFAULT); var compiledDesc = StreamSpecCompiler.CompileFilter( raw, false, false, true, false, null, validationEnv.StatementRawInfo, validationEnv.Services); var result = (FilterStreamSpecCompiled) compiledDesc.StreamSpecCompiled; additionalForgeables.AddAll(compiledDesc.AdditionalForgeables); category.FilterSpecCompiled = result.FilterSpecCompiled; validationEnv.FilterSpecCompileds.Add(result.FilterSpecCompiled); // compile expressions foreach (var item in category.Items) { ValidateNotTable(category.FilterSpecRaw.EventTypeName, validationEnv.Services); var filterSpecRaw = new FilterSpecRaw( category.FilterSpecRaw.EventTypeName, Collections.SingletonList(item.Expression), null); var rawExpr = new FilterStreamSpecRaw( filterSpecRaw, ViewSpec.EMPTY_VIEWSPEC_ARRAY, null, StreamSpecOptions.DEFAULT); var compiledDescItems = StreamSpecCompiler.CompileFilter( rawExpr, false, false, true, false, null, validationEnv.StatementRawInfo, validationEnv.Services); var compiled = (FilterStreamSpecCompiled) compiledDescItems.StreamSpecCompiled; additionalForgeables.AddAll(compiledDescItems.AdditionalForgeables); compiled.FilterSpecCompiled.TraverseFilterBooleanExpr( node => validationEnv.FilterBooleanExpressions.Add(node)); item.FilterPlan = compiled.FilterSpecCompiled.Parameters; } } else if (contextSpec is ContextSpecHash) { var hashed = (ContextSpecHash) contextSpec; foreach (var hashItem in hashed.Items) { var raw = new FilterStreamSpecRaw( hashItem.FilterSpecRaw, ViewSpec.EMPTY_VIEWSPEC_ARRAY, null, StreamSpecOptions.DEFAULT); ValidateNotTable(hashItem.FilterSpecRaw.EventTypeName, validationEnv.Services); var compiledDesc = StreamSpecCompiler.Compile( raw, eventTypesReferenced, false, false, true, false, null, 0, validationEnv.StatementRawInfo, validationEnv.Services); additionalForgeables.AddAll(compiledDesc.AdditionalForgeables); var result = (FilterStreamSpecCompiled) compiledDesc.StreamSpecCompiled; validationEnv.FilterSpecCompileds.Add(result.FilterSpecCompiled); hashItem.FilterSpecCompiled = result.FilterSpecCompiled; // validate parameters var streamTypes = new StreamTypeServiceImpl( result.FilterSpecCompiled.FilterForEventType, null, true); var validationContext = new ExprValidationContextBuilder( streamTypes, validationEnv.StatementRawInfo, validationEnv.Services) .WithIsFilterExpression(true) .Build(); ExprNodeUtilityValidate.Validate( ExprNodeOrigin.CONTEXT, Collections.SingletonList(hashItem.Function), validationContext); } } else if (contextSpec is ContextSpecInitiatedTerminated) { var def = (ContextSpecInitiatedTerminated) contextSpec; var startCondition = ValidateRewriteContextCondition( true, nestingLevel, def.StartCondition, eventTypesReferenced, new MatchEventSpec(), new LinkedHashSet<string>(), validationEnv); additionalForgeables.AddAll(startCondition.AdditionalForgeables); var endCondition = ValidateRewriteContextCondition( false, nestingLevel, def.EndCondition, eventTypesReferenced, startCondition.Matches, startCondition.AllTags, validationEnv); additionalForgeables.AddAll(endCondition.AdditionalForgeables); def.StartCondition = startCondition.Condition; def.EndCondition = endCondition.Condition; if (def.DistinctExpressions != null) { if (!(startCondition.Condition is ContextSpecConditionFilter)) { throw new ExprValidationException( "Distinct-expressions require a stream as the initiated-by condition"); } var distinctExpressions = def.DistinctExpressions; if (distinctExpressions.Length == 0) { throw new ExprValidationException("Distinct-expressions have not been provided"); } var filter = (ContextSpecConditionFilter) startCondition.Condition; if (filter.OptionalFilterAsName == null) { throw new ExprValidationException( "Distinct-expressions require that a stream name is assigned to the stream using 'as'"); } var types = new StreamTypeServiceImpl( filter.FilterSpecCompiled.FilterForEventType, filter.OptionalFilterAsName, true); var validationContext = new ExprValidationContextBuilder(types, validationEnv.StatementRawInfo, validationEnv.Services) .WithAllowBindingConsumption(true) .Build(); for (var i = 0; i < distinctExpressions.Length; i++) { ExprNodeUtilityValidate.ValidatePlainExpression( ExprNodeOrigin.CONTEXTDISTINCT, distinctExpressions[i]); distinctExpressions[i] = ExprNodeUtilityValidate.GetValidatedSubtree( ExprNodeOrigin.CONTEXTDISTINCT, distinctExpressions[i], validationContext); } var multiKeyPlan = MultiKeyPlanner.PlanMultiKey( distinctExpressions, false, @base.StatementRawInfo, validationEnv.Services.SerdeResolver); def.DistinctMultiKey = multiKeyPlan.ClassRef; additionalForgeables.AddAll(multiKeyPlan.MultiKeyForgeables); } } else if (contextSpec is ContextNested) { var nested = (ContextNested) contextSpec; var level = 0; ISet<string> namesUsed = new HashSet<string>(); namesUsed.Add(validationEnv.ContextName); foreach (var nestedContext in nested.Contexts) { if (namesUsed.Contains(nestedContext.ContextName)) { throw new ExprValidationException( "Context by name '" + nestedContext.ContextName + "' has already been declared within nested context '" + validationEnv.ContextName + "'"); } namesUsed.Add(nestedContext.ContextName); var forgeables = ValidateContextDetail(nestedContext.ContextDetail, level, validationEnv); additionalForgeables.AddAll(forgeables); level++; } } else { throw new IllegalStateException("Unrecognized context detail " + contextSpec); } return additionalForgeables; }
public static StmtForgeMethodSelectResult Make( IContainer container, bool dataflowOperator, string @namespace, string classPostfix, StatementBaseInfo @base, StatementCompileTimeServices services) { var filterSpecCompileds = new List<FilterSpecCompiled>(); var scheduleHandleCallbackProviders = new List<ScheduleHandleCallbackProvider>(); var namedWindowConsumers = new List<NamedWindowConsumerStreamSpec>(); var statementSpec = @base.StatementSpec; var additionalForgeables = new List<StmtClassForgeableFactory>(); var streamNames = StatementForgeMethodSelectUtil.DetermineStreamNames(statementSpec.StreamSpecs); var numStreams = streamNames.Length; if (numStreams == 0) { throw new ExprValidationException("The from-clause is required but has not been specified"); } // first we create streams for subselects, if there are any SubSelectActivationDesc subSelectActivationDesc = SubSelectHelperActivations.CreateSubSelectActivation( filterSpecCompileds, namedWindowConsumers, @base, services); IDictionary<ExprSubselectNode, SubSelectActivationPlan> subselectActivation = subSelectActivationDesc.Subselects; additionalForgeables.AddAll(subSelectActivationDesc.AdditionalForgeables); // verify for joins that required views are present StreamJoinAnalysisResultCompileTime joinAnalysisResult = StatementForgeMethodSelectUtil.VerifyJoinViews(statementSpec); var streamEventTypes = new EventType[statementSpec.StreamSpecs.Length]; var eventTypeNames = new string[numStreams]; var isNamedWindow = new bool[numStreams]; var viewableActivatorForges = new ViewableActivatorForge[numStreams]; var viewForges = new IList<ViewFactoryForge>[numStreams]; var historicalEventViewables = new HistoricalEventViewableForge[numStreams]; for (var stream = 0; stream < numStreams; stream++) { var streamSpec = statementSpec.StreamSpecs[stream]; var isCanIterateUnbound = streamSpec.ViewSpecs.Length == 0 && (services.Configuration.Compiler.ViewResources.IsIterableUnbound || AnnotationUtil.HasAnnotation(statementSpec.Annotations, typeof(IterableUnboundAttribute))); var args = new ViewFactoryForgeArgs( stream, false, -1, streamSpec.Options, null, @base.StatementRawInfo, services); if (dataflowOperator) { var dfResult = HandleDataflowActivation(args, streamSpec); streamEventTypes[stream] = dfResult.StreamEventType; eventTypeNames[stream] = dfResult.EventTypeName; viewableActivatorForges[stream] = dfResult.ViewableActivatorForge; viewForges[stream] = dfResult.ViewForges; additionalForgeables.AddAll(dfResult.AdditionalForgeables); } else if (streamSpec is FilterStreamSpecCompiled) { var filterStreamSpec = (FilterStreamSpecCompiled) statementSpec.StreamSpecs[stream]; var filterSpecCompiled = filterStreamSpec.FilterSpecCompiled; streamEventTypes[stream] = filterSpecCompiled.ResultEventType; eventTypeNames[stream] = filterStreamSpec.FilterSpecCompiled.FilterForEventTypeName; viewableActivatorForges[stream] = new ViewableActivatorFilterForge( filterSpecCompiled, isCanIterateUnbound, stream, false, -1); ViewFactoryForgeDesc viewForgeDesc = ViewFactoryForgeUtil.CreateForges(streamSpec.ViewSpecs, args, streamEventTypes[stream]); viewForges[stream] = viewForgeDesc.Forges; additionalForgeables.AddAll(viewForgeDesc.MultikeyForges); filterSpecCompileds.Add(filterSpecCompiled); } else if (streamSpec is PatternStreamSpecCompiled) { var patternStreamSpec = (PatternStreamSpecCompiled) streamSpec; var forges = patternStreamSpec.Root.CollectFactories(); foreach (var forgeNode in forges) { forgeNode.CollectSelfFilterAndSchedule(filterSpecCompileds, scheduleHandleCallbackProviders); } var patternType = ViewableActivatorPatternForge.MakeRegisterPatternType( @base, stream, patternStreamSpec, services); var patternContext = new PatternContext(0, patternStreamSpec.MatchedEventMapMeta, false, -1, false); viewableActivatorForges[stream] = new ViewableActivatorPatternForge( patternType, patternStreamSpec, patternContext, isCanIterateUnbound); streamEventTypes[stream] = patternType; ViewFactoryForgeDesc viewForgeDesc = ViewFactoryForgeUtil.CreateForges(streamSpec.ViewSpecs, args, patternType); viewForges[stream] = viewForgeDesc.Forges; additionalForgeables.AddAll(viewForgeDesc.MultikeyForges); } else if (streamSpec is NamedWindowConsumerStreamSpec) { var namedSpec = (NamedWindowConsumerStreamSpec) streamSpec; var namedWindow = services.NamedWindowCompileTimeResolver.Resolve(namedSpec.NamedWindow.EventType.Name); var namedWindowType = namedWindow.EventType; if (namedSpec.OptPropertyEvaluator != null) { namedWindowType = namedSpec.OptPropertyEvaluator.FragmentEventType; } var typesFilterValidation = new StreamTypeServiceImpl( namedWindowType, namedSpec.OptionalStreamName, false); var filterSingle = ExprNodeUtilityMake.ConnectExpressionsByLogicalAndWhenNeeded(namedSpec.FilterExpressions); var filterQueryGraph = EPLValidationUtil.ValidateFilterGetQueryGraphSafe( filterSingle, typesFilterValidation, @base.StatementRawInfo, services); namedWindowConsumers.Add(namedSpec); viewableActivatorForges[stream] = new ViewableActivatorNamedWindowForge( namedSpec, namedWindow, filterSingle, filterQueryGraph, true, namedSpec.OptPropertyEvaluator); streamEventTypes[stream] = namedWindowType; viewForges[stream] = Collections.GetEmptyList<ViewFactoryForge>(); joinAnalysisResult.SetNamedWindowsPerStream(stream, namedWindow); eventTypeNames[stream] = namedSpec.NamedWindow.EventType.Name; isNamedWindow[stream] = true; // Consumers to named windows cannot declare a data window view onto the named window to avoid duplicate remove streams ViewFactoryForgeDesc viewForgeDesc = ViewFactoryForgeUtil.CreateForges(streamSpec.ViewSpecs, args, namedWindowType); viewForges[stream] = viewForgeDesc.Forges; additionalForgeables.AddAll(viewForgeDesc.MultikeyForges); EPStatementStartMethodHelperValidate.ValidateNoDataWindowOnNamedWindow(viewForges[stream]); } else if (streamSpec is TableQueryStreamSpec) { ValidateNoViews(streamSpec, "Table data"); var tableStreamSpec = (TableQueryStreamSpec) streamSpec; if (numStreams > 1 && tableStreamSpec.FilterExpressions.Count > 0) { throw new ExprValidationException( "Joins with tables do not allow table filter expressions, please add table filters to the where-clause instead"); } var table = tableStreamSpec.Table; EPLValidationUtil.ValidateContextName( true, table.TableName, table.OptionalContextName, statementSpec.Raw.OptionalContextName, false); var filter = ExprNodeUtilityMake.ConnectExpressionsByLogicalAndWhenNeeded(tableStreamSpec.FilterExpressions); viewableActivatorForges[stream] = new ViewableActivatorTableForge(table, filter); viewForges[stream] = Collections.GetEmptyList<ViewFactoryForge>(); eventTypeNames[stream] = tableStreamSpec.Table.TableName; streamEventTypes[stream] = tableStreamSpec.Table.InternalEventType; joinAnalysisResult.SetTablesForStream(stream, table); if (tableStreamSpec.Options.IsUnidirectional) { throw new ExprValidationException("Tables cannot be marked as unidirectional"); } if (tableStreamSpec.Options.IsRetainIntersection || tableStreamSpec.Options.IsRetainUnion) { throw new ExprValidationException("Tables cannot be marked with retain"); } } else if (streamSpec is DBStatementStreamSpec) { ValidateNoViews(streamSpec, "Historical data"); var sqlStreamSpec = (DBStatementStreamSpec) streamSpec; var typeConversionHook = (SQLColumnTypeConversion) ImportUtil.GetAnnotationHook( statementSpec.Annotations, HookType.SQLCOL, typeof(SQLColumnTypeConversion), services.ImportServiceCompileTime); var outputRowConversionHook = (SQLOutputRowConversion) ImportUtil.GetAnnotationHook( statementSpec.Annotations, HookType.SQLROW, typeof(SQLOutputRowConversion), services.ImportServiceCompileTime); var viewable = HistoricalEventViewableDatabaseForgeFactory.CreateDBStatementView( stream, sqlStreamSpec, typeConversionHook, outputRowConversionHook, @base, services, statementSpec.Annotations); streamEventTypes[stream] = viewable.EventType; viewForges[stream] = Collections.GetEmptyList<ViewFactoryForge>(); viewableActivatorForges[stream] = new ViewableActivatorHistoricalForge(viewable); historicalEventViewables[stream] = viewable; } else if (streamSpec is MethodStreamSpec) { ValidateNoViews(streamSpec, "Method data"); var methodStreamSpec = (MethodStreamSpec) streamSpec; var viewable = HistoricalEventViewableMethodForgeFactory.CreateMethodStatementView( stream, methodStreamSpec, @base, services); historicalEventViewables[stream] = viewable; streamEventTypes[stream] = viewable.EventType; viewForges[stream] = Collections.GetEmptyList<ViewFactoryForge>(); viewableActivatorForges[stream] = new ViewableActivatorHistoricalForge(viewable); historicalEventViewables[stream] = viewable; } else { throw new IllegalStateException("Unrecognized stream " + streamSpec); } // plan serde for iterate-unbound if (isCanIterateUnbound) { var serdeForgeables = SerdeEventTypeUtility.Plan( streamEventTypes[stream], @base.StatementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddAll(serdeForgeables); } } // handle match-recognize pattern if (statementSpec.Raw.MatchRecognizeSpec != null) { if (numStreams > 1) { throw new ExprValidationException("Joins are not allowed when using match-recognize"); } if (joinAnalysisResult.TablesPerStream[0] != null) { throw new ExprValidationException("Tables cannot be used with match-recognize"); } var isUnbound = viewForges[0].IsEmpty() && !(statementSpec.StreamSpecs[0] is NamedWindowConsumerStreamSpec); var eventType = viewForges[0].IsEmpty() ? streamEventTypes[0] : viewForges[0][(viewForges[0].Count - 1)].EventType; var plan = RowRecogNFAViewPlanUtil.ValidateAndPlan(services.Container, eventType, isUnbound, @base, services); var forge = new RowRecogNFAViewFactoryForge(plan.Forge); additionalForgeables.AddAll(plan.AdditionalForgeables); scheduleHandleCallbackProviders.Add(forge); viewForges[0].Add(forge); var serdeForgeables = SerdeEventTypeUtility.Plan( eventType, @base.StatementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddAll(serdeForgeables); } // Obtain event types from view factory chains for (var i = 0; i < viewForges.Length; i++) { streamEventTypes[i] = viewForges[i].IsEmpty() ? streamEventTypes[i] : viewForges[i][(viewForges[i].Count - 1)].EventType; } // add unique-information to join analysis joinAnalysisResult.AddUniquenessInfo(viewForges, statementSpec.Annotations); // plan sub-selects SubSelectHelperForgePlan subselectForgePlan = SubSelectHelperForgePlanner.PlanSubSelect( @base, subselectActivation, streamNames, streamEventTypes, eventTypeNames, services); var subselectForges = subselectForgePlan.Subselects; additionalForgeables.AddAll(subselectForgePlan.AdditionalForgeables); DetermineViewSchedules(subselectForges, scheduleHandleCallbackProviders); // determine view schedules var viewResourceDelegateExpr = new ViewResourceDelegateExpr(); ViewFactoryForgeUtil.DetermineViewSchedules(viewForges, scheduleHandleCallbackProviders); var hasIStreamOnly = StatementForgeMethodSelectUtil.GetHasIStreamOnly(isNamedWindow, viewForges); var optionalStreamsIfAny = OuterJoinAnalyzer.OptionalStreamsIfAny(statementSpec.Raw.OuterJoinDescList); StreamTypeService typeService = new StreamTypeServiceImpl( streamEventTypes, streamNames, hasIStreamOnly, false, optionalStreamsIfAny); // Validate views that require validation, specifically streams that don't have // sub-views such as DB SQL joins var historicalViewableDesc = new HistoricalViewableDesc(numStreams); for (var stream = 0; stream < historicalEventViewables.Length; stream++) { var historicalEventViewable = historicalEventViewables[stream]; if (historicalEventViewable == null) { continue; } scheduleHandleCallbackProviders.Add(historicalEventViewable); IList<StmtClassForgeableFactory> forgeables = historicalEventViewable.Validate(typeService, @base, services); additionalForgeables.AddAll(forgeables); historicalViewableDesc.SetHistorical(stream, historicalEventViewable.RequiredStreams); if (historicalEventViewable.RequiredStreams.Contains(stream)) { throw new ExprValidationException( "Parameters for historical stream " + stream + " indicate that the stream is subordinate to itself as stream parameters originate in the same stream"); } } // Validate where-clause filter tree, outer join clause and output limit expression var whereClauseValidated = EPStatementStartMethodHelperValidate.ValidateNodes( statementSpec.Raw, typeService, viewResourceDelegateExpr, @base.StatementRawInfo, services); var whereClauseForge = whereClauseValidated?.Forge; // Obtain result set processor var resultSetProcessorDesc = ResultSetProcessorFactoryFactory.GetProcessorPrototype( new ResultSetSpec(statementSpec), typeService, viewResourceDelegateExpr, joinAnalysisResult.UnidirectionalInd, true, @base.ContextPropertyRegistry, false, false, @base.StatementRawInfo, services); additionalForgeables.AddAll(resultSetProcessorDesc.AdditionalForgeables); // Handle 'prior' function nodes in terms of view requirements var viewResourceDelegateDesc = ViewResourceVerifyHelper.VerifyPreviousAndPriorRequirements(viewForges, viewResourceDelegateExpr); var hasPrior = ViewResourceDelegateDesc.HasPrior(viewResourceDelegateDesc); if (hasPrior) { for (var stream = 0; stream < numStreams; stream++) { if (!viewResourceDelegateDesc[stream].PriorRequests.IsEmpty()) { viewForges[stream].Add(new PriorEventViewForge(viewForges[stream].IsEmpty(), streamEventTypes[stream])); var serdeForgeables = SerdeEventTypeUtility.Plan( streamEventTypes[stream], @base.StatementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddAll(serdeForgeables); } } } var outputProcessDesc = OutputProcessViewForgeFactory.Make( typeService.EventTypes, resultSetProcessorDesc.ResultEventType, resultSetProcessorDesc.ResultSetProcessorType, statementSpec, @base.StatementRawInfo, services); var outputProcessViewFactoryForge = outputProcessDesc.Forge; additionalForgeables.AddAll(outputProcessDesc.AdditionalForgeables); outputProcessViewFactoryForge.CollectSchedules(scheduleHandleCallbackProviders); JoinSetComposerPrototypeForge joinForge = null; if (numStreams > 1) { var hasAggregations = !resultSetProcessorDesc.AggregationServiceForgeDesc.Expressions.IsEmpty(); var desc = JoinSetComposerPrototypeForgeFactory.MakeComposerPrototype( statementSpec, joinAnalysisResult, typeService, historicalViewableDesc, false, hasAggregations, @base.StatementRawInfo, services); joinForge = desc.Forge; additionalForgeables.AddAll(desc.AdditionalForgeables); HandleIndexDependencies(joinForge.OptionalQueryPlan, services); } // plan table access var tableAccessForges = ExprTableEvalHelperPlan.PlanTableAccess(@base.StatementSpec.TableAccessNodes); ValidateTableAccessUse(statementSpec.Raw.IntoTableSpec, statementSpec.Raw.TableExpressions); if (joinAnalysisResult.IsUnidirectional && statementSpec.Raw.IntoTableSpec != null) { throw new ExprValidationException("Into-table does not allow unidirectional joins"); } var orderByWithoutOutputLimit = statementSpec.Raw.OrderByList != null && !statementSpec.Raw.OrderByList.IsEmpty() && statementSpec.Raw.OutputLimitSpec == null; var statementAIFactoryProviderClassName = CodeGenerationIDGenerator.GenerateClassNameSimple( typeof(StatementAIFactoryProvider), classPostfix); var resultSetProcessorProviderClassName = CodeGenerationIDGenerator.GenerateClassNameSimple( typeof(ResultSetProcessorFactoryProvider), classPostfix); var outputProcessViewProviderClassName = CodeGenerationIDGenerator.GenerateClassNameSimple( typeof(OutputProcessViewFactoryProvider), classPostfix); var statementProviderClassName = CodeGenerationIDGenerator.GenerateClassNameSimple(typeof(StatementProvider), classPostfix); var statementFieldsClassName = CodeGenerationIDGenerator.GenerateClassNameSimple(typeof(StatementFields), classPostfix); //var statementFieldsClassName = namespaceScope.FieldsClassNameOptional; var forgeX = new StatementAgentInstanceFactorySelectForge( typeService.StreamNames, viewableActivatorForges, resultSetProcessorProviderClassName, viewForges, viewResourceDelegateDesc, whereClauseForge, joinForge, outputProcessViewProviderClassName, subselectForges, tableAccessForges, orderByWithoutOutputLimit, joinAnalysisResult.IsUnidirectional); var namespaceScope = new CodegenNamespaceScope( @namespace, statementFieldsClassName, services.IsInstrumented); var forgeablesX = additionalForgeables .Select(additional => additional.Make(namespaceScope, classPostfix)) .ToList(); forgeablesX.Add( new StmtClassForgeableRSPFactoryProvider( resultSetProcessorProviderClassName, resultSetProcessorDesc, namespaceScope, @base.StatementRawInfo)); forgeablesX.Add( new StmtClassForgeableOPVFactoryProvider( outputProcessViewProviderClassName, outputProcessViewFactoryForge, namespaceScope, numStreams, @base.StatementRawInfo)); forgeablesX.Add( new StmtClassForgeableAIFactoryProviderSelect(statementAIFactoryProviderClassName, namespaceScope, forgeX)); forgeablesX.Add( new StmtClassForgeableStmtFields(statementFieldsClassName, namespaceScope, numStreams)); if (!dataflowOperator) { var informationals = StatementInformationalsUtil.GetInformationals( @base, filterSpecCompileds, scheduleHandleCallbackProviders, namedWindowConsumers, true, resultSetProcessorDesc.SelectSubscriberDescriptor, namespaceScope, services); forgeablesX.Add( new StmtClassForgeableStmtProvider(statementAIFactoryProviderClassName, statementProviderClassName, informationals, namespaceScope)); } var forgeableResult = new StmtForgeMethodResult( forgeablesX, filterSpecCompileds, scheduleHandleCallbackProviders, namedWindowConsumers, FilterSpecCompiled.MakeExprNodeList(filterSpecCompileds, EmptyList<FilterSpecParamExprNodeForge>.Instance)); return new StmtForgeMethodSelectResult(forgeableResult, resultSetProcessorDesc.ResultEventType, numStreams); }
public static OutputProcessViewFactoryForgeDesc Make( EventType[] typesPerStream, EventType resultEventType, ResultSetProcessorType resultSetProcessorType, StatementSpecCompiled statementSpec, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { InsertIntoDesc insertIntoDesc = statementSpec.Raw.InsertIntoDesc; SelectClauseStreamSelectorEnum selectStreamSelector = statementSpec.Raw.SelectStreamSelectorEnum; OutputLimitSpec outputLimitSpec = statementSpec.Raw.OutputLimitSpec; int streamCount = statementSpec.StreamSpecs.Length; bool isDistinct = statementSpec.Raw.SelectClauseSpec.IsDistinct; bool isGrouped = statementSpec.GroupByExpressions != null && statementSpec.GroupByExpressions.GroupByNodes.Length > 0; List<StmtClassForgeableFactory> additionalForgeables = new List<StmtClassForgeableFactory>(); // determine routing bool isRouted = false; bool routeToFront = false; if (insertIntoDesc != null) { isRouted = true; routeToFront = services.NamedWindowCompileTimeResolver.Resolve(insertIntoDesc.EventTypeName) != null; } OutputStrategyPostProcessForge outputStrategyPostProcessForge = null; if ((insertIntoDesc != null) || (selectStreamSelector == SelectClauseStreamSelectorEnum.RSTREAM_ONLY)) { SelectClauseStreamSelectorEnum? insertIntoStreamSelector = null; TableMetaData table = null; if (insertIntoDesc != null) { insertIntoStreamSelector = insertIntoDesc.StreamSelector; table = services.TableCompileTimeResolver.Resolve(statementSpec.Raw.InsertIntoDesc.EventTypeName); if (table != null) { EPLValidationUtil.ValidateContextName( true, table.TableName, table.OptionalContextName, statementSpec.Raw.OptionalContextName, true); } } bool audit = AuditEnum.INSERT.GetAudit(statementSpec.Annotations) != null; outputStrategyPostProcessForge = new OutputStrategyPostProcessForge( isRouted, insertIntoStreamSelector, selectStreamSelector, routeToFront, table, audit); } MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKeyDistinct( isDistinct, resultEventType, statementRawInfo, SerdeCompileTimeResolverNonHA.INSTANCE); MultiKeyClassRef distinctMultiKey = multiKeyPlan.ClassRef; additionalForgeables.AddRange(multiKeyPlan.MultiKeyForgeables); OutputProcessViewFactoryForge outputProcessViewFactoryForge; if (outputLimitSpec == null) { if (!isDistinct) { if (outputStrategyPostProcessForge == null || !outputStrategyPostProcessForge.HasTable) { // without table we have a shortcut implementation outputProcessViewFactoryForge = new OutputProcessViewDirectSimpleForge(outputStrategyPostProcessForge); } else { outputProcessViewFactoryForge = new OutputProcessViewDirectForge(outputStrategyPostProcessForge); } } else { outputProcessViewFactoryForge = new OutputProcessViewDirectDistinctOrAfterFactoryForge( outputStrategyPostProcessForge, isDistinct, distinctMultiKey, null, null, resultEventType); } } else if (outputLimitSpec.RateType == OutputLimitRateType.AFTER) { outputProcessViewFactoryForge = new OutputProcessViewDirectDistinctOrAfterFactoryForge( outputStrategyPostProcessForge, isDistinct, distinctMultiKey, outputLimitSpec.AfterTimePeriodExpr, outputLimitSpec.AfterNumberOfEvents, resultEventType); } else { try { bool isWithHavingClause = statementSpec.Raw.HavingClause != null; bool isStartConditionOnCreation = HasOnlyTables(statementSpec.StreamSpecs); OutputConditionFactoryForge outputConditionFactoryForge = OutputConditionFactoryFactory.CreateCondition( outputLimitSpec, isGrouped, isWithHavingClause, isStartConditionOnCreation, statementRawInfo, services); bool hasOrderBy = statementSpec.Raw.OrderByList != null && statementSpec.Raw.OrderByList.Count > 0; bool hasAfter = outputLimitSpec.AfterNumberOfEvents != null || outputLimitSpec.AfterTimePeriodExpr != null; // hint checking with order-by bool hasOptHint = ResultSetProcessorOutputConditionTypeExtensions .GetOutputLimitOpt(statementSpec.Annotations, services.Configuration, hasOrderBy); ResultSetProcessorOutputConditionType conditionType = ResultSetProcessorOutputConditionTypeExtensions .GetConditionType( outputLimitSpec.DisplayLimit, resultSetProcessorType.IsAggregated(), hasOrderBy, hasOptHint, resultSetProcessorType.IsGrouped()); // plan serdes foreach (EventType eventType in typesPerStream) { IList<StmtClassForgeableFactory> serdeForgeables = SerdeEventTypeUtility.Plan( eventType, statementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddRange(serdeForgeables); } bool terminable = outputLimitSpec.RateType == OutputLimitRateType.TERM || outputLimitSpec.IsAndAfterTerminate; outputProcessViewFactoryForge = new OutputProcessViewConditionForge( outputStrategyPostProcessForge, isDistinct, distinctMultiKey, outputLimitSpec.AfterTimePeriodExpr, outputLimitSpec.AfterNumberOfEvents, outputConditionFactoryForge, streamCount, conditionType, terminable, hasAfter, resultSetProcessorType.IsUnaggregatedUngrouped(), selectStreamSelector, typesPerStream, resultEventType); } catch (Exception ex) { throw new ExprValidationException("Failed to validate the output rate limiting clause: " + ex.Message, ex); } } return new OutputProcessViewFactoryForgeDesc(outputProcessViewFactoryForge, additionalForgeables); }
private TableAccessAnalysisResult AnalyzePlanAggregations( string tableName, IList<TableColumnDesc> columns, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { // once upfront: obtains aggregation factories for each aggregation // we do this once as a factory may be a heavier object IDictionary<TableColumnDesc, AggregationForgeFactory> aggregationFactories = new Dictionary<TableColumnDesc, AggregationForgeFactory>(); foreach (var column in columns) { if (column is TableColumnDescAgg) { var agg = (TableColumnDescAgg) column; var factory = agg.Aggregation.Factory; aggregationFactories.Put(column, factory); } } // sort into these categories: // plain / method-agg / access-agg // compile all-column public types IList<TableColumnDescTyped> plainColumns = new List<TableColumnDescTyped>(); IList<TableColumnDescAgg> methodAggColumns = new List<TableColumnDescAgg>(); IList<TableColumnDescAgg> accessAggColumns = new List<TableColumnDescAgg>(); var allColumnsPublicTypes = new LinkedHashMap<string, object>(); foreach (var column in columns) { // handle plain types if (column is TableColumnDescTyped) { var typed = (TableColumnDescTyped) column; plainColumns.Add(typed); allColumnsPublicTypes.Put(column.ColumnName, typed.UnresolvedType); continue; } // handle aggs var agg = (TableColumnDescAgg) column; var aggFactory = aggregationFactories.Get(agg); if (aggFactory.IsAccessAggregation) { accessAggColumns.Add(agg); } else { methodAggColumns.Add(agg); } allColumnsPublicTypes.Put(column.ColumnName, agg.Aggregation.EvaluationType); } // determine column metadata // var columnMetadata = new LinkedHashMap<string, TableMetadataColumn>(); // handle typed columns var allColumnsInternalTypes = new LinkedHashMap<string, object>(); allColumnsInternalTypes.Put(INTERNAL_RESERVED_PROPERTY, typeof(object)); var indexPlain = 1; var assignPairsPlain = new TableMetadataColumnPairPlainCol[plainColumns.Count]; foreach (var typedColumn in plainColumns) { allColumnsInternalTypes.Put(typedColumn.ColumnName, typedColumn.UnresolvedType); columnMetadata.Put( typedColumn.ColumnName, new TableMetadataColumnPlain(typedColumn.ColumnName, typedColumn.IsKey, indexPlain)); assignPairsPlain[indexPlain - 1] = new TableMetadataColumnPairPlainCol( typedColumn.PositionInDeclaration, indexPlain); indexPlain++; } // determine internally-used event type var visibility = services.ModuleVisibilityRules.GetAccessModifierTable(@base, tableName); var internalName = EventTypeNameUtil.GetTableInternalTypeName(tableName); var internalMetadata = new EventTypeMetadata( internalName, @base.ModuleName, EventTypeTypeClass.TABLE_INTERNAL, EventTypeApplicationType.OBJECTARR, visibility, EventTypeBusModifier.NONBUS, false, EventTypeIdPair.Unassigned()); var internalEventType = BaseNestableEventUtil.MakeOATypeCompileTime( internalMetadata, allColumnsInternalTypes, null, null, null, null, services.BeanEventTypeFactoryPrivate, services.EventTypeCompileTimeResolver); services.EventTypeCompileTimeRegistry.NewType(internalEventType); // for use by indexes and lookups var publicName = EventTypeNameUtil.GetTablePublicTypeName(tableName); var publicMetadata = new EventTypeMetadata( publicName, @base.ModuleName, EventTypeTypeClass.TABLE_PUBLIC, EventTypeApplicationType.OBJECTARR, visibility, EventTypeBusModifier.NONBUS, false, EventTypeIdPair.Unassigned()); var publicEventType = BaseNestableEventUtil.MakeOATypeCompileTime( publicMetadata, allColumnsPublicTypes, null, null, null, null, services.BeanEventTypeFactoryPrivate, services.EventTypeCompileTimeResolver); services.EventTypeCompileTimeRegistry.NewType(publicEventType); // handle aggregation-methods single-func first. var methodFactories = new AggregationForgeFactory[methodAggColumns.Count]; var index = 0; var assignPairsMethod = new TableMetadataColumnPairAggMethod[methodAggColumns.Count]; foreach (var column in methodAggColumns) { var factory = aggregationFactories.Get(column); var optionalEnumerationType = EPTypeHelper.OptionalFromEnumerationExpr( statementRawInfo, services, column.Aggregation); methodFactories[index] = factory; var bindingInfo = factory.AggregationPortableValidation; var expression = ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(factory.AggregationExpression); columnMetadata.Put( column.ColumnName, new TableMetadataColumnAggregation( column.ColumnName, false, index, bindingInfo, expression, true, optionalEnumerationType)); assignPairsMethod[index] = new TableMetadataColumnPairAggMethod(column.PositionInDeclaration); index++; } // handle access-aggregation (sharable, multi-value) aggregations var stateFactories = new AggregationStateFactoryForge[accessAggColumns.Count]; var accessAccessorForges = new AggregationAccessorSlotPairForge[accessAggColumns.Count]; var assignPairsAccess = new TableMetadataColumnPairAggAccess[accessAggColumns.Count]; var accessNum = 0; foreach (var column in accessAggColumns) { var factory = aggregationFactories.Get(column); var forge = factory.GetAggregationStateFactory(false); stateFactories[accessNum] = forge; var accessor = factory.AccessorForge; var bindingInfo = factory.AggregationPortableValidation; accessAccessorForges[accessNum] = new AggregationAccessorSlotPairForge(accessNum, accessor); var expression = ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(factory.AggregationExpression); var optionalEnumerationType = EPTypeHelper.OptionalFromEnumerationExpr( statementRawInfo, services, column.Aggregation); columnMetadata.Put( column.ColumnName, new TableMetadataColumnAggregation( column.ColumnName, false, index, bindingInfo, expression, false, optionalEnumerationType)); assignPairsAccess[accessNum] = new TableMetadataColumnPairAggAccess(column.PositionInDeclaration, accessor); index++; accessNum++; } // determine primary key index information var primaryKeyColumns = new List<string>(); var primaryKeyTypes = new List<Type>(); var primaryKeyGetters = new List<EventPropertyGetterSPI>(); var primaryKeyColNums = new List<int>(); var colNum = -1; foreach (var typedColumn in plainColumns) { colNum++; if (typedColumn.IsKey) { primaryKeyColumns.Add(typedColumn.ColumnName); primaryKeyTypes.Add(internalEventType.GetPropertyType(typedColumn.ColumnName)); primaryKeyGetters.Add(internalEventType.GetGetterSPI(typedColumn.ColumnName)); primaryKeyColNums.Add(colNum + 1); } } string[] primaryKeyColumnArray = null; Type[] primaryKeyTypeArray = null; EventPropertyGetterSPI[] primaryKeyGetterArray = null; int[] primaryKeyColNumsArray = null; if (!primaryKeyColumns.IsEmpty()) { primaryKeyColumnArray = primaryKeyColumns.ToArray(); primaryKeyTypeArray = primaryKeyTypes.ToArray(); primaryKeyGetterArray = primaryKeyGetters.ToArray(); primaryKeyColNumsArray = primaryKeyColNums.ToArray(); } var forgeDesc = new AggregationRowStateForgeDesc( methodFactories, null, stateFactories, accessAccessorForges, new AggregationUseFlags(false, false, false)); var multiKeyPlan = MultiKeyPlanner.PlanMultiKey( primaryKeyTypeArray, false, statementRawInfo, services.SerdeResolver); var propertyForges = new DataInputOutputSerdeForge[internalEventType.PropertyNames.Length - 1]; var additionalForgeables = new List<StmtClassForgeableFactory>(multiKeyPlan.MultiKeyForgeables); for (var i = 1; i < internalEventType.PropertyNames.Length; i++) { var propertyName = internalEventType.PropertyNames[i]; var propertyType = internalEventType.Types.Get(propertyName); var desc = SerdeEventPropertyUtility.ForgeForEventProperty( publicEventType, propertyName, propertyType, statementRawInfo, services.SerdeResolver); propertyForges[i - 1] = desc.Forge; // plan serdes for nested types foreach (var eventType in desc.NestedTypes) { var serdeForgeables = SerdeEventTypeUtility.Plan( eventType, statementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddAll(serdeForgeables); } } return new TableAccessAnalysisResult( columnMetadata, internalEventType, propertyForges, publicEventType, assignPairsPlain, assignPairsMethod, assignPairsAccess, forgeDesc, primaryKeyColumnArray, primaryKeyGetterArray, primaryKeyTypeArray, primaryKeyColNumsArray, multiKeyPlan.ClassRef, additionalForgeables); }
private AggregationForgeFactoryAccessSorted HandleNonTable(ExprValidationContext validationContext) { if (positionalParams.Length == 0) { throw new ExprValidationException("Missing the sort criteria expression"); } // validate that the streams referenced in the criteria are a single stream's ISet <int> streams = ExprNodeUtilityQuery.GetIdentStreamNumbers(positionalParams[0]); if (streams.Count > 1 || streams.IsEmpty()) { throw new ExprValidationException(ErrorPrefix + " requires that any parameter expressions evaluate properties of the same stream"); } int streamNum = streams.First(); // validate that there is a remove stream, use "ever" if not if (!_ever && ExprAggMultiFunctionLinearAccessNode.GetIstreamOnly(validationContext.StreamTypeService, streamNum)) { if (_sortedwin) { throw new ExprValidationException(ErrorPrefix + " requires that a data window is declared for the stream"); } } // determine typing and evaluation _containedType = validationContext.StreamTypeService.EventTypes[streamNum]; Type componentType = _containedType.UnderlyingType; Type accessorResultType = componentType; AggregationAccessorForge accessor; TableMetaData tableMetadata = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(_containedType); if (!_sortedwin) { if (tableMetadata != null) { accessor = new AggregationAccessorMinMaxByTable(_max, tableMetadata); } else { accessor = new AggregationAccessorMinMaxByNonTable(_max); } } else { if (tableMetadata != null) { accessor = new AggregationAccessorSortedTable(_max, componentType, tableMetadata); } else { accessor = new AggregationAccessorSortedNonTable(_max, componentType); } accessorResultType = TypeHelper.GetArrayType(accessorResultType); } Pair <ExprNode[], bool[]> criteriaExpressions = CriteriaExpressions; AggregationStateTypeWStream type; if (_ever) { type = _max ? AggregationStateTypeWStream.MAXEVER : AggregationStateTypeWStream.MINEVER; } else { type = AggregationStateTypeWStream.SORTED; } AggregationStateKeyWStream stateKey = new AggregationStateKeyWStream(streamNum, _containedType, type, criteriaExpressions.First, optionalFilter); ExprForge optionalFilterForge = optionalFilter == null ? null : optionalFilter.Forge; EventType streamEventType = validationContext.StreamTypeService.EventTypes[streamNum]; Type[] criteriaTypes = ExprNodeUtilityQuery.GetExprResultTypes(criteriaExpressions.First); DataInputOutputSerdeForge[] criteriaSerdes = new DataInputOutputSerdeForge[criteriaTypes.Length]; for (int i = 0; i < criteriaTypes.Length; i++) { criteriaSerdes[i] = validationContext.SerdeResolver.SerdeForAggregation(criteriaTypes[i], validationContext.StatementRawInfo); } SortedAggregationStateDesc sortedDesc = new SortedAggregationStateDesc( _max, validationContext.ImportService, criteriaExpressions.First, criteriaTypes, criteriaSerdes, criteriaExpressions.Second, _ever, streamNum, this, optionalFilterForge, streamEventType); IList <StmtClassForgeableFactory> serdeForgables = SerdeEventTypeUtility.Plan( _containedType, validationContext.StatementRawInfo, validationContext.SerdeEventTypeRegistry, validationContext.SerdeResolver); validationContext.AdditionalForgeables.AddAll(serdeForgables); return(new AggregationForgeFactoryAccessSorted( this, accessor, accessorResultType, _containedType, stateKey, sortedDesc, AggregationAgentDefault.INSTANCE)); }
private AggregationForgeFactoryAccessSorted HandleCreateTable(ExprValidationContext validationContext) { if (positionalParams.Length == 0) { throw new ExprValidationException("Missing the sort criteria expression"); } string message = "For tables columns, the aggregation function requires the 'sorted(*)' declaration"; if (!_sortedwin && !_ever) { throw new ExprValidationException(message); } if (validationContext.StreamTypeService.StreamNames.Length == 0) { throw new ExprValidationException("'Sorted' requires that the event type is provided"); } EventType containedType = validationContext.StreamTypeService.EventTypes[0]; Type componentType = containedType.UnderlyingType; Pair <ExprNode[], bool[]> criteriaExpressions = CriteriaExpressions; Type accessorResultType = componentType; AggregationAccessorForge accessor; if (!_sortedwin) { accessor = new AggregationAccessorMinMaxByNonTable(_max); } else { accessor = new AggregationAccessorSortedNonTable(_max, componentType); accessorResultType = TypeHelper.GetArrayType(accessorResultType); } Type[] criteriaTypes = ExprNodeUtilityQuery.GetExprResultTypes(criteriaExpressions.First); DataInputOutputSerdeForge[] criteriaSerdes = new DataInputOutputSerdeForge[criteriaTypes.Length]; for (int i = 0; i < criteriaTypes.Length; i++) { criteriaSerdes[i] = validationContext.SerdeResolver.SerdeForAggregation(criteriaTypes[i], validationContext.StatementRawInfo); } SortedAggregationStateDesc stateDesc = new SortedAggregationStateDesc( _max, validationContext.ImportService, criteriaExpressions.First, criteriaTypes, criteriaSerdes, criteriaExpressions.Second, _ever, 0, this, null, containedType); IList <StmtClassForgeableFactory> serdeForgables = SerdeEventTypeUtility.Plan( containedType, validationContext.StatementRawInfo, validationContext.SerdeEventTypeRegistry, validationContext.SerdeResolver); validationContext.AdditionalForgeables.AddAll(serdeForgables); return(new AggregationForgeFactoryAccessSorted(this, accessor, accessorResultType, containedType, null, stateDesc, null)); }
private AggregationLinearFactoryDesc HandleNonIntoTable( ExprNode[] childNodes, AggregationAccessorLinearType?stateType, ExprValidationContext validationContext) { var streamTypeService = validationContext.StreamTypeService; int streamNum; Type resultType; ExprForge forge; ExprNode evaluatorIndex = null; bool istreamOnly; EventType containedType; Type scalarCollectionComponentType = null; // validate wildcard use var isWildcard = childNodes.Length == 0 || childNodes.Length > 0 && childNodes[0] is ExprWildcard; if (isWildcard) { ExprAggMultiFunctionUtil.ValidateWildcardStreamNumbers(validationContext.StreamTypeService, stateType?.GetNameInvariant()); streamNum = 0; containedType = streamTypeService.EventTypes[0]; resultType = containedType.UnderlyingType; var tableMetadataX = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(containedType); forge = ExprNodeUtilityMake.MakeUnderlyingForge(0, resultType, tableMetadataX); istreamOnly = GetIstreamOnly(streamTypeService, 0); if ((stateType == AggregationAccessorLinearType.WINDOW) && istreamOnly && !streamTypeService.IsOnDemandStreams) { throw MakeUnboundValidationEx(stateType); } } else if (childNodes.Length > 0 && childNodes[0] is ExprStreamUnderlyingNode) { // validate "stream.*" streamNum = ExprAggMultiFunctionUtil.ValidateStreamWildcardGetStreamNum(childNodes[0]); istreamOnly = GetIstreamOnly(streamTypeService, streamNum); if ((stateType == AggregationAccessorLinearType.WINDOW) && istreamOnly && !streamTypeService.IsOnDemandStreams) { throw MakeUnboundValidationEx(stateType); } var type = streamTypeService.EventTypes[streamNum]; containedType = type; resultType = type.UnderlyingType; var tableMetadataX = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(type); forge = ExprNodeUtilityMake.MakeUnderlyingForge(streamNum, resultType, tableMetadataX); } else { // validate when neither wildcard nor "stream.*" var child = childNodes[0]; var streams = ExprNodeUtilityQuery.GetIdentStreamNumbers(child); if (streams.IsEmpty() || (streams.Count > 1)) { throw new ExprValidationException( GetErrorPrefix(stateType) + " requires that any child expressions evaluate properties of the same stream; Use 'firstever' or 'lastever' or 'nth' instead"); } streamNum = streams.First(); istreamOnly = GetIstreamOnly(streamTypeService, streamNum); if ((stateType == AggregationAccessorLinearType.WINDOW) && istreamOnly && !streamTypeService.IsOnDemandStreams) { throw MakeUnboundValidationEx(stateType); } resultType = childNodes[0].Forge.EvaluationType; forge = childNodes[0].Forge; if (streamNum >= streamTypeService.EventTypes.Length) { containedType = streamTypeService.EventTypes[0]; } else { containedType = streamTypeService.EventTypes[streamNum]; } scalarCollectionComponentType = resultType; } if (childNodes.Length > 1) { if (stateType == AggregationAccessorLinearType.WINDOW) { throw new ExprValidationException(GetErrorPrefix(stateType) + " does not accept an index expression; Use 'first' or 'last' instead"); } evaluatorIndex = childNodes[1]; var indexResultType = evaluatorIndex.Forge.EvaluationType; if (indexResultType != typeof(int?) && indexResultType != typeof(int)) { throw new ExprValidationException(GetErrorPrefix(stateType) + " requires an index expression that returns an integer value"); } } // determine accessor AggregationAccessorForge accessor; if (evaluatorIndex != null) { var isFirst = stateType == AggregationAccessorLinearType.FIRST; var constant = -1; ExprForge forgeIndex; if (evaluatorIndex.Forge.ForgeConstantType.IsCompileTimeConstant) { constant = evaluatorIndex.Forge.ExprEvaluator.Evaluate(null, true, null).AsInt32(); forgeIndex = null; } else { forgeIndex = evaluatorIndex.Forge; } accessor = new AggregationAccessorFirstLastIndexWEvalForge(streamNum, forge, forgeIndex, constant, isFirst); } else { if (stateType == AggregationAccessorLinearType.FIRST) { accessor = new AggregationAccessorFirstWEvalForge(streamNum, forge); } else if (stateType == AggregationAccessorLinearType.LAST) { accessor = new AggregationAccessorLastWEvalForge(streamNum, forge); } else if (stateType == AggregationAccessorLinearType.WINDOW) { accessor = new AggregationAccessorWindowWEvalForge(streamNum, forge, resultType); } else { throw new IllegalStateException("Access type is undefined or not known as code '" + stateType + "'"); } } var accessorResultType = resultType; if (stateType == AggregationAccessorLinearType.WINDOW) { accessorResultType = TypeHelper.GetArrayType(resultType); } var isFafWindow = streamTypeService.IsOnDemandStreams && stateType == AggregationAccessorLinearType.WINDOW; var tableMetadata = validationContext.TableCompileTimeResolver.ResolveTableFromEventType(containedType); if (tableMetadata == null && !isFafWindow && (istreamOnly || streamTypeService.IsOnDemandStreams)) { if (optionalFilter != null) { positionalParams = ExprNodeUtilityMake.AddExpression(positionalParams, optionalFilter); } var serde = validationContext.SerdeResolver.SerdeForAggregation(accessorResultType, validationContext.StatementRawInfo); AggregationForgeFactory factoryX = new AggregationForgeFactoryFirstLastUnbound(this, accessorResultType, optionalFilter != null, serde); return(new AggregationLinearFactoryDesc(factoryX, containedType, scalarCollectionComponentType, streamNum)); } var stateKey = new AggregationStateKeyWStream( streamNum, containedType, AggregationStateTypeWStream.DATAWINDOWACCESS_LINEAR, ExprNodeUtilityQuery.EMPTY_EXPR_ARRAY, optionalFilter); var optionalFilterForge = optionalFilter == null ? null : optionalFilter.Forge; AggregationStateFactoryForge stateFactory = new AggregationStateLinearForge(this, streamNum, optionalFilterForge); var factory = new AggregationForgeFactoryAccessLinear( this, accessor, accessorResultType, stateKey, stateFactory, AggregationAgentDefault.INSTANCE, containedType); var enumerationType = scalarCollectionComponentType == null ? containedType : null; var serdeForgables = SerdeEventTypeUtility.Plan( containedType, validationContext.StatementRawInfo, validationContext.SerdeEventTypeRegistry, validationContext.SerdeResolver); validationContext.AdditionalForgeables.AddAll(serdeForgables); return(new AggregationLinearFactoryDesc(factory, enumerationType, scalarCollectionComponentType, streamNum)); }
private static void RecursiveCompile( EvalForgeNode evalNode, MatchEventSpec tags, Stack<EvalForgeNode> parentNodeStack, ISet<string> allTagNamesOrdered, int streamNum, IList<StmtClassForgeableFactory> additionalForgeables, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { parentNodeStack.Push(evalNode); foreach (var child in evalNode.ChildNodes) { RecursiveCompile( child, tags, parentNodeStack, allTagNamesOrdered, streamNum, additionalForgeables, 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); } var forgeables = SerdeEventTypeUtility.Plan( pair.First, statementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddAll(forgeables); } // 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); } var forgeables = SerdeEventTypeUtility.Plan( mapEventType, statementRawInfo, services.SerdeEventTypeRegistry, services.SerdeResolver); additionalForgeables.AddAll(forgeables); } } StreamTypeService streamTypeService = new StreamTypeServiceImpl(filterTypes, true, false); var exprNodes = filterNode.RawFilterSpec.FilterExpressions; FilterSpecCompiledDesc compiled = FilterSpecCompiler.MakeFilterSpec( resolvedEventType, eventName, exprNodes, filterNode.RawFilterSpec.OptionalPropertyEvalSpec, filterTaggedEventTypes, arrayCompositeEventTypes, allTagNamesOrdered, streamTypeService, null, statementRawInfo, services); filterNode.FilterSpec = compiled.FilterSpecCompiled; additionalForgeables.AddAll(compiled.AdditionalForgeables); } 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, null, false); 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, null, false); 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, null, false); 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"); } var multiKeyPlan = MultiKeyPlanner.PlanMultiKey(distinctExpressions.ToArray(), false, statementRawInfo, services.SerdeResolver); distinctNode.SetDistinctExpressions(distinctExpressions, multiKeyPlan.ClassRef, timePeriodComputeForge, expiryTimeExp); additionalForgeables.AddAll(multiKeyPlan.MultiKeyForgeables); } 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, null, false); 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); } }