コード例 #1
0
 public StatementAgentInstanceFactorySelect(
     int numStreams,
     ViewableActivator[] eventStreamParentViewableActivators,
     StatementContext statementContext,
     StatementSpecCompiled statementSpec,
     EPServicesContext services,
     StreamTypeService typeService,
     ViewFactoryChain[] unmaterializedViewChain,
     ResultSetProcessorFactoryDesc resultSetProcessorFactoryDesc,
     StreamJoinAnalysisResult joinAnalysisResult,
     bool recoveringResilient,
     JoinSetComposerPrototype joinSetComposerPrototype,
     SubSelectStrategyCollection subSelectStrategyCollection,
     ViewResourceDelegateVerified viewResourceDelegate,
     OutputProcessViewFactory outputProcessViewFactory) :
     base(statementSpec.Annotations)
 {
     _numStreams = numStreams;
     _eventStreamParentViewableActivators = eventStreamParentViewableActivators;
     _statementContext              = statementContext;
     _statementSpec                 = statementSpec;
     _services                      = services;
     _typeService                   = typeService;
     _unmaterializedViewChain       = unmaterializedViewChain;
     _resultSetProcessorFactoryDesc = resultSetProcessorFactoryDesc;
     _joinAnalysisResult            = joinAnalysisResult;
     _joinSetComposerPrototype      = joinSetComposerPrototype;
     _subSelectStrategyCollection   = subSelectStrategyCollection;
     _viewResourceDelegate          = viewResourceDelegate;
     _outputProcessViewFactory      = outputProcessViewFactory;
 }
コード例 #2
0
 public JoinSetComposerPrototypeImpl(string statementName,
                                     string statementId,
                                     OuterJoinDesc[] outerJoinDescList,
                                     ExprNode optionalFilterNode,
                                     EventType[] streamTypes,
                                     string[] streamNames,
                                     StreamJoinAnalysisResult streamJoinAnalysisResult,
                                     Attribute[] annotations,
                                     HistoricalViewableDesc historicalViewableDesc,
                                     ExprEvaluatorContext exprEvaluatorContext,
                                     QueryPlanIndex[] indexSpecs,
                                     QueryPlan queryPlan,
                                     HistoricalStreamIndexList[] historicalStreamIndexLists,
                                     bool joinRemoveStream,
                                     bool isOuterJoins,
                                     TableService tableService)
 {
     _statementName            = statementName;
     _statementId              = statementId;
     _outerJoinDescList        = outerJoinDescList;
     _optionalFilterNode       = optionalFilterNode;
     _streamTypes              = streamTypes;
     _streamNames              = streamNames;
     _streamJoinAnalysisResult = streamJoinAnalysisResult;
     _annotations              = annotations;
     _historicalViewableDesc   = historicalViewableDesc;
     _exprEvaluatorContext     = exprEvaluatorContext;
     _indexSpecs = indexSpecs;
     _queryPlan  = queryPlan;
     _historicalStreamIndexLists = historicalStreamIndexLists;
     _joinRemoveStream           = joinRemoveStream;
     _isOuterJoins = isOuterJoins;
     _tableService = tableService;
 }
コード例 #3
0
        private JoinPlanResult HandleJoin(
            string[] streamNames,
            Viewable[] streamViews,
            ResultSetProcessor resultSetProcessor,
            AgentInstanceContext agentInstanceContext,
            IList <StopCallback> stopCallbacks,
            StreamJoinAnalysisResult joinAnalysisResult,
            bool isRecoveringResilient)
        {
            var joinSetComposerDesc = _joinSetComposerPrototype.Create(streamViews, false, agentInstanceContext, isRecoveringResilient);

            stopCallbacks.Add(new ProxyStopCallback(() => joinSetComposerDesc.JoinSetComposer.Destroy()));

            var filter        = new JoinSetFilter(joinSetComposerDesc.PostJoinFilterEvaluator);
            var indicatorView = _outputProcessViewFactory.MakeView(resultSetProcessor, agentInstanceContext);

            // Create strategy for join execution
            JoinExecutionStrategy execution = new JoinExecutionStrategyImpl(joinSetComposerDesc.JoinSetComposer, filter, indicatorView, agentInstanceContext);

            // The view needs a reference to the join execution to pull iterator values
            indicatorView.JoinExecutionStrategy = execution;

            // Hook up dispatchable with buffer and execution strategy
            var joinStatementDispatch = new JoinExecStrategyDispatchable(execution, _statementSpec.StreamSpecs.Length);

            agentInstanceContext.EpStatementAgentInstanceHandle.OptionalDispatchable = joinStatementDispatch;

            JoinPreloadMethod preloadMethod;

            if (joinAnalysisResult.UnidirectionalStreamNumber >= 0)
            {
                preloadMethod = new JoinPreloadMethodNull();
            }
            else
            {
                if (!joinSetComposerDesc.JoinSetComposer.AllowsInit)
                {
                    preloadMethod = new JoinPreloadMethodNull();
                }
                else
                {
                    preloadMethod = new JoinPreloadMethodImpl(streamNames.Length, joinSetComposerDesc.JoinSetComposer);
                }
            }

            // Create buffer for each view. Point buffer to dispatchable for join.
            for (var i = 0; i < _statementSpec.StreamSpecs.Length; i++)
            {
                var buffer = new BufferView(i);
                streamViews[i].AddView(buffer);
                buffer.Observer = joinStatementDispatch;
                preloadMethod.SetBuffer(buffer, i);
            }

            return(new JoinPlanResult(indicatorView, preloadMethod, joinSetComposerDesc));
        }
コード例 #4
0
 // Remove plans for non-unidirectional streams
 private static void RemoveUnidirectionalAndTable(QueryPlan queryPlan, StreamJoinAnalysisResult streamJoinAnalysisResult)
 {
     for (int streamNum = 0; streamNum < queryPlan.ExecNodeSpecs.Length; streamNum++)
     {
         bool unidirectional = streamJoinAnalysisResult.IsUnidirectional && !streamJoinAnalysisResult.UnidirectionalInd[streamNum];
         bool table          = streamJoinAnalysisResult.TablesPerStream[streamNum] != null;
         if (unidirectional || table)
         {
             queryPlan.ExecNodeSpecs[streamNum] = new QueryPlanNodeNoOp();
         }
     }
 }
コード例 #5
0
        private static void VerifyJoinUnidirectional(
            StreamJoinAnalysisResult analysisResult,
            StatementSpecCompiled statementSpec)
        {
            var numUnidirectionalStreams = analysisResult.UnidirectionalCount;
            var numStreams = statementSpec.StreamSpecs.Length;

            // only a single stream is unidirectional (applies to all but all-full-outer-join)
            if (!IsFullOuterJoinAllStreams(statementSpec))
            {
                if (numUnidirectionalStreams > 1)
                {
                    throw new ExprValidationException(
                              "The unidirectional keyword can only apply to one stream in a join");
                }
            }
            else
            {
                // verify full-outer-join: requires unidirectional for all streams
                if (numUnidirectionalStreams > 1 && numUnidirectionalStreams < numStreams)
                {
                    throw new ExprValidationException(
                              "The unidirectional keyword must either apply to a single stream or all streams in a full outer join");
                }
            }

            // verify no-child-view for unidirectional
            for (var i = 0; i < statementSpec.StreamSpecs.Length; i++)
            {
                if (analysisResult.UnidirectionalInd[i])
                {
                    if (analysisResult.HasChildViews[i])
                    {
                        throw new ExprValidationException(
                                  "The unidirectional keyword requires that no views are declared onto the stream (applies to stream " +
                                  i + ")");
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Build query plan using the filter.
        /// </summary>
        /// <param name="typesPerStream">event types for each stream</param>
        /// <param name="outerJoinDescList">list of outer join criteria, or null if there are no outer joins</param>
        /// <param name="queryGraph">relationships between streams based on filter expressions and outer-join on-criteria</param>
        /// <param name="streamNames">names of streams</param>
        /// <param name="historicalViewableDesc">The historical viewable desc.</param>
        /// <param name="dependencyGraph">dependencies between historical streams</param>
        /// <param name="historicalStreamIndexLists">index management, populated for the query plan</param>
        /// <param name="streamJoinAnalysisResult">The stream join analysis result.</param>
        /// <param name="isQueryPlanLogging">if set to <c>true</c> [is query plan logging].</param>
        /// <param name="annotations">The annotations.</param>
        /// <param name="exprEvaluatorContext">The expr evaluator context.</param>
        /// <returns>
        /// query plan
        /// </returns>
        /// <exception cref="System.ArgumentException">
        /// Number of join stream types is less then 2
        /// or
        /// Too many outer join descriptors found
        /// </exception>
        /// <throws>ExprValidationException if the query plan fails</throws>
        public static QueryPlan GetPlan(EventType[] typesPerStream,
                                        OuterJoinDesc[] outerJoinDescList,
                                        QueryGraph queryGraph,
                                        string[] streamNames,
                                        HistoricalViewableDesc historicalViewableDesc,
                                        DependencyGraph dependencyGraph,
                                        HistoricalStreamIndexList[] historicalStreamIndexLists,
                                        StreamJoinAnalysisResult streamJoinAnalysisResult,
                                        bool isQueryPlanLogging,
                                        Attribute[] annotations,
                                        ExprEvaluatorContext exprEvaluatorContext)

        {
            string methodName = ".getPlan ";

            int numStreams = typesPerStream.Length;

            if (numStreams < 2)
            {
                throw new ArgumentException("Number of join stream types is less then 2");
            }
            if (outerJoinDescList.Length >= numStreams)
            {
                throw new ArgumentException("Too many outer join descriptors found");
            }

            if (numStreams == 2)
            {
                OuterJoinType?outerJoinType = null;
                if (outerJoinDescList.Length > 0)
                {
                    outerJoinType = outerJoinDescList[0].OuterJoinType;
                }

                QueryPlan queryPlanX = TwoStreamQueryPlanBuilder.Build(typesPerStream, queryGraph, outerJoinType, streamJoinAnalysisResult.UniqueKeys, streamJoinAnalysisResult.TablesPerStream);
                RemoveUnidirectionalAndTable(queryPlanX, streamJoinAnalysisResult);

                if (log.IsDebugEnabled)
                {
                    log.Debug(methodName + "2-Stream queryPlan=" + queryPlanX);
                }
                return(queryPlanX);
            }

            bool hasPreferMergeJoin = HintEnum.PREFER_MERGE_JOIN.GetHint(annotations) != null;
            bool hasForceNestedIter = HintEnum.FORCE_NESTED_ITER.GetHint(annotations) != null;
            bool isAllInnerJoins    = outerJoinDescList.Length == 0 || OuterJoinDesc.ConsistsOfAllInnerJoins(outerJoinDescList);

            if (isAllInnerJoins && !hasPreferMergeJoin)
            {
                QueryPlan queryPlanX = NStreamQueryPlanBuilder.Build(queryGraph, typesPerStream,
                                                                     historicalViewableDesc, dependencyGraph, historicalStreamIndexLists,
                                                                     hasForceNestedIter, streamJoinAnalysisResult.UniqueKeys,
                                                                     streamJoinAnalysisResult.TablesPerStream);

                if (queryPlanX != null)
                {
                    RemoveUnidirectionalAndTable(queryPlanX, streamJoinAnalysisResult);

                    if (log.IsDebugEnabled)
                    {
                        log.Debug(methodName + "Count-Stream inner-join queryPlan=" + queryPlanX);
                    }
                    return(queryPlanX);
                }

                if (isQueryPlanLogging && queryPlanLog.IsInfoEnabled)
                {
                    log.Info("Switching to Outer-NStream algorithm for query plan");
                }
            }

            QueryPlan queryPlan = NStreamOuterQueryPlanBuilder.Build(queryGraph, outerJoinDescList, streamNames, typesPerStream,
                                                                     historicalViewableDesc, dependencyGraph, historicalStreamIndexLists, exprEvaluatorContext, streamJoinAnalysisResult.UniqueKeys,
                                                                     streamJoinAnalysisResult.TablesPerStream);

            RemoveUnidirectionalAndTable(queryPlan, streamJoinAnalysisResult);
            return(queryPlan);
        }
コード例 #7
0
        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="statementSpec">is a container for the definition of all statement constructs thatmay have been used in the statement, i.e. if defines the select clauses, insert into, outer joins etc.
        /// </param>
        /// <param name="services">is the service instances for dependency injection</param>
        /// <param name="statementContext">is statement-level information and statement services</param>
        /// <throws>ExprValidationException if the preparation failed</throws>
        public EPPreparedExecuteMethodQuery(StatementSpecCompiled statementSpec,
                                            EPServicesContext services,
                                            StatementContext statementContext)

        {
            var queryPlanLogging = services.ConfigSnapshot.EngineDefaults.LoggingConfig.IsEnableQueryPlan;

            if (queryPlanLogging)
            {
                QueryPlanLog.Info("Query plans for Fire-and-forget query '" + statementContext.Expression + "'");
            }

            _hasTableAccess = (statementSpec.TableNodes != null && statementSpec.TableNodes.Length > 0);
            foreach (var streamSpec in statementSpec.StreamSpecs)
            {
                _hasTableAccess |= streamSpec is TableQueryStreamSpec;
            }

            _statementSpec = statementSpec;
            _services      = services;

            EPPreparedExecuteMethodHelper.ValidateFAFQuery(statementSpec);

            var numStreams     = statementSpec.StreamSpecs.Length;
            var typesPerStream = new EventType[numStreams];
            var namesPerStream = new string[numStreams];

            _processors           = new FireAndForgetProcessor[numStreams];
            _agentInstanceContext = new AgentInstanceContext(statementContext, null, -1, null, null, statementContext.DefaultAgentInstanceScriptContext);

            // resolve types and processors
            for (var i = 0; i < numStreams; i++)
            {
                var streamSpec = statementSpec.StreamSpecs[i];
                _processors[i] = FireAndForgetProcessorFactory.ValidateResolveProcessor(streamSpec, services);

                string streamName = _processors[i].NamedWindowOrTableName;
                if (streamSpec.OptionalStreamName != null)
                {
                    streamName = streamSpec.OptionalStreamName;
                }
                namesPerStream[i] = streamName;
                typesPerStream[i] = _processors[i].EventTypeResultSetProcessor;
            }

            // compile filter to optimize access to named window
            _filters = new FilterSpecCompiled[numStreams];
            if (statementSpec.FilterRootNode != null)
            {
                var tagged = new LinkedHashMap <string, Pair <EventType, string> >();
                for (var i = 0; i < numStreams; i++)
                {
                    try {
                        var types = new StreamTypeServiceImpl(typesPerStream, namesPerStream, new bool[numStreams], services.EngineURI, false);
                        _filters[i] = FilterSpecCompiler.MakeFilterSpec(typesPerStream[i], namesPerStream[i],
                                                                        Collections.SingletonList(statementSpec.FilterRootNode), null,
                                                                        tagged, tagged, types,
                                                                        null, statementContext, Collections.SingletonList(i));
                    }
                    catch (Exception ex) {
                        Log.Warn("Unexpected exception analyzing filter paths: " + ex.Message, ex);
                    }
                }
            }

            // obtain result set processor
            var isIStreamOnly = new bool[namesPerStream.Length];

            CompatExtensions.Fill(isIStreamOnly, true);
            StreamTypeService typeService = new StreamTypeServiceImpl(typesPerStream, namesPerStream, isIStreamOnly, services.EngineURI, true);

            EPStatementStartMethodHelperValidate.ValidateNodes(statementSpec, statementContext, typeService, null);

            var resultSetProcessorPrototype = ResultSetProcessorFactoryFactory.GetProcessorPrototype(statementSpec, statementContext, typeService, null, new bool[0], true, ContextPropertyRegistryImpl.EMPTY_REGISTRY, null, _services.ConfigSnapshot);

            _resultSetProcessor = EPStatementStartMethodHelperAssignExpr.GetAssignResultSetProcessor(_agentInstanceContext, resultSetProcessorPrototype);

            if (statementSpec.SelectClauseSpec.IsDistinct)
            {
                if (_resultSetProcessor.ResultEventType is EventTypeSPI)
                {
                    _eventBeanReader = ((EventTypeSPI)_resultSetProcessor.ResultEventType).GetReader();
                }
                if (_eventBeanReader == null)
                {
                    _eventBeanReader = new EventBeanReaderDefaultImpl(_resultSetProcessor.ResultEventType);
                }
            }

            // plan joins or simple queries
            if (numStreams > 1)
            {
                var streamJoinAnalysisResult = new StreamJoinAnalysisResult(numStreams);
                CompatExtensions.Fill(streamJoinAnalysisResult.NamedWindow, true);
                for (var i = 0; i < numStreams; i++)
                {
                    var processorInstance = _processors[i].GetProcessorInstance(_agentInstanceContext);
                    if (_processors[i].IsVirtualDataWindow)
                    {
                        streamJoinAnalysisResult.ViewExternal[i] = agentInstanceContext => processorInstance.VirtualDataWindow;
                    }
                    var uniqueIndexes = _processors[i].GetUniqueIndexes(processorInstance);
                    streamJoinAnalysisResult.UniqueKeys[i] = uniqueIndexes;
                }

                var hasAggregations = !resultSetProcessorPrototype.AggregationServiceFactoryDesc.Expressions.IsEmpty();
                _joinSetComposerPrototype = JoinSetComposerPrototypeFactory.MakeComposerPrototype(
                    null, null,
                    statementSpec.OuterJoinDescList, statementSpec.FilterRootNode, typesPerStream, namesPerStream,
                    streamJoinAnalysisResult, queryPlanLogging, statementContext, new HistoricalViewableDesc(numStreams),
                    _agentInstanceContext, false, hasAggregations, services.TableService, true);
            }

            // check context partition use
            if (statementSpec.OptionalContextName != null)
            {
                if (numStreams > 1)
                {
                    throw new ExprValidationException("Joins in runtime queries for context partitions are not supported");
                }
            }
        }
コード例 #8
0
        private static StreamJoinAnalysisResult VerifyJoinViews(StatementSpecCompiled statementSpec, NamedWindowMgmtService namedWindowMgmtService, AgentInstanceContext defaultAgentInstanceContext)
        {
            var streamSpecs    = statementSpec.StreamSpecs;
            var analysisResult = new StreamJoinAnalysisResult(streamSpecs.Length);

            if (streamSpecs.Length < 2)
            {
                return(analysisResult);
            }

            // Determine if any stream has a unidirectional keyword

            // inspect unidirectional indicator and named window flags
            var unidirectionalStreamNumber = -1;

            for (var i = 0; i < statementSpec.StreamSpecs.Length; i++)
            {
                var streamSpec = statementSpec.StreamSpecs[i];
                if (streamSpec.Options.IsUnidirectional)
                {
                    analysisResult.SetUnidirectionalInd(i);
                    if (unidirectionalStreamNumber != -1)
                    {
                        throw new ExprValidationException("The unidirectional keyword can only apply to one stream in a join");
                    }
                    unidirectionalStreamNumber = i;
                }
                if (streamSpec.ViewSpecs.Length > 0)
                {
                    analysisResult.SetHasChildViews(i);
                }
                if (streamSpec is NamedWindowConsumerStreamSpec)
                {
                    var nwSpec = (NamedWindowConsumerStreamSpec)streamSpec;
                    if (nwSpec.OptPropertyEvaluator != null && !streamSpec.Options.IsUnidirectional)
                    {
                        throw new ExprValidationException("Failed to validate named window use in join, contained-event is only allowed for named windows when marked as unidirectional");
                    }
                    analysisResult.SetNamedWindow(i);
                    var        processor     = namedWindowMgmtService.GetProcessor(nwSpec.WindowName);
                    string[][] uniqueIndexes = processor.UniqueIndexes;
                    analysisResult.UniqueKeys[i] = uniqueIndexes;
                    if (processor.IsVirtualDataWindow)
                    {
                        analysisResult.ViewExternal[i] = agentInstanceContext => processor.GetProcessorInstance(agentInstanceContext).RootViewInstance.VirtualDataWindow;
                    }
                }
            }
            if ((unidirectionalStreamNumber != -1) && (analysisResult.HasChildViews[unidirectionalStreamNumber]))
            {
                throw new ExprValidationException("The unidirectional keyword requires that no views are declared onto the stream");
            }
            analysisResult.UnidirectionalStreamNumber = unidirectionalStreamNumber;

            // count streams that provide data, excluding streams that poll data (DB and method)
            var countProviderNonpolling = 0;

            for (var i = 0; i < statementSpec.StreamSpecs.Length; i++)
            {
                var streamSpec = statementSpec.StreamSpecs[i];
                if ((streamSpec is MethodStreamSpec) ||
                    (streamSpec is DBStatementStreamSpec) ||
                    (streamSpec is TableQueryStreamSpec))
                {
                    continue;
                }
                countProviderNonpolling++;
            }

            // if there is only one stream providing data, the analysis is done
            if (countProviderNonpolling == 1)
            {
                return(analysisResult);
            }
            // there are multiple driving streams, verify the presence of a view for insert/remove stream

            // validation of join views works differently for unidirectional as there can be self-joins that don't require a view
            // see if this is a self-join in which all streams are filters and filter specification is the same.
            FilterSpecCompiled unidirectionalFilterSpec = null;
            FilterSpecCompiled lastFilterSpec           = null;
            var pureSelfJoin = true;

            foreach (var streamSpec in statementSpec.StreamSpecs)
            {
                if (!(streamSpec is FilterStreamSpecCompiled))
                {
                    pureSelfJoin = false;
                    continue;
                }

                var filterSpec = ((FilterStreamSpecCompiled)streamSpec).FilterSpec;
                if ((lastFilterSpec != null) && (!lastFilterSpec.EqualsTypeAndFilter(filterSpec)))
                {
                    pureSelfJoin = false;
                }
                if (streamSpec.ViewSpecs.Length > 0)
                {
                    pureSelfJoin = false;
                }
                lastFilterSpec = filterSpec;

                if (streamSpec.Options.IsUnidirectional)
                {
                    unidirectionalFilterSpec = filterSpec;
                }
            }

            // self-join without views and not unidirectional
            if ((pureSelfJoin) && (unidirectionalFilterSpec == null))
            {
                analysisResult.IsPureSelfJoin = true;
                return(analysisResult);
            }

            // weed out filter and pattern streams that don't have a view in a join
            for (var i = 0; i < statementSpec.StreamSpecs.Length; i++)
            {
                var streamSpec = statementSpec.StreamSpecs[i];
                if (streamSpec.ViewSpecs.Length > 0)
                {
                    continue;
                }

                var name = streamSpec.OptionalStreamName;
                if ((name == null) && (streamSpec is FilterStreamSpecCompiled))
                {
                    name = ((FilterStreamSpecCompiled)streamSpec).FilterSpec.FilterForEventTypeName;
                }
                if ((name == null) && (streamSpec is PatternStreamSpecCompiled))
                {
                    name = "pattern event stream";
                }

                if (streamSpec.Options.IsUnidirectional)
                {
                    continue;
                }
                // allow a self-join without a child view, in that the filter spec is the same as the unidirection's stream filter
                if ((unidirectionalFilterSpec != null) &&
                    (streamSpec is FilterStreamSpecCompiled) &&
                    (((FilterStreamSpecCompiled)streamSpec).FilterSpec.EqualsTypeAndFilter(unidirectionalFilterSpec)))
                {
                    analysisResult.SetUnidirectionalNonDriving(i);
                    continue;
                }
                if ((streamSpec is FilterStreamSpecCompiled) ||
                    (streamSpec is PatternStreamSpecCompiled))
                {
                    throw new ExprValidationException("Joins require that at least one view is specified for each stream, no view was specified for " + name);
                }
            }

            return(analysisResult);
        }
コード例 #9
0
        /// <summary>
        /// Builds join tuple composer.
        /// </summary>
        /// <param name="statementName">Name of the statement.</param>
        /// <param name="statementId">The statement identifier.</param>
        /// <param name="outerJoinDescList">list of descriptors for outer join criteria</param>
        /// <param name="optionalFilterNode">filter tree for analysis to build indexes for fast access</param>
        /// <param name="streamTypes">types of streams</param>
        /// <param name="streamNames">names of streams</param>
        /// <param name="streamJoinAnalysisResult">The stream join analysis result.</param>
        /// <param name="queryPlanLogging">if set to <c>true</c> [query plan logging].</param>
        /// <param name="statementContext">The statement context.</param>
        /// <param name="historicalViewableDesc">The historical viewable desc.</param>
        /// <param name="exprEvaluatorContext">The expr evaluator context.</param>
        /// <param name="selectsRemoveStream">if set to <c>true</c> [selects remove stream].</param>
        /// <param name="hasAggregations">if set to <c>true</c> [has aggregations].</param>
        /// <param name="tableService">The table service.</param>
        /// <param name="isOnDemandQuery">if set to <c>true</c> [is on demand query].</param>
        /// <param name="allowIndexInit">if set to <c>true</c> [allow index initialize].</param>
        /// <returns>
        /// composer implementation
        /// </returns>
        /// <throws>com.espertech.esper.epl.expression.core.ExprValidationException is thrown to indicate thatvalidation of view use in joins failed.
        /// {D255958A-8513-4226-94B9-080D98F904A1}</throws>
        public static JoinSetComposerPrototype MakeComposerPrototype(string statementName, int statementId, OuterJoinDesc[] outerJoinDescList, ExprNode optionalFilterNode, EventType[] streamTypes, string[] streamNames, StreamJoinAnalysisResult streamJoinAnalysisResult, bool queryPlanLogging, StatementContext statementContext, HistoricalViewableDesc historicalViewableDesc, ExprEvaluatorContext exprEvaluatorContext, bool selectsRemoveStream, bool hasAggregations, TableService tableService, bool isOnDemandQuery, bool allowIndexInit)
        {
            // Determine if there is a historical stream, and what dependencies exist
            var historicalDependencyGraph = new DependencyGraph(streamTypes.Length, false);

            for (var i = 0; i < streamTypes.Length; i++)
            {
                if (historicalViewableDesc.Historical[i])
                {
                    var streamsThisStreamDependsOn = historicalViewableDesc.DependenciesPerHistorical[i];
                    historicalDependencyGraph.AddDependency(i, streamsThisStreamDependsOn);
                }
            }

            if (log.IsDebugEnabled)
            {
                log.Debug("Dependency graph: " + historicalDependencyGraph);
            }

            // Handle a join with a database or other historical data source for 2 streams
            if ((historicalViewableDesc.HasHistorical) && (streamTypes.Length == 2))
            {
                return(MakeComposerHistorical2Stream(outerJoinDescList, optionalFilterNode, streamTypes, historicalViewableDesc, queryPlanLogging, exprEvaluatorContext, statementContext, streamNames, allowIndexInit));
            }

            var isOuterJoins = !OuterJoinDesc.ConsistsOfAllInnerJoins(outerJoinDescList);

            // Query graph for graph relationships between streams/historicals
            // For outer joins the query graph will just contain outer join relationships
            var hint       = ExcludePlanHint.GetHint(streamNames, statementContext);
            var queryGraph = new QueryGraph(streamTypes.Length, hint, false);

            if (outerJoinDescList.Length > 0)
            {
                OuterJoinAnalyzer.Analyze(outerJoinDescList, queryGraph);
                if (log.IsDebugEnabled)
                {
                    log.Debug(".makeComposer After outer join queryGraph=\n" + queryGraph);
                }
            }

            // Let the query graph reflect the where-clause
            if (optionalFilterNode != null)
            {
                // Analyze relationships between streams using the optional filter expression.
                // Relationships are properties in AND and EQUALS nodes of joins.
                FilterExprAnalyzer.Analyze(optionalFilterNode, queryGraph, isOuterJoins);
                if (log.IsDebugEnabled)
                {
                    log.Debug(".makeComposer After filter expression queryGraph=\n" + queryGraph);
                }

                // Add navigation entries based on key and index property equivalency (a=b, b=c follows a=c)
                QueryGraph.FillEquivalentNav(streamTypes, queryGraph);
                if (log.IsDebugEnabled)
                {
                    log.Debug(".makeComposer After fill equiv. nav. queryGraph=\n" + queryGraph);
                }
            }

            // Historical index lists
            var historicalStreamIndexLists = new HistoricalStreamIndexList[streamTypes.Length];

            var queryPlan = QueryPlanBuilder.GetPlan(streamTypes, outerJoinDescList, queryGraph, streamNames,
                                                     historicalViewableDesc, historicalDependencyGraph, historicalStreamIndexLists,
                                                     streamJoinAnalysisResult, queryPlanLogging, statementContext.Annotations, exprEvaluatorContext);

            // remove unused indexes - consider all streams or all unidirectional
            var usedIndexes = new HashSet <TableLookupIndexReqKey>();
            var indexSpecs  = queryPlan.IndexSpecs;

            for (var streamNum = 0; streamNum < queryPlan.ExecNodeSpecs.Length; streamNum++)
            {
                var planNode = queryPlan.ExecNodeSpecs[streamNum];
                if (planNode != null)
                {
                    planNode.AddIndexes(usedIndexes);
                }
            }
            foreach (var indexSpec in indexSpecs)
            {
                if (indexSpec == null)
                {
                    continue;
                }
                var items      = indexSpec.Items;
                var indexNames = items.Keys.ToArray();
                foreach (var indexName in indexNames)
                {
                    if (!usedIndexes.Contains(indexName))
                    {
                        items.Remove(indexName);
                    }
                }
            }

            var hook = QueryPlanIndexHookUtil.GetHook(statementContext.Annotations);

            if (queryPlanLogging && (QueryPlanLog.IsInfoEnabled || hook != null))
            {
                QueryPlanLog.Info("Query plan: " + queryPlan.ToQueryPlan());
                if (hook != null)
                {
                    hook.Join(queryPlan);
                }
            }

            // register index-use references for tables
            if (!isOnDemandQuery)
            {
                foreach (var usedIndex in usedIndexes)
                {
                    if (usedIndex.TableName != null)
                    {
                        tableService.GetTableMetadata(usedIndex.TableName).AddIndexReference(usedIndex.Name, statementName);
                    }
                }
            }

            var joinRemoveStream = selectsRemoveStream || hasAggregations;

            return(new JoinSetComposerPrototypeImpl(
                       statementName,
                       statementId,
                       outerJoinDescList,
                       optionalFilterNode,
                       streamTypes,
                       streamNames,
                       streamJoinAnalysisResult,
                       statementContext.Annotations,
                       historicalViewableDesc,
                       exprEvaluatorContext,
                       indexSpecs,
                       queryPlan,
                       historicalStreamIndexLists,
                       joinRemoveStream,
                       isOuterJoins,
                       tableService,
                       statementContext.EventTableIndexService));
        }