}
}
}
EventType[] outerEventTypes;
StreamTypeService subselectTypeService;
// Use the override provided by the subselect if applicable
if (subselect.getFilterSubqueryStreamTypes() != null) {
subselectTypeService = subselect.getFilterSubqueryStreamTypes();
outerEventTypes = new EventType[subselectTypeService.getEventTypes().length - 1];
System.arraycopy(subselectTypeService.getEventTypes(), 1, outerEventTypes, 0, subselectTypeService.getEventTypes().length - 1);
}
else {
// Streams event types are the original stream types with the stream zero the subselect stream
LinkedHashMap<String, Pair<EventType, String>> namesAndTypes = new LinkedHashMap<String, Pair<EventType, String>>();
namesAndTypes.put(subexpressionStreamName, new Pair<EventType, String>(eventType, subselecteventTypeName));
for (int i = 0; i < outerEventTypesSelect.length; i++)
{
Pair<EventType, String> pair = new Pair<EventType, String>(outerEventTypesSelect[i], outerEventTypeNamees[i]);
namesAndTypes.put(outerStreamNames[i], pair);
}
subselectTypeService = new StreamTypeServiceImpl(namesAndTypes, services.getEngineURI(), true, true);
outerEventTypes = outerEventTypesSelect;
}
ViewResourceDelegateUnverified viewResourceDelegateSubselect = new ViewResourceDelegateUnverified();
// Validate select expression
SelectClauseSpecCompiled selectClauseSpec = subselect.getStatementSpecCompiled().getSelectClauseSpec();
AggregationServiceFactoryDesc aggregationServiceFactoryDesc = null;
List<ExprNode> selectExpressions = new ArrayList<ExprNode>();
List<String> assignedNames = new ArrayList<String>();
boolean isWildcard = false;
boolean isStreamWildcard = false;
if (selectClauseSpec.getSelectExprList().length > 0)
{
List<ExprAggregateNode> aggExprNodes = new LinkedList<ExprAggregateNode>();
ExprEvaluatorContextStatement evaluatorContextStmt = new ExprEvaluatorContextStatement(statementContext);
ExprValidationContext validationContext = new ExprValidationContext(subselectTypeService, statementContext.getMethodResolutionService(), viewResourceDelegateSubselect, statementContext.getSchedulingService(), statementContext.getVariableService(), evaluatorContextStmt, statementContext.getEventAdapterService(), statementContext.getStatementName(), statementContext.getStatementId(), statementContext.getAnnotations(), statementContext.getContextDescriptor());
for (int i = 0; i < selectClauseSpec.getSelectExprList().length; i++) {
SelectClauseElementCompiled element = selectClauseSpec.getSelectExprList()[i];
if (element instanceof SelectClauseExprCompiledSpec)
{
// validate
SelectClauseExprCompiledSpec compiled = (SelectClauseExprCompiledSpec) element;
ExprNode selectExpression = compiled.getSelectExpression();
selectExpression = ExprNodeUtility.getValidatedSubtree(selectExpression, validationContext);
selectExpressions.add(selectExpression);
assignedNames.add(compiled.getAssignedName());
// handle aggregation
ExprAggregateNodeUtil.getAggregatesBottomUp(selectExpression, aggExprNodes);
if (aggExprNodes.size() > 0)
{
// This stream (stream 0) properties must either all be under aggregation, or all not be.
List<Pair<Integer, String>> propertiesNotAggregated = ExprNodeUtility.getExpressionProperties(selectExpression, false);
for (Pair<Integer, String> pair : propertiesNotAggregated)
{
if (pair.getFirst() == 0)
{
throw new ExprValidationException("Subselect properties must all be within aggregation functions");
}
}
}
}
else if (element instanceof SelectClauseElementWildcard) {
isWildcard = true;
}
else if (element instanceof SelectClauseStreamCompiledSpec) {
isStreamWildcard = true;
}
} // end of for loop
if (!selectExpressions.isEmpty()) {
subselect.setSelectClause(selectExpressions.toArray(new ExprNode[selectExpressions.size()]));
subselect.setSelectAsNames(assignedNames.toArray(new String[assignedNames.size()]));
if (isWildcard || isStreamWildcard) {
throw new ExprValidationException("Subquery multi-column select does not allow wildcard or stream wildcard when selecting multiple columns.");
}
if (selectExpressions.size() > 1 && !subselect.isAllowMultiColumnSelect()) {
throw new ExprValidationException("Subquery multi-column select is not allowed in this context.");
}
if ((selectExpressions.size() > 1 && aggExprNodes.size() > 0)) {
// all properties must be aggregated
if (!ExprNodeUtility.getNonAggregatedProps(subselectTypeService.getEventTypes(), selectExpressions, contextPropertyRegistry).isEmpty()) {
throw new ExprValidationException("Subquery with multi-column select requires that either all or none of the selected columns are under aggregation.");
}
}
}
if (aggExprNodes.size() > 0)
{
List<ExprAggregateNode> havingAgg = Collections.emptyList();
List<ExprAggregateNode> orderByAgg = Collections.emptyList();
aggregationServiceFactoryDesc = AggregationServiceFactoryFactory.getService(aggExprNodes, havingAgg, orderByAgg, false, evaluatorContextStmt, annotations, statementContext.getVariableService(), false, statementSpec.getFilterRootNode(), statementSpec.getHavingExprRootNode(), statementContext.getAggregationServiceFactoryService(), subselectTypeService.getEventTypes());
// Other stream properties, if there is aggregation, cannot be under aggregation.
for (ExprAggregateNode aggNode : aggExprNodes)
{
List<Pair<Integer, String>> propertiesNodesAggregated = ExprNodeUtility.getExpressionProperties(aggNode, true);
for (Pair<Integer, String> pair : propertiesNodesAggregated)
{
if (pair.getFirst() != 0)
{
throw new ExprValidationException("Subselect aggregation functions cannot aggregate across correlated properties");
}
}
}
}
}
// no aggregation functions allowed in filter
if (statementSpec.getFilterRootNode() != null)
{
List<ExprAggregateNode> aggExprNodesFilter = new LinkedList<ExprAggregateNode>();
ExprAggregateNodeUtil.getAggregatesBottomUp(statementSpec.getFilterRootNode(), aggExprNodesFilter);
if (aggExprNodesFilter.size() > 0)
{
throw new ExprValidationException("Aggregation functions are not supported within subquery filters, consider using insert-into instead");
}
}
// Validate filter expression, if there is one
ExprNode filterExpr = statementSpec.getFilterRootNode();
boolean correlatedSubquery = false;
if (filterExpr != null)
{
ExprEvaluatorContextStatement evaluatorContextStmt = new ExprEvaluatorContextStatement(statementContext);
ExprValidationContext validationContext = new ExprValidationContext(subselectTypeService, statementContext.getMethodResolutionService(), viewResourceDelegateSubselect, statementContext.getSchedulingService(), statementContext.getVariableService(), evaluatorContextStmt, statementContext.getEventAdapterService(), statementContext.getStatementName(), statementContext.getStatementId(), statementContext.getAnnotations(), statementContext.getContextDescriptor());
filterExpr = ExprNodeUtility.getValidatedSubtree(filterExpr, validationContext);
if (JavaClassHelper.getBoxedType(filterExpr.getExprEvaluator().getType()) != Boolean.class)
{
throw new ExprValidationException("Subselect filter expression must return a boolean value");
}
// check the presence of a correlated filter, not allowed with aggregation
ExprNodeIdentifierVisitor visitor = new ExprNodeIdentifierVisitor(true);
filterExpr.accept(visitor);
List<Pair<Integer, String>> propertiesNodes = visitor.getExprProperties();
for (Pair<Integer, String> pair : propertiesNodes)
{
if (pair.getFirst() != 0)
{
correlatedSubquery = true;
break;
}
}
}
ViewResourceDelegateVerified viewResourceDelegateVerified = EPStatementStartMethodHelperViewResources.verifyPreviousAndPriorRequirements(new ViewFactoryChain[]{viewFactoryChain}, viewResourceDelegateSubselect);
List<ExprPriorNode> priorNodes = viewResourceDelegateVerified.getPerStream()[0].getPriorRequestsAsList();
List<ExprPreviousNode> previousNodes = viewResourceDelegateVerified.getPerStream()[0].getPreviousRequests();
// Set the aggregated flag
// This must occur here as some analysis of return type depends on aggregated or not.
subselect.setAggregatedSubquery(aggregationServiceFactoryDesc != null);
// Set the filter.
ExprEvaluator filterExprEval = (filterExpr == null) ? null : filterExpr.getExprEvaluator();
ExprEvaluator assignedFilterExpr = aggregationServiceFactoryDesc != null ? null : filterExprEval;
subselect.setFilterExpr(assignedFilterExpr);
// validation for correlated subqueries against named windows contained-event syntax
if ((filterStreamSpec instanceof NamedWindowConsumerStreamSpec && correlatedSubquery)) {
NamedWindowConsumerStreamSpec namedSpec = (NamedWindowConsumerStreamSpec) filterStreamSpec;
if (namedSpec.getOptPropertyEvaluator() != null) {
throw new ExprValidationException("Failed to validate named window use in subquery, contained-event is only allowed for named windows when not correlated");
}
}
// Determine strategy factories
//
// handle named window index share first
boolean disableIndexShare = HintEnum.DISABLE_WINDOW_SUBQUERY_INDEXSHARE.getHint(annotations) != null;
if ((filterStreamSpec instanceof NamedWindowConsumerStreamSpec) && (!disableIndexShare)) {
NamedWindowConsumerStreamSpec namedSpec = (NamedWindowConsumerStreamSpec) filterStreamSpec;
if (namedSpec.getFilterExpressions().isEmpty()) {
NamedWindowProcessor processor = services.getNamedWindowService().getProcessor(namedSpec.getWindowName());
if (processor == null) {
throw new ExprValidationException("A named window by name '" + namedSpec.getWindowName() + "' does not exist");
}
if (processor.isEnableSubqueryIndexShare()) {
if (queryPlanLogging && queryPlanLog.isInfoEnabled()) {
queryPlanLog.info("prefering shared index");
}
boolean fullTableScan = HintEnum.SET_NOINDEX.getHint(annotations) != null;
SubordPropPlan joinedPropPlan = QueryPlanIndexBuilder.getJoinProps(filterExpr, outerEventTypes.length, subselectTypeService.getEventTypes());
NamedWindowProcessorInstance processorInstanceSubq = processor.getProcessorInstance(null);
SubordTableLookupStrategy namedWindowSubqueryLookup = processorInstanceSubq.getRootViewInstance().getAddSubqueryLookupStrategy(statementContext.getStatementName(), statementContext.getStatementId(), statementContext.getAnnotations(), outerEventTypesSelect, joinedPropPlan, fullTableScan, subqueryNum, indexHint);
stopCallbacks.add(new NamedWindowSubqueryStopCallback(processorInstanceSubq, namedWindowSubqueryLookup));
SubSelectStrategyFactory factory = new SubSelectStrategyFactoryNamedWinIndexShare(namedWindowSubqueryLookup, filterExprEval, aggregationServiceFactoryDesc);
SubSelectStrategyFactoryDesc factoryDesc = new SubSelectStrategyFactoryDesc(subSelectActivation, factory, aggregationServiceFactoryDesc, priorNodes, previousNodes);