private static StreamJoinAnalysisResult VerifyJoinViews(StatementSpecCompiled statementSpec, NamedWindowMgmtService namedWindowMgmtService, AgentInstanceContext defaultAgentInstanceContext) { var streamSpecs = statementSpec.StreamSpecs; var analysisResult = new StreamJoinAnalysisResult(streamSpecs.Length); if (streamSpecs.Length < 2) { return(analysisResult); } // Determine if any stream has a unidirectional keyword // inspect unidirectional indicator and named window flags var unidirectionalStreamNumber = -1; for (var i = 0; i < statementSpec.StreamSpecs.Length; i++) { var streamSpec = statementSpec.StreamSpecs[i]; if (streamSpec.Options.IsUnidirectional) { analysisResult.SetUnidirectionalInd(i); if (unidirectionalStreamNumber != -1) { throw new ExprValidationException("The unidirectional keyword can only apply to one stream in a join"); } unidirectionalStreamNumber = i; } if (streamSpec.ViewSpecs.Length > 0) { analysisResult.SetHasChildViews(i); } if (streamSpec is NamedWindowConsumerStreamSpec) { var nwSpec = (NamedWindowConsumerStreamSpec)streamSpec; if (nwSpec.OptPropertyEvaluator != null && !streamSpec.Options.IsUnidirectional) { throw new ExprValidationException("Failed to validate named window use in join, contained-event is only allowed for named windows when marked as unidirectional"); } analysisResult.SetNamedWindow(i); var processor = namedWindowMgmtService.GetProcessor(nwSpec.WindowName); string[][] uniqueIndexes = processor.UniqueIndexes; analysisResult.UniqueKeys[i] = uniqueIndexes; if (processor.IsVirtualDataWindow) { analysisResult.ViewExternal[i] = agentInstanceContext => processor.GetProcessorInstance(agentInstanceContext).RootViewInstance.VirtualDataWindow; } } } if ((unidirectionalStreamNumber != -1) && (analysisResult.HasChildViews[unidirectionalStreamNumber])) { throw new ExprValidationException("The unidirectional keyword requires that no views are declared onto the stream"); } analysisResult.UnidirectionalStreamNumber = unidirectionalStreamNumber; // count streams that provide data, excluding streams that poll data (DB and method) var countProviderNonpolling = 0; for (var i = 0; i < statementSpec.StreamSpecs.Length; i++) { var streamSpec = statementSpec.StreamSpecs[i]; if ((streamSpec is MethodStreamSpec) || (streamSpec is DBStatementStreamSpec) || (streamSpec is TableQueryStreamSpec)) { continue; } countProviderNonpolling++; } // if there is only one stream providing data, the analysis is done if (countProviderNonpolling == 1) { return(analysisResult); } // there are multiple driving streams, verify the presence of a view for insert/remove stream // validation of join views works differently for unidirectional as there can be self-joins that don't require a view // see if this is a self-join in which all streams are filters and filter specification is the same. FilterSpecCompiled unidirectionalFilterSpec = null; FilterSpecCompiled lastFilterSpec = null; var pureSelfJoin = true; foreach (var streamSpec in statementSpec.StreamSpecs) { if (!(streamSpec is FilterStreamSpecCompiled)) { pureSelfJoin = false; continue; } var filterSpec = ((FilterStreamSpecCompiled)streamSpec).FilterSpec; if ((lastFilterSpec != null) && (!lastFilterSpec.EqualsTypeAndFilter(filterSpec))) { pureSelfJoin = false; } if (streamSpec.ViewSpecs.Length > 0) { pureSelfJoin = false; } lastFilterSpec = filterSpec; if (streamSpec.Options.IsUnidirectional) { unidirectionalFilterSpec = filterSpec; } } // self-join without views and not unidirectional if ((pureSelfJoin) && (unidirectionalFilterSpec == null)) { analysisResult.IsPureSelfJoin = true; return(analysisResult); } // weed out filter and pattern streams that don't have a view in a join for (var i = 0; i < statementSpec.StreamSpecs.Length; i++) { var streamSpec = statementSpec.StreamSpecs[i]; if (streamSpec.ViewSpecs.Length > 0) { continue; } var name = streamSpec.OptionalStreamName; if ((name == null) && (streamSpec is FilterStreamSpecCompiled)) { name = ((FilterStreamSpecCompiled)streamSpec).FilterSpec.FilterForEventTypeName; } if ((name == null) && (streamSpec is PatternStreamSpecCompiled)) { name = "pattern event stream"; } if (streamSpec.Options.IsUnidirectional) { continue; } // allow a self-join without a child view, in that the filter spec is the same as the unidirection's stream filter if ((unidirectionalFilterSpec != null) && (streamSpec is FilterStreamSpecCompiled) && (((FilterStreamSpecCompiled)streamSpec).FilterSpec.EqualsTypeAndFilter(unidirectionalFilterSpec))) { analysisResult.SetUnidirectionalNonDriving(i); continue; } if ((streamSpec is FilterStreamSpecCompiled) || (streamSpec is PatternStreamSpecCompiled)) { throw new ExprValidationException("Joins require that at least one view is specified for each stream, no view was specified for " + name); } } return(analysisResult); }
protected internal static StreamJoinAnalysisResultCompileTime VerifyJoinViews( StatementSpecCompiled statementSpec, NamedWindowCompileTimeResolver namedWindowCompileTimeResolver) { var streamSpecs = statementSpec.StreamSpecs; var analysisResult = new StreamJoinAnalysisResultCompileTime(streamSpecs.Length); if (streamSpecs.Length < 2) { return analysisResult; } // Determine if any stream has a unidirectional keyword // inspect unidirectional indicator and named window flags for (var i = 0; i < statementSpec.StreamSpecs.Length; i++) { var streamSpec = statementSpec.StreamSpecs[i]; if (streamSpec.Options.IsUnidirectional) { analysisResult.SetUnidirectionalInd(i); } if (streamSpec.ViewSpecs.Length > 0) { analysisResult.SetHasChildViews(i); } if (streamSpec is NamedWindowConsumerStreamSpec) { var nwSpec = (NamedWindowConsumerStreamSpec) streamSpec; if (nwSpec.OptPropertyEvaluator != null && !streamSpec.Options.IsUnidirectional) { throw new ExprValidationException( "Failed to validate named window use in join, Contained-event is only allowed for named windows when marked as unidirectional"); } var nwinfo = nwSpec.NamedWindow; analysisResult.SetNamedWindowsPerStream(i, nwinfo); analysisResult.UniqueKeys[i] = EventTableIndexMetadataUtil.GetUniqueness( nwinfo.IndexMetadata, nwinfo.Uniqueness); } } // non-outer-join: verify unidirectional can be on a single stream only if (statementSpec.StreamSpecs.Length > 1 && analysisResult.IsUnidirectional) { VerifyJoinUnidirectional(analysisResult, statementSpec); } // count streams that provide data, excluding streams that poll data (DB and method) var countProviderNonpolling = 0; for (var i = 0; i < statementSpec.StreamSpecs.Length; i++) { var streamSpec = statementSpec.StreamSpecs[i]; if (streamSpec is MethodStreamSpec || streamSpec is DBStatementStreamSpec || streamSpec is TableQueryStreamSpec) { continue; } countProviderNonpolling++; } // if there is only one stream providing data, the analysis is done if (countProviderNonpolling == 1) { return analysisResult; } // there are multiple driving streams, verify the presence of a view for insert/remove stream // validation of join views works differently for unidirectional as there can be self-joins that don't require a view // see if this is a self-join in which all streams are filters and filter specification is the same. FilterSpecCompiled unidirectionalFilterSpec = null; FilterSpecCompiled lastFilterSpec = null; var pureSelfJoin = true; foreach (var streamSpec in statementSpec.StreamSpecs) { if (!(streamSpec is FilterStreamSpecCompiled)) { pureSelfJoin = false; continue; } var filterSpec = ((FilterStreamSpecCompiled) streamSpec).FilterSpecCompiled; if (lastFilterSpec != null && !lastFilterSpec.EqualsTypeAndFilter(filterSpec)) { pureSelfJoin = false; } if (streamSpec.ViewSpecs.Length > 0) { pureSelfJoin = false; } lastFilterSpec = filterSpec; if (streamSpec.Options.IsUnidirectional) { unidirectionalFilterSpec = filterSpec; } } // self-join without views and not unidirectional if (pureSelfJoin && unidirectionalFilterSpec == null) { analysisResult.IsPureSelfJoin = true; return analysisResult; } // weed out filter and pattern streams that don't have a view in a join for (var i = 0; i < statementSpec.StreamSpecs.Length; i++) { var streamSpec = statementSpec.StreamSpecs[i]; if (streamSpec.ViewSpecs.Length > 0) { continue; } var name = streamSpec.OptionalStreamName; if (name == null && streamSpec is FilterStreamSpecCompiled) { name = ((FilterStreamSpecCompiled) streamSpec).FilterSpecCompiled.FilterForEventTypeName; } if (name == null && streamSpec is PatternStreamSpecCompiled) { name = "pattern event stream"; } if (streamSpec.Options.IsUnidirectional) { continue; } // allow a self-join without a child view, in that the filter spec is the same as the unidirection's stream filter if (unidirectionalFilterSpec != null && streamSpec is FilterStreamSpecCompiled && ((FilterStreamSpecCompiled) streamSpec).FilterSpecCompiled.EqualsTypeAndFilter( unidirectionalFilterSpec)) { analysisResult.SetUnidirectionalNonDriving(i); continue; } if (streamSpec is FilterStreamSpecCompiled || streamSpec is PatternStreamSpecCompiled) { throw new ExprValidationException( "Joins require that at least one view is specified for each stream, no view was specified for " + name); } } return analysisResult; }