Exemplo n.º 1
0
 public override IList<StmtClassForgeableFactory> InitAdditionalForgeables(ViewForgeEnv viewForgeEnv)
 {
     return SerdeEventTypeUtility.Plan(
         eventType,
         viewForgeEnv.StatementRawInfo,
         viewForgeEnv.SerdeEventTypeRegistry,
         viewForgeEnv.SerdeResolver);
 }
        private AggregationLinearFactoryDesc HandleCreateTable(
            ExprNode[] childNodes,
            AggregationAccessorLinearType?stateType,
            ExprValidationContext validationContext)
        {
            var message = "For tables columns, the " +
                          stateType?.GetNameInvariant() +
                          " aggregation function requires the 'window(*)' declaration";

            if (stateType != AggregationAccessorLinearType.WINDOW)
            {
                throw new ExprValidationException(message);
            }

            if (childNodes.Length == 0 || childNodes.Length > 1 || !(childNodes[0] is ExprWildcard))
            {
                throw new ExprValidationException(message);
            }

            if (validationContext.StreamTypeService.StreamNames.Length == 0)
            {
                throw new ExprValidationException(GetErrorPrefix(stateType) + " requires that the event type is provided");
            }

            var containedType = validationContext.StreamTypeService.EventTypes[0];
            var componentType = containedType.UnderlyingType;
            AggregationAccessorForge     accessor     = new AggregationAccessorWindowNoEvalForge(componentType);
            AggregationStateFactoryForge stateFactory = new AggregationStateLinearForge(this, 0, null);
            var factory = new AggregationForgeFactoryAccessLinear(
                this,
                accessor,
                TypeHelper.GetArrayType(componentType),
                null,
                stateFactory,
                null,
                containedType);

            var additionalForgeables = SerdeEventTypeUtility.Plan(
                containedType,
                validationContext.StatementRawInfo,
                validationContext.SerdeEventTypeRegistry,
                validationContext.SerdeResolver);

            validationContext.AdditionalForgeables.AddAll(additionalForgeables);

            return(new AggregationLinearFactoryDesc(factory, containedType, null, 0));
        }
Exemplo n.º 3
0
        public static SelectExprProcessorDescriptor GetProcessor(
            SelectProcessorArgs args,
            InsertIntoDesc insertIntoDesc,
            bool withSubscriber)
        {
            IList<StmtClassForgeableFactory> additionalForgeables = new List<StmtClassForgeableFactory>();

            SelectExprProcessorWInsertTarget synthetic = GetProcessorInternal(args, insertIntoDesc);
            additionalForgeables.AddAll(synthetic.AdditionalForgeables);

            // plan serdes for variant event types
            if (synthetic.InsertIntoTargetType is VariantEventType ||
                synthetic.InsertIntoTargetType is WrapperEventType && 
                (((WrapperEventType) synthetic.InsertIntoTargetType).UnderlyingEventType is VariantEventType)) {
                var serdeForgeables = SerdeEventTypeUtility.Plan(
                    synthetic.Forge.ResultEventType,
                    args.StatementRawInfo,
                    args.CompileTimeServices.SerdeEventTypeRegistry,
                    args.CompileTimeServices.SerdeResolver);
                additionalForgeables.AddAll(serdeForgeables);
                foreach (EventType eventType in args.TypeService.EventTypes) {
                    serdeForgeables = SerdeEventTypeUtility.Plan(
                        eventType,
                        args.StatementRawInfo,
                        args.CompileTimeServices.SerdeEventTypeRegistry,
                        args.CompileTimeServices.SerdeResolver);
                    additionalForgeables.AddAll(serdeForgeables);
                }
            }

            if (args.IsFireAndForget || !withSubscriber) {
                return new SelectExprProcessorDescriptor(new SelectSubscriberDescriptor(), synthetic.Forge, additionalForgeables);
            }

            // Handle for-clause delivery contract checking
            ExprNode[] groupedDeliveryExpr = null;
            MultiKeyClassRef groupedDeliveryMultiKey = null;

            var forDelivery = false;
            if (args.ForClauseSpec != null) {
                foreach (var item in args.ForClauseSpec.Clauses) {
                    if (item.Keyword == null) {
                        throw new ExprValidationException(
                            "Expected any of the " +
                            EnumHelper.GetValues<ForClauseKeyword>().RenderAny().ToLowerInvariant() +
                            " for-clause keywords after reserved keyword 'for'");
                    }

                    try {
                        var keyword = EnumHelper.Parse<ForClauseKeyword>(item.Keyword);
                        if (keyword == ForClauseKeyword.GROUPED_DELIVERY && item.Expressions.IsEmpty()) {
                            throw new ExprValidationException(
                                "The for-clause with the " +
                                ForClauseKeyword.GROUPED_DELIVERY.GetName() +
                                " keyword requires one or more grouping expressions");
                        }

                        if (keyword == ForClauseKeyword.DISCRETE_DELIVERY && !item.Expressions.IsEmpty()) {
                            throw new ExprValidationException(
                                "The for-clause with the " +
                                ForClauseKeyword.DISCRETE_DELIVERY.GetName() +
                                " keyword does not allow grouping expressions");
                        }

                        if (forDelivery) {
                            throw new ExprValidationException(
                                "The for-clause with delivery keywords may only occur once in a statement");
                        }
                    }
                    catch (ExprValidationException) {
                        throw;
                    }
                    catch (EPException) {
                        throw;
                    }
                    catch (Exception) {
                        throw new ExprValidationException(
                            "Expected any of the " +
                            EnumHelper.GetValues<ForClauseKeyword>().RenderAny().ToLowerInvariant() +
                            " for-clause keywords after reserved keyword 'for'");
                    }

                    StreamTypeService type = new StreamTypeServiceImpl(synthetic.Forge.ResultEventType, null, false);
                    groupedDeliveryExpr = new ExprNode[item.Expressions.Count];
                    var validationContext = new ExprValidationContextBuilder(
                            type,
                            args.StatementRawInfo,
                            args.CompileTimeServices)
                        .WithAllowBindingConsumption(true)
                        .Build();
                    for (var i = 0; i < item.Expressions.Count; i++) {
                        groupedDeliveryExpr[i] = ExprNodeUtilityValidate.GetValidatedSubtree(
                            ExprNodeOrigin.FORCLAUSE,
                            item.Expressions[i],
                            validationContext);
                    }

                    forDelivery = true;
                    
                    MultiKeyPlan multiKeyPlan = MultiKeyPlanner.PlanMultiKey(
                        groupedDeliveryExpr, false, args.StatementRawInfo, args.SerdeResolver);
                    groupedDeliveryMultiKey = multiKeyPlan.ClassRef;
                    additionalForgeables = multiKeyPlan.MultiKeyForgeables;
                }

                if (groupedDeliveryExpr != null && groupedDeliveryExpr.Length == 0) {
                    groupedDeliveryExpr = null;
                }
            }

            var allowSubscriber = args.CompileTimeServices.Configuration.Compiler.ByteCode.IsAllowSubscriber;
            SelectSubscriberDescriptor descriptor;
            SelectExprProcessorForge forge;

            if (allowSubscriber) {
                BindProcessorForge bindProcessor = new BindProcessorForge(
                    synthetic.Forge,
                    args.SelectionList,
                    args.TypeService.EventTypes,
                    args.TypeService.StreamNames,
                    args.TableCompileTimeResolver);
                descriptor = new SelectSubscriberDescriptor(
                    bindProcessor.ExpressionTypes,
                    bindProcessor.ColumnNamesAssigned,
                    forDelivery,
                    groupedDeliveryExpr,
                    groupedDeliveryMultiKey);
                forge = new BindSelectExprProcessorForge(synthetic.Forge, bindProcessor);
            } else {
                descriptor = new SelectSubscriberDescriptor();
                forge = new ListenerOnlySelectExprProcessorForge(synthetic.Forge);
            }

            return new SelectExprProcessorDescriptor(descriptor, forge, additionalForgeables);
        }
Exemplo n.º 4
0
        public static ViewFactoryForgeDesc CreateForges(
            ViewSpec[] viewSpecDefinitions,
            ViewFactoryForgeArgs args,
            EventType parentEventType)
        {
            try {
                // Clone the view spec list to prevent parameter modification
                var viewSpecList = new List<ViewSpec>(viewSpecDefinitions);
                var viewForgeEnv = new ViewForgeEnv(args);
                var additionalForgeables = new List<StmtClassForgeableFactory>();

                // Inspect views and add merge views if required
                // As users can specify merge views, if they are not provided they get added
                AddMergeViews(viewSpecList);

                // Instantiate factories, not making them aware of each other yet, we now have a chain
                var forgesChain = InstantiateFactories(viewSpecList, args, viewForgeEnv);

                
                // Determine event type serdes that may be required
                foreach (ViewFactoryForge forge in forgesChain) {
                    if (forge is DataWindowViewForge) {
                        IList<StmtClassForgeableFactory> serdeForgeables = SerdeEventTypeUtility.Plan(
                            parentEventType,
                            viewForgeEnv.StatementRawInfo,
                            viewForgeEnv.SerdeEventTypeRegistry,
                            viewForgeEnv.SerdeResolver);
                        additionalForgeables.AddAll(serdeForgeables);
                    }
                }
                
                // Build data window views that occur next to each other ("d d", "d d d") into a single intersection or union
                // Calls attach on the contained-views.
                var forgesChainWIntersections = BuildIntersectionsUnions(
                    forgesChain,
                    args,
                    viewForgeEnv,
                    parentEventType);

                // Verify group window use
                VerifyGroups(forgesChainWIntersections);

                // Build group window views that may contain data windows and also intersection and union
                // Calls attach on the contained-views.
                var forgesGrouped = BuildGrouped(forgesChainWIntersections, args, viewForgeEnv, parentEventType);

                var eventType = parentEventType;

                for (var i = 0; i < forgesGrouped.Count; i++) {
                    ViewFactoryForge factoryToAttach = forgesGrouped[i];
                    try {
                        factoryToAttach.Attach(eventType, args.StreamNum, viewForgeEnv);
                        eventType = factoryToAttach.EventType;
                    }
                    catch (ViewParameterException ex) {
                        throw new ViewProcessingException(ex.Message, ex);
                    }
                }

                // get multikey forges
                var multikeyForges = GetMultikeyForges(forgesGrouped, viewForgeEnv);
                additionalForgeables.AddAll(multikeyForges);

                return new ViewFactoryForgeDesc(forgesGrouped, additionalForgeables);
            }
            catch (ViewProcessingException ex) {
                throw new ExprValidationException("Failed to validate data window declaration: " + ex.Message, ex);
            }
        }
Exemplo n.º 5
0
        private ContextDetailMatchPair ValidateRewriteContextCondition(
            bool isStartCondition,
            int nestingLevel,
            ContextSpecCondition endpoint,
            ISet<string> eventTypesReferenced,
            MatchEventSpec priorMatches,
            ISet<string> priorAllTags,
            CreateContextValidationEnv validationEnv)
        {
            if (endpoint is ContextSpecConditionCrontab) {
                var crontab = (ContextSpecConditionCrontab) endpoint;
                var forgesPerCrontab = new ExprForge[crontab.Crontabs.Count][];
                for (int i = 0; i < crontab.Crontabs.Count; i++) {
                    var item = crontab.Crontabs[i];
                    var forges = ScheduleExpressionUtil.CrontabScheduleValidate(
                        ExprNodeOrigin.CONTEXTCONDITION,
                        item,
                        false,
                        validationEnv.StatementRawInfo,
                        validationEnv.Services);
                    forgesPerCrontab[i] = forges;
                }
                crontab.ForgesPerCrontab = forgesPerCrontab;
                validationEnv.ScheduleHandleCallbackProviders.Add(crontab);
                return new ContextDetailMatchPair(
                    crontab,
                    new MatchEventSpec(),
                    new LinkedHashSet<string>(),
                    EmptyList<StmtClassForgeableFactory>.Instance);
            }

            if (endpoint is ContextSpecConditionTimePeriod) {
                var timePeriod = (ContextSpecConditionTimePeriod) endpoint;
                var validationContext = new ExprValidationContextBuilder(
                    new StreamTypeServiceImpl(false),
                    validationEnv.StatementRawInfo,
                    validationEnv.Services).Build();
                ExprNodeUtilityValidate.GetValidatedSubtree(
                    ExprNodeOrigin.CONTEXTCONDITION,
                    timePeriod.TimePeriod,
                    validationContext);
                if (timePeriod.TimePeriod.IsConstantResult) {
                    if (timePeriod.TimePeriod.EvaluateAsSeconds(null, true, null) < 0) {
                        throw new ExprValidationException(
                            "Invalid negative time period expression '" +
                            ExprNodeUtilityPrint.ToExpressionStringMinPrecedenceSafe(timePeriod.TimePeriod) +
                            "'");
                    }
                }

                validationEnv.ScheduleHandleCallbackProviders.Add(timePeriod);
                return new ContextDetailMatchPair(
                    timePeriod,
                    new MatchEventSpec(),
                    new LinkedHashSet<string>(),
                    EmptyList<StmtClassForgeableFactory>.Instance);
            }

            if (endpoint is ContextSpecConditionPattern) {
                var pattern = (ContextSpecConditionPattern) endpoint;
                var matches = ValidatePatternContextConditionPattern(
                    isStartCondition,
                    nestingLevel,
                    pattern,
                    eventTypesReferenced,
                    priorMatches,
                    priorAllTags,
                    validationEnv);

                var validatedDesc = ValidatePatternContextConditionPattern(
                    isStartCondition,
                    nestingLevel,
                    pattern,
                    eventTypesReferenced,
                    priorMatches,
                    priorAllTags,
                    validationEnv);
                return new ContextDetailMatchPair(
                    pattern,
                    validatedDesc.MatchEventSpec,
                    validatedDesc.AllTags,
                    validatedDesc.AdditionalForgeables);
            }

            if (endpoint is ContextSpecConditionFilter) {
                var filter = (ContextSpecConditionFilter) endpoint;
                ValidateNotTable(filter.FilterSpecRaw.EventTypeName, validationEnv.Services);

                // compile as filter if there are no prior match to consider
                if (priorMatches == null ||
                    priorMatches.ArrayEventTypes.IsEmpty() && priorMatches.TaggedEventTypes.IsEmpty()) {
                    var rawExpr = new FilterStreamSpecRaw(
                        filter.FilterSpecRaw,
                        ViewSpec.EMPTY_VIEWSPEC_ARRAY,
                        null,
                        StreamSpecOptions.DEFAULT);
                    var compiledDesc = StreamSpecCompiler.Compile(
                        rawExpr,
                        eventTypesReferenced,
                        false,
                        false,
                        true,
                        false,
                        filter.OptionalFilterAsName,
                        0,
                        validationEnv.StatementRawInfo,
                        validationEnv.Services);
                    var compiled = (FilterStreamSpecCompiled) compiledDesc.StreamSpecCompiled;

                    filter.FilterSpecCompiled = compiled.FilterSpecCompiled;
                    var matchEventSpec = new MatchEventSpec();
                    var filterForType = compiled.FilterSpecCompiled.FilterForEventType;
                    var allTags = new LinkedHashSet<string>();
                    if (filter.OptionalFilterAsName != null) {
                        matchEventSpec.TaggedEventTypes.Put(
                            filter.OptionalFilterAsName,
                            new Pair<EventType, string>(filterForType, rawExpr.RawFilterSpec.EventTypeName));
                        allTags.Add(filter.OptionalFilterAsName);
                    }

                    validationEnv.FilterSpecCompileds.Add(compiled.FilterSpecCompiled);
                    var serdeForgeables = SerdeEventTypeUtility.Plan(
                        filter.FilterSpecCompiled.FilterForEventType,
                        validationEnv.StatementRawInfo,
                        validationEnv.Services.SerdeEventTypeRegistry,
                        validationEnv.Services.SerdeResolver);
                    var allForgeables = compiledDesc.AdditionalForgeables
                        .Concat(serdeForgeables)
                        .ToList();
                    return new ContextDetailMatchPair(filter, matchEventSpec, allTags, allForgeables);
                }

                // compile as pattern if there are prior matches to consider, since this is a type of followed-by relationship
                EvalForgeNode forgeNode = new EvalFilterForgeNode(validationEnv.Services.IsAttachPatternText, filter.FilterSpecRaw, filter.OptionalFilterAsName, 0);
                var pattern = new ContextSpecConditionPattern(forgeNode, true, false);
                var validated = ValidatePatternContextConditionPattern(
                    isStartCondition,
                    nestingLevel,
                    pattern,
                    eventTypesReferenced,
                    priorMatches,
                    priorAllTags,
                    validationEnv);
                return new ContextDetailMatchPair(pattern, validated.MatchEventSpec, validated.AllTags, validated.AdditionalForgeables);
            }

            if (endpoint is ContextSpecConditionImmediate || endpoint is ContextSpecConditionNever) {
                return new ContextDetailMatchPair(
                    endpoint,
                    new MatchEventSpec(),
                    new LinkedHashSet<String>(),
                    EmptyList<StmtClassForgeableFactory>.Instance);
            }

            throw new IllegalStateException("Unrecognized endpoint type " + endpoint);
        }
Exemplo n.º 6
0
        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 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);
        }
Exemplo n.º 8
0
        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);
        }
Exemplo n.º 9
0
        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));
        }
Exemplo n.º 13
0
        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);
            }
        }