public JoinSetComposerPrototypeHistorical2StreamDesc(
     JoinSetComposerPrototypeHistorical2StreamForge forge,
     IList<StmtClassForgeableFactory> additionalForgeables)
 {
     Forge = forge;
     AdditionalForgeables = additionalForgeables;
 }
        private static JoinSetComposerPrototypeHistorical2StreamDesc MakeComposerHistorical2Stream(
            OuterJoinDesc[] outerJoinDescs,
            ExprNode whereClause,
            EventType[] streamTypes,
            string[] streamNames,
            HistoricalViewableDesc historicalViewableDesc,
            bool queryPlanLogging,
            StatementRawInfo statementRawInfo,
            StatementCompileTimeServices services)
        {
            var polledViewNum = 0;
            var streamViewNum = 1;
            if (historicalViewableDesc.Historical[1]) {
                streamViewNum = 0;
                polledViewNum = 1;
            }

            // if all-historical join, check dependency
            var isAllHistoricalNoSubordinate = false;
            if (historicalViewableDesc.Historical[0] && historicalViewableDesc.Historical[1]) {
                var graph = new DependencyGraph(2, false);
                graph.AddDependency(0, historicalViewableDesc.DependenciesPerHistorical[0]);
                graph.AddDependency(1, historicalViewableDesc.DependenciesPerHistorical[1]);
                if (graph.FirstCircularDependency != null) {
                    throw new ExprValidationException("Circular dependency detected between historical streams");
                }

                // if both streams are independent
                if (graph.RootNodes.Count == 2) {
                    isAllHistoricalNoSubordinate = true; // No parameters used by either historical
                }
                else {
                    if (graph.GetDependenciesForStream(0).Count == 0) {
                        streamViewNum = 0;
                        polledViewNum = 1;
                    }
                    else {
                        streamViewNum = 1;
                        polledViewNum = 0;
                    }
                }
            }

            // Build an outer join expression node
            var isOuterJoin = false;
            ExprNode outerJoinEqualsNode = null;
            var isInnerJoinOnly = false;
            var outerJoinPerStream = new bool[2];
            if (outerJoinDescs != null && outerJoinDescs.Length > 0) {
                var outerJoinDesc = outerJoinDescs[0];
                isInnerJoinOnly = outerJoinDesc.OuterJoinType.Equals(OuterJoinType.INNER);

                if (isAllHistoricalNoSubordinate) {
                    if (outerJoinDesc.OuterJoinType.Equals(OuterJoinType.FULL)) {
                        isOuterJoin = true;
                        outerJoinPerStream[0] = true;
                        outerJoinPerStream[1] = true;
                    }
                    else if (outerJoinDesc.OuterJoinType.Equals(OuterJoinType.LEFT)) {
                        isOuterJoin = true;
                        outerJoinPerStream[0] = true;
                    }
                    else if (outerJoinDesc.OuterJoinType.Equals(OuterJoinType.RIGHT)) {
                        isOuterJoin = true;
                        outerJoinPerStream[1] = true;
                    }
                }
                else {
                    if (outerJoinDesc.OuterJoinType.Equals(OuterJoinType.FULL)) {
                        isOuterJoin = true;
                        outerJoinPerStream[0] = true;
                        outerJoinPerStream[1] = true;
                    }
                    else if (outerJoinDesc.OuterJoinType.Equals(OuterJoinType.LEFT) &&
                             streamViewNum == 0) {
                        isOuterJoin = true;
                        outerJoinPerStream[0] = true;
                    }
                    else if (outerJoinDesc.OuterJoinType.Equals(OuterJoinType.RIGHT) &&
                             streamViewNum == 1) {
                        isOuterJoin = true;
                        outerJoinPerStream[1] = true;
                    }
                }

                outerJoinEqualsNode = outerJoinDesc.MakeExprNode(statementRawInfo, services);
            }

            // Determine filter for indexing purposes
            ExprNode filterForIndexing = null;
            if (outerJoinEqualsNode != null && whereClause != null && isInnerJoinOnly) {
                // both filter and outer join, add
                filterForIndexing = new ExprAndNodeImpl();
                filterForIndexing.AddChildNode(whereClause);
                filterForIndexing.AddChildNode(outerJoinEqualsNode);
            }
            else if (outerJoinEqualsNode == null && whereClause != null) {
                filterForIndexing = whereClause;
            }
            else if (outerJoinEqualsNode != null) {
                filterForIndexing = outerJoinEqualsNode;
            }

            var indexStrategies =
                DetermineIndexing(
                    filterForIndexing,
                    streamTypes[polledViewNum],
                    streamTypes[streamViewNum],
                    polledViewNum,
                    streamViewNum,
                    streamNames,
                    statementRawInfo,
                    services);

            QueryPlanIndexHook hook = QueryPlanIndexHookUtil.GetHook(
                statementRawInfo.Annotations,
                services.ImportServiceCompileTime);
            if (queryPlanLogging && (QUERY_PLAN_LOG.IsInfoEnabled || hook != null)) {
                QUERY_PLAN_LOG.Info("historical lookup strategy: " + indexStrategies.LookupForge.ToQueryPlan());
                QUERY_PLAN_LOG.Info("historical index strategy: " + indexStrategies.IndexingForge.ToQueryPlan());
                hook?.Historical(
                    new QueryPlanIndexDescHistorical(
                        indexStrategies.LookupForge.GetType().GetSimpleName(),
                        indexStrategies.IndexingForge.GetType().GetSimpleName()));
            }

            JoinSetComposerPrototypeHistorical2StreamForge forge = new JoinSetComposerPrototypeHistorical2StreamForge(
                streamTypes,
                whereClause,
                isOuterJoin,
                polledViewNum,
                streamViewNum,
                outerJoinEqualsNode,
                indexStrategies.LookupForge,
                indexStrategies.IndexingForge,
                isAllHistoricalNoSubordinate,
                outerJoinPerStream);
            return new JoinSetComposerPrototypeHistorical2StreamDesc(
                forge, indexStrategies.AdditionalForgeables);
        }