/// <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");
                }
            }
        }
        public override EPStatementStartResult StartInternal(EPServicesContext services, StatementContext statementContext, bool isNewStatement, bool isRecoveringStatement, bool isRecoveringResilient)
        {
            var createDesc = StatementSpec.CreateVariableDesc;

            VariableServiceUtil.CheckAlreadyDeclaredTable(createDesc.VariableName, services.TableService);

            // Get assignment value
            Object value = null;

            if (createDesc.Assignment != null)
            {
                // Evaluate assignment expression
                var typeService          = new StreamTypeServiceImpl(new EventType[0], new String[0], new bool[0], services.EngineURI, false);
                var evaluatorContextStmt = new ExprEvaluatorContextStatement(statementContext, false);
                var validationContext    = new ExprValidationContext(
                    typeService,
                    statementContext.MethodResolutionService, null,
                    statementContext.SchedulingService,
                    statementContext.VariableService,
                    statementContext.TableService, evaluatorContextStmt,
                    statementContext.EventAdapterService,
                    statementContext.StatementName,
                    statementContext.StatementId,
                    statementContext.Annotations,
                    statementContext.ContextDescriptor,
                    statementContext.ScriptingService,
                    false, false, false, false, null, false);
                var validated = ExprNodeUtility.GetValidatedSubtree(ExprNodeOrigin.VARIABLEASSIGN, createDesc.Assignment, validationContext);
                value = validated.ExprEvaluator.Evaluate(new EvaluateParams(null, true, evaluatorContextStmt));
            }

            // Create variable
            try
            {
                services.VariableService.CreateNewVariable(
                    StatementSpec.OptionalContextName,
                    createDesc.VariableName,
                    createDesc.VariableType,
                    createDesc.IsConstant,
                    createDesc.IsArray,
                    createDesc.IsArrayOfPrimitive,
                    value,
                    services.EngineImportService);
            }
            catch (VariableExistsException ex)
            {
                // for new statement we don't allow creating the same variable
                if (isNewStatement)
                {
                    throw new ExprValidationException("Cannot create variable: " + ex.Message, ex);
                }
            }
            catch (VariableDeclarationException ex)
            {
                throw new ExprValidationException("Cannot create variable: " + ex.Message, ex);
            }

            var destroyMethod = new EPStatementDestroyCallbackList();

            destroyMethod.AddCallback(
                () =>
            {
                try
                {
                    services.StatementVariableRefService.RemoveReferencesStatement(statementContext.StatementName);
                }
                catch (Exception ex)
                {
                    Log.Error("Error removing variable '" + createDesc.VariableName + "': " + ex.Message);
                }
            });

            var stopMethod = new EPStatementStopMethod(() => { });

            VariableMetaData variableMetaData = services.VariableService.GetVariableMetaData(createDesc.VariableName);
            Viewable         outputView;

            if (StatementSpec.OptionalContextName != null)
            {
                EventType eventType      = CreateVariableView.GetEventType(statementContext.StatementId, services.EventAdapterService, variableMetaData);
                var       contextFactory = new StatementAgentInstanceFactoryCreateVariable(statementContext, services, variableMetaData, eventType);
                var       mergeView      = new ContextMergeView(eventType);
                outputView = mergeView;
                var statement = new ContextManagedStatementCreateVariableDesc(StatementSpec, statementContext, mergeView, contextFactory);
                services.ContextManagementService.AddStatement(StatementSpec.OptionalContextName, statement, isRecoveringResilient);

                ContextManagementService contextManagementService = services.ContextManagementService;
                destroyMethod.AddCallback(() => contextManagementService.DestroyedStatement(StatementSpec.OptionalContextName, statementContext.StatementName, statementContext.StatementId));
            }
            else
            {
                // allocate
                services.VariableService.AllocateVariableState(createDesc.VariableName, VariableServiceConstants.NOCONTEXT_AGENTINSTANCEID, statementContext.StatementExtensionServicesContext);
                var createView = new CreateVariableView(statementContext.StatementId, services.EventAdapterService, services.VariableService, createDesc.VariableName, statementContext.StatementResultService);

                services.VariableService.RegisterCallback(createDesc.VariableName, 0, createView.Update);
                statementContext.StatementStopService.StatementStopped +=
                    () => services.VariableService.UnregisterCallback(createDesc.VariableName, 0, createView.Update);

                // Create result set processor, use wildcard selection
                StatementSpec.SelectClauseSpec.SetSelectExprList(new SelectClauseElementWildcard());
                StatementSpec.SelectStreamDirEnum = SelectClauseStreamSelectorEnum.RSTREAM_ISTREAM_BOTH;
                StreamTypeService typeService   = new StreamTypeServiceImpl(new EventType[] { createView.EventType }, new String[] { "create_variable" }, new bool[] { true }, services.EngineURI, false);
                var agentInstanceContext        = GetDefaultAgentInstanceContext(statementContext);
                var resultSetProcessorPrototype = ResultSetProcessorFactoryFactory.GetProcessorPrototype(
                    StatementSpec, statementContext, typeService, null, new bool[0], true, ContextPropertyRegistryImpl.EMPTY_REGISTRY, null, services.ConfigSnapshot);
                var resultSetProcessor = EPStatementStartMethodHelperAssignExpr.GetAssignResultSetProcessor(agentInstanceContext, resultSetProcessorPrototype);

                // Attach output view
                var outputViewFactory = OutputProcessViewFactoryFactory.Make(StatementSpec, services.InternalEventRouter, agentInstanceContext.StatementContext, resultSetProcessor.ResultEventType, null, services.TableService, resultSetProcessorPrototype.ResultSetProcessorFactory.ResultSetProcessorType);
                var outputViewBase    = outputViewFactory.MakeView(resultSetProcessor, agentInstanceContext);
                createView.AddView(outputViewBase);
                outputView = outputViewBase;
            }

            services.StatementVariableRefService.AddReferences(statementContext.StatementName, Collections.SingletonList(createDesc.VariableName), null);

            return(new EPStatementStartResult(outputView, stopMethod, destroyMethod.Destroy));
        }