public void TestGetNavigableStreams() { _queryGraph = new QueryGraph(5, null, false); _queryGraph.AddStrictEquals(3, "p3", null, 4, "p4", null); _queryGraph.AddStrictEquals(2, "p2", null, 3, "p3", null); _queryGraph.AddStrictEquals(1, "p1", null, 2, "p2", null); Assert.AreEqual(0, _queryGraph.GetNavigableStreams(0).Count); EPAssertionUtil.AssertEqualsAnyOrder(new int[] { 2 }, _queryGraph.GetNavigableStreams(1)); EPAssertionUtil.AssertEqualsAnyOrder(new int[] { 1, 3 }, _queryGraph.GetNavigableStreams(2)); EPAssertionUtil.AssertEqualsAnyOrder(new int[] { 2, 4 }, _queryGraph.GetNavigableStreams(3)); EPAssertionUtil.AssertEqualsAnyOrder(new int[] { 3 }, _queryGraph.GetNavigableStreams(4)); }
/// <summary> /// Recusivly builds a substream-per-stream ordered tree graph using the /// join information supplied for outer joins and from the query graph (where clause). /// <para />Required streams are considered first and their lookup is placed first in the list /// to gain performance. /// </summary> /// <param name="streamNum">is the root stream number that supplies the incoming event to build the tree for</param> /// <param name="queryGraph">contains where-clause stream relationship info</param> /// <param name="completedStreams">is a temporary holder for streams already considered</param> /// <param name="substreamsPerStream">is the ordered, tree-like structure to be filled</param> /// <param name="streamCallStack">the query plan call stack of streams available via cursor</param> /// <param name="dependencyGraph">dependencies between historical streams</param> /// <throws>ExprValidationException if the query planning failed</throws> internal static void RecursiveBuildInnerJoin( int streamNum, Stack <int> streamCallStack, QueryGraph queryGraph, ISet <int> completedStreams, IDictionary <int, int[]> substreamsPerStream, DependencyGraph dependencyGraph) { // add this stream to the set of completed streams completedStreams.Add(streamNum); // check if the dependencies have been satisfied if (dependencyGraph.HasDependency(streamNum)) { var dependencies = dependencyGraph.GetDependenciesForStream(streamNum); foreach (var dependentStream in dependencies) { if (!streamCallStack.Contains(dependentStream)) { throw new ExprValidationException("Historical stream " + streamNum + " parameter dependency originating in stream " + dependentStream + " cannot or may not be satisfied by the join"); } } } // Determine the streams we can navigate to from this stream var navigableStreams = queryGraph.GetNavigableStreams(streamNum); // remove streams with a dependency on other streams not yet processed var navigableStreamArr = navigableStreams.ToArray(); foreach (int navigableStream in navigableStreamArr) { if (dependencyGraph.HasUnsatisfiedDependency(navigableStream, completedStreams)) { navigableStreams.Remove(navigableStream); } } // remove those already done navigableStreams.RemoveAll(completedStreams); // if we are a leaf node, we are done if (navigableStreams.IsEmpty()) { substreamsPerStream.Put(streamNum, new int[0]); return; } // First the outer (required) streams to this stream, then the inner (optional) streams var substreams = new int[navigableStreams.Count]; substreamsPerStream.Put(streamNum, substreams); var count = 0; foreach (int stream in navigableStreams) { substreams[count++] = stream; completedStreams.Add(stream); } foreach (int stream in navigableStreams) { streamCallStack.Push(stream); RecursiveBuildInnerJoin(stream, streamCallStack, queryGraph, completedStreams, substreamsPerStream, dependencyGraph); streamCallStack.Pop(); } }
/// <summary> /// Recusivly builds a substream-per-stream ordered tree graph using the /// join information supplied for outer joins and from the query graph (where clause). /// <para />Required streams are considered first and their lookup is placed first in the list /// to gain performance. /// </summary> /// <param name="streamNum">is the root stream number that supplies the incoming event to build the tree for</param> /// <param name="streamCallStack">the query plan call stack of streams available via cursor</param> /// <param name="queryGraph">contains where-clause stream relationship info</param> /// <param name="outerInnerGraph">contains the outer join stream relationship info</param> /// <param name="innerJoinGraph">The inner join graph.</param> /// <param name="completedStreams">is a temporary holder for streams already considered</param> /// <param name="substreamsPerStream">is the ordered, tree-like structure to be filled</param> /// <param name="requiredPerStream">indicates which streams are required and which are optional</param> /// <param name="dependencyGraph">dependencies between historical streams</param> /// <exception cref="ExprValidationException">Historical stream + streamNum + parameter dependency originating in stream + dependentStream + cannot or may not be satisfied by the join</exception> /// <throws>ExprValidationException if the query planning failed</throws> internal static void RecursiveBuild( int streamNum, Stack <int> streamCallStack, QueryGraph queryGraph, OuterInnerDirectionalGraph outerInnerGraph, InnerJoinGraph innerJoinGraph, ISet <int> completedStreams, IDictionary <int, int[]> substreamsPerStream, bool[] requiredPerStream, DependencyGraph dependencyGraph) { // add this stream to the set of completed streams completedStreams.Add(streamNum); // check if the dependencies have been satisfied if (dependencyGraph.HasDependency(streamNum)) { var dependencies = dependencyGraph.GetDependenciesForStream(streamNum); foreach (var dependentStream in dependencies) { if (!streamCallStack.Contains(dependentStream)) { throw new ExprValidationException("Historical stream " + streamNum + " parameter dependency originating in stream " + dependentStream + " cannot or may not be satisfied by the join"); } } } // Determine the streams we can navigate to from this stream var navigableStreams = queryGraph.GetNavigableStreams(streamNum); // add unqualified navigable streams (since on-expressions in outer joins are optional) var unqualifiedNavigable = outerInnerGraph.UnqualifiedNavigableStreams.Get(streamNum); if (unqualifiedNavigable != null) { navigableStreams.AddAll(unqualifiedNavigable); } // remove those already done navigableStreams.RemoveAll(completedStreams); // Which streams are inner streams to this stream (optional), which ones are outer to the stream (required) var requiredStreams = GetOuterStreams(streamNum, navigableStreams, outerInnerGraph); // Add inner joins, if any, unless already completed for this stream innerJoinGraph.AddRequiredStreams(streamNum, requiredStreams, completedStreams); var optionalStreams = GetInnerStreams(streamNum, navigableStreams, outerInnerGraph, innerJoinGraph, completedStreams); // Remove from the required streams the optional streams which places 'full' joined streams // into the optional stream category requiredStreams.RemoveAll(optionalStreams); // if we are a leaf node, we are done if (navigableStreams.IsEmpty()) { substreamsPerStream.Put(streamNum, new int[0]); return; } // First the outer (required) streams to this stream, then the inner (optional) streams var substreams = new int[requiredStreams.Count + optionalStreams.Count]; substreamsPerStream.Put(streamNum, substreams); var count = 0; foreach (int stream in requiredStreams) { substreams[count++] = stream; requiredPerStream[stream] = true; } foreach (int stream in optionalStreams) { substreams[count++] = stream; } // next we look at all the required streams and add their dependent streams foreach (int stream in requiredStreams) { completedStreams.Add(stream); } foreach (int stream in requiredStreams) { streamCallStack.Push(stream); RecursiveBuild(stream, streamCallStack, queryGraph, outerInnerGraph, innerJoinGraph, completedStreams, substreamsPerStream, requiredPerStream, dependencyGraph); streamCallStack.Pop(); } // look at all the optional streams and add their dependent streams foreach (int stream in optionalStreams) { streamCallStack.Push(stream); RecursiveBuild(stream, streamCallStack, queryGraph, outerInnerGraph, innerJoinGraph, completedStreams, substreamsPerStream, requiredPerStream, dependencyGraph); streamCallStack.Pop(); } }