/// <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> protected internal static void RecursiveBuildInnerJoin( int streamNum, Stack<int> streamCallStack, QueryGraphForge 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 (var stream in navigableStreams) { substreams[count++] = stream; completedStreams.Add(stream); } foreach (var 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="queryGraph">contains where-clause stream relationship info</param> /// <param name="outerInnerGraph">contains the outer join 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="requiredPerStream">indicates which streams are required and which are optional</param> /// <param name="streamCallStack">the query plan call stack of streams available via cursor</param> /// <param name="dependencyGraph">dependencies between historical streams</param> /// <param name="innerJoinGraph">inner join graph</param> /// <throws>ExprValidationException if the query planning failed</throws> public static void RecursiveBuild( int streamNum, Stack<int> streamCallStack, QueryGraphForge 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 (var stream in requiredStreams) { substreams[count++] = stream; requiredPerStream[stream] = true; } foreach (var stream in optionalStreams) { substreams[count++] = stream; } // next we look at all the required streams and add their dependent streams foreach (var stream in requiredStreams) { completedStreams.Add(stream); } foreach (var 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 (var stream in optionalStreams) { streamCallStack.Push(stream); RecursiveBuild( stream, streamCallStack, queryGraph, outerInnerGraph, innerJoinGraph, completedStreams, substreamsPerStream, requiredPerStream, dependencyGraph); streamCallStack.Pop(); } }