public static bool IsPotentialSelfJoin(StatementSpecCompiled spec) { // Include create-context as nested contexts that have pattern-initiated sub-contexts may change filters during execution if (spec.Raw.CreateContextDesc != null && spec.Raw.CreateContextDesc.ContextDetail is ContextNested) { return true; } // if order-by is specified, ans since multiple output rows may produce, ensure dispatch if (spec.Raw.OrderByList.Count > 0) { return true; } foreach (var streamSpec in spec.StreamSpecs) { if (streamSpec is PatternStreamSpecCompiled) { return true; } } // not a self join if (spec.StreamSpecs.Length <= 1 && spec.SubselectNodes.Count == 0) { return false; } // join - determine types joined IList<EventType> filteredTypes = new List<EventType>(); // consider subqueryes var optSubselectTypes = PopulateSubqueryTypes(spec.SubselectNodes); var hasFilterStream = false; foreach (var streamSpec in spec.StreamSpecs) { if (streamSpec is FilterStreamSpecCompiled) { var type = ((FilterStreamSpecCompiled) streamSpec).FilterSpecCompiled.FilterForEventType; filteredTypes.Add(type); hasFilterStream = true; } } if (filteredTypes.Count == 1 && optSubselectTypes.IsEmpty()) { return false; } // pattern-only streams are not self-joins if (!hasFilterStream) { return false; } // is type overlap in filters for (var i = 0; i < filteredTypes.Count; i++) { for (var j = i + 1; j < filteredTypes.Count; j++) { var typeOne = filteredTypes[i]; var typeTwo = filteredTypes[j]; if (typeOne == typeTwo) { return true; } if (typeOne.SuperTypes != null) { foreach (var typeOneSuper in typeOne.SuperTypes) { if (typeOneSuper == typeTwo) { return true; } } } if (typeTwo.SuperTypes != null) { foreach (var typeTwoSuper in typeTwo.SuperTypes) { if (typeOne == typeTwoSuper) { return true; } } } } } // analyze subselect types if (!optSubselectTypes.IsEmpty()) { foreach (var typeOne in filteredTypes) { if (optSubselectTypes.Contains(typeOne)) { return true; } if (typeOne.SuperTypes != null) { foreach (var typeOneSuper in typeOne.SuperTypes) { if (optSubselectTypes.Contains(typeOneSuper)) { return true; } } } } } return false; }
public static StatementSpecCompiledDesc Compile( StatementSpecRaw spec, Compilable compilable, bool isSubquery, bool isOnDemandQuery, Attribute[] annotations, IList<ExprSubselectNode> subselectNodes, IList<ExprTableAccessNode> tableAccessNodes, StatementRawInfo statementRawInfo, StatementCompileTimeServices compileTimeServices) { IList<StreamSpecCompiled> compiledStreams; ISet<string> eventTypeReferences = new HashSet<string>(); IList<StmtClassForgeableFactory> additionalForgeables = new List<StmtClassForgeableFactory>(2); if (!isOnDemandQuery && spec.FireAndForgetSpec != null) { throw new StatementSpecCompileException( "Provided EPL expression is an on-demand query expression (not a continuous query)", compilable.ToEPL()); } // If not using a join and not specifying a data window, make the where-clause, if present, the filter of the stream // if selecting using filter spec, and not subquery in where clause if (spec.StreamSpecs.Count == 1 && spec.StreamSpecs[0] is FilterStreamSpecRaw && spec.StreamSpecs[0].ViewSpecs.Length == 0 && spec.WhereClause != null && spec.OnTriggerDesc == null && !isSubquery && !isOnDemandQuery && (tableAccessNodes == null || tableAccessNodes.IsEmpty())) { bool disqualified; ExprNode whereClause = spec.WhereClause; var visitorX = new ExprNodeSubselectDeclaredDotVisitor(); whereClause.Accept(visitorX); disqualified = visitorX.Subselects.Count > 0 || HintEnum.DISABLE_WHEREEXPR_MOVETO_FILTER.GetHint(annotations) != null; if (!disqualified) { var viewResourceVisitor = new ExprNodeViewResourceVisitor(); whereClause.Accept(viewResourceVisitor); disqualified = viewResourceVisitor.ExprNodes.Count > 0; } var streamSpec = (FilterStreamSpecRaw) spec.StreamSpecs[0]; if (streamSpec.RawFilterSpec.OptionalPropertyEvalSpec != null) { disqualified = true; } if (!disqualified) { spec.WhereClause = null; streamSpec.RawFilterSpec.FilterExpressions.Add(whereClause); } } // compile select-clause var selectClauseCompiled = CompileSelectClause(spec.SelectClauseSpec); // Determine subselects in filter streams, these may need special handling for locking var visitor = new ExprNodeSubselectDeclaredDotVisitor(); try { StatementSpecRawWalkerSubselectAndDeclaredDot.WalkStreamSpecs(spec, visitor); } catch (ExprValidationException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } foreach (var subselectNode in visitor.Subselects) { subselectNode.IsFilterStreamSubselect = true; } // Determine subselects for compilation, and lambda-expression shortcut syntax for named windows visitor.Reset(); GroupByClauseExpressions groupByRollupExpressions; try { StatementSpecRawWalkerSubselectAndDeclaredDot.WalkSubselectAndDeclaredDotExpr(spec, visitor); var expressionCopier = new ExpressionCopier( spec, statementRawInfo.OptionalContextDescriptor, compileTimeServices, visitor); groupByRollupExpressions = GroupByExpressionHelper.GetGroupByRollupExpressions( spec.GroupByExpressions, spec.SelectClauseSpec, spec.HavingClause, spec.OrderByList, expressionCopier); } catch (ExprValidationException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } // Expand match-recognize patterns if (spec.MatchRecognizeSpec != null) { RowRecogExprNode expandedPatternNode; try { var copier = new ExpressionCopier( spec, statementRawInfo.OptionalContextDescriptor, compileTimeServices, visitor); expandedPatternNode = RowRecogPatternExpandUtil.Expand(spec.MatchRecognizeSpec.Pattern, copier); } catch (ExprValidationException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } spec.MatchRecognizeSpec.Pattern = expandedPatternNode; } if (isSubquery && !visitor.Subselects.IsEmpty()) { throw new StatementSpecCompileException( "Invalid nested subquery, subquery-within-subquery is not supported", compilable.ToEPL()); } foreach (var subselectNode in visitor.Subselects) { if (!subselectNodes.Contains(subselectNode)) { subselectNodes.Add(subselectNode); } } // Compile subselects found var subselectNumber = 0; foreach (var subselect in subselectNodes) { var raw = subselect.StatementSpecRaw; var desc = Compile( raw, compilable, true, isOnDemandQuery, annotations, Collections.GetEmptyList<ExprSubselectNode>(), Collections.GetEmptyList<ExprTableAccessNode>(), statementRawInfo, compileTimeServices); additionalForgeables.AddAll(desc.AdditionalForgeables); subselect.SetStatementSpecCompiled(desc.Compiled, subselectNumber); subselectNumber++; } // Set table-access number var tableAccessNumber = 0; foreach (var tableAccess in tableAccessNodes) { tableAccess.TableAccessNumber = tableAccessNumber; tableAccessNumber++; } // compile each stream used try { compiledStreams = new List<StreamSpecCompiled>(spec.StreamSpecs.Count); var streamNum = 0; foreach (var rawSpec in spec.StreamSpecs) { streamNum++; var desc = StreamSpecCompiler.Compile( rawSpec, eventTypeReferences, spec.InsertIntoDesc != null, spec.StreamSpecs.Count > 1, false, spec.OnTriggerDesc != null, rawSpec.OptionalStreamName, streamNum, statementRawInfo, compileTimeServices); additionalForgeables.AddAll(desc.AdditionalForgeables); compiledStreams.Add(desc.StreamSpecCompiled); } } catch (ExprValidationException ex) { if (ex.Message == null) { throw new StatementSpecCompileException( "Unexpected exception compiling statement, please consult the log file and report the exception", ex, compilable.ToEPL()); } throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } catch (EPException ex) { throw new StatementSpecCompileException(ex.Message, ex, compilable.ToEPL()); } catch (Exception ex) { var text = "Unexpected error compiling statement"; Log.Error(text, ex); throw new StatementSpecCompileException( text + ": " + ex.GetType().Name + ":" + ex.Message, ex, compilable.ToEPL()); } var compiled = new StatementSpecCompiled( spec, compiledStreams.ToArray(), selectClauseCompiled, annotations, groupByRollupExpressions, subselectNodes, visitor.DeclaredExpressions, tableAccessNodes); return new StatementSpecCompiledDesc(compiled, additionalForgeables); }