/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.epl.view; import com.espertech.esper.client.EventType; import com.espertech.esper.client.annotation.HintEnum; import com.espertech.esper.core.service.InternalEventRouter; import com.espertech.esper.core.service.StatementContext; import com.espertech.esper.core.service.StatementVariableRef; import com.espertech.esper.epl.core.ResultSetProcessorHelperFactory; import com.espertech.esper.epl.core.ResultSetProcessorType; import com.espertech.esper.epl.expression.core.ExprValidationException; import com.espertech.esper.epl.spec.*; import com.espertech.esper.epl.table.mgmt.TableMetadata; import com.espertech.esper.epl.table.mgmt.TableService; import com.espertech.esper.epl.util.EPLValidationUtil; /** * Factory for factories for output processing views. */ public class OutputProcessViewFactoryFactory { public static OutputProcessViewFactory make(StatementSpecCompiled statementSpec, InternalEventRouter internalEventRouter, StatementContext statementContext, EventType resultEventType, OutputProcessViewCallback optionalOutputProcessViewCallback, TableService tableService, ResultSetProcessorType resultSetProcessorType, ResultSetProcessorHelperFactory resultSetProcessorHelperFactory, StatementVariableRef statementVariableRef) throws ExprValidationException { // determine direct-callback if (optionalOutputProcessViewCallback != null) { return new OutputProcessViewFactoryCallback(optionalOutputProcessViewCallback); } // determine routing boolean isRouted = false; boolean routeToFront = false; if (statementSpec.getInsertIntoDesc() != null) { isRouted = true; routeToFront = statementContext.getNamedWindowMgmtService().isNamedWindow(statementSpec.getInsertIntoDesc().getEventTypeName()); } OutputStrategyPostProcessFactory outputStrategyPostProcessFactory = null; if ((statementSpec.getInsertIntoDesc() != null) || (statementSpec.getSelectStreamSelectorEnum() == SelectClauseStreamSelectorEnum.RSTREAM_ONLY)) { SelectClauseStreamSelectorEnum insertIntoStreamSelector = null; String tableName = null; if (statementSpec.getInsertIntoDesc() != null) { insertIntoStreamSelector = statementSpec.getInsertIntoDesc().getStreamSelector(); TableMetadata tableMetadata = tableService.getTableMetadata(statementSpec.getInsertIntoDesc().getEventTypeName()); if (tableMetadata != null) { tableName = tableMetadata.getTableName(); EPLValidationUtil.validateContextName(true, tableName, tableMetadata.getContextName(), statementSpec.getOptionalContextName(), true); statementVariableRef.addReferences(statementContext.getStatementName(), tableMetadata.getTableName()); } } outputStrategyPostProcessFactory = new OutputStrategyPostProcessFactory(isRouted, insertIntoStreamSelector, statementSpec.getSelectStreamSelectorEnum(), internalEventRouter, statementContext.getEpStatementHandle(), routeToFront, tableService, tableName); } // Do we need to enforce an output policy? int streamCount = statementSpec.getStreamSpecs().length; OutputLimitSpec outputLimitSpec = statementSpec.getOutputLimitSpec(); boolean isDistinct = statementSpec.getSelectClauseSpec().isDistinct(); boolean isGrouped = statementSpec.getGroupByExpressions() != null && statementSpec.getGroupByExpressions().getGroupByNodes().length > 0; OutputProcessViewFactory outputProcessViewFactory; if (outputLimitSpec == null) { if (!isDistinct) { outputProcessViewFactory = new OutputProcessViewDirectFactory(statementContext, outputStrategyPostProcessFactory, resultSetProcessorHelperFactory); } else { outputProcessViewFactory = new OutputProcessViewDirectDistinctOrAfterFactory(statementContext, outputStrategyPostProcessFactory, resultSetProcessorHelperFactory, isDistinct, null, null, resultEventType); } } else if (outputLimitSpec.getRateType() == OutputLimitRateType.AFTER) { outputProcessViewFactory = new OutputProcessViewDirectDistinctOrAfterFactory(statementContext, outputStrategyPostProcessFactory, resultSetProcessorHelperFactory, isDistinct, outputLimitSpec.getAfterTimePeriodExpr(), outputLimitSpec.getAfterNumberOfEvents(), resultEventType); } else { try { boolean isWithHavingClause = statementSpec.getHavingExprRootNode() != null; boolean isStartConditionOnCreation = hasOnlyTables(statementSpec.getStreamSpecs()); OutputConditionFactory outputConditionFactory = OutputConditionFactoryFactory.createCondition(outputLimitSpec, statementContext, isGrouped, isWithHavingClause, isStartConditionOnCreation, resultSetProcessorHelperFactory); boolean hasOrderBy = statementSpec.getOrderByList() != null && statementSpec.getOrderByList().length > 0; OutputProcessViewConditionFactory.ConditionType conditionType; boolean hasAfter = outputLimitSpec.getAfterNumberOfEvents() != null || outputLimitSpec.getAfterTimePeriodExpr() != null; boolean isUnaggregatedUngrouped = resultSetProcessorType == ResultSetProcessorType.HANDTHROUGH || resultSetProcessorType == ResultSetProcessorType.UNAGGREGATED_UNGROUPED; // hint checking with order-by boolean hasOptHint = HintEnum.ENABLE_OUTPUTLIMIT_OPT.getHint(statementSpec.getAnnotations()) != null; if (hasOptHint && hasOrderBy) { throw new ExprValidationException("The " + HintEnum.ENABLE_OUTPUTLIMIT_OPT + " hint is not supported with order-by"); } if (outputLimitSpec.getDisplayLimit() == OutputLimitLimitType.SNAPSHOT) { conditionType = OutputProcessViewConditionFactory.ConditionType.SNAPSHOT; } else if (outputLimitSpec.getDisplayLimit() == OutputLimitLimitType.FIRST && statementSpec.getGroupByExpressions() == null) { // For FIRST without groups we are using a special logic that integrates the first-flag, in order to still conveniently use all sorts of output conditions. // FIRST with group-by is handled by setting the output condition to null (OutputConditionNull) and letting the ResultSetProcessor handle first-per-group. // Without having-clause there is no required order of processing, thus also use regular policy. conditionType = OutputProcessViewConditionFactory.ConditionType.POLICY_FIRST; } else if (isUnaggregatedUngrouped && outputLimitSpec.getDisplayLimit() == OutputLimitLimitType.LAST) { conditionType = OutputProcessViewConditionFactory.ConditionType.POLICY_LASTALL_UNORDERED; } else if (hasOptHint && outputLimitSpec.getDisplayLimit() == OutputLimitLimitType.ALL && !hasOrderBy) { conditionType = OutputProcessViewConditionFactory.ConditionType.POLICY_LASTALL_UNORDERED; } else if (hasOptHint && outputLimitSpec.getDisplayLimit() == OutputLimitLimitType.LAST && !hasOrderBy) { conditionType = OutputProcessViewConditionFactory.ConditionType.POLICY_LASTALL_UNORDERED; } else { conditionType = OutputProcessViewConditionFactory.ConditionType.POLICY_NONFIRST; } SelectClauseStreamSelectorEnum selectClauseStreamSelectorEnum = statementSpec.getSelectStreamSelectorEnum(); boolean terminable = outputLimitSpec.getRateType() == OutputLimitRateType.TERM || outputLimitSpec.isAndAfterTerminate(); outputProcessViewFactory = new OutputProcessViewConditionFactory(statementContext, outputStrategyPostProcessFactory, isDistinct, outputLimitSpec.getAfterTimePeriodExpr(), outputLimitSpec.getAfterNumberOfEvents(), resultEventType, outputConditionFactory, streamCount, conditionType, outputLimitSpec.getDisplayLimit(), terminable, hasAfter, isUnaggregatedUngrouped, selectClauseStreamSelectorEnum, resultSetProcessorHelperFactory); } catch (Exception ex) { throw new ExprValidationException("Error in the output rate limiting clause: " + ex.getMessage(), ex); } } return outputProcessViewFactory; } private static boolean hasOnlyTables(StreamSpecCompiled[] streamSpecs) { if (streamSpecs.length == 0) { return false; } for (StreamSpecCompiled streamSpec : streamSpecs) { if (!(streamSpec instanceof TableQueryStreamSpec)) { return false; } } return true; } }