diff --git a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs index 011dc965..6ce77050 100644 --- a/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs +++ b/MarkMpn.Sql4Cds.Engine/ExecutionPlanBuilder.cs @@ -285,20 +285,55 @@ private void ConvertStatement(TSqlStatement statement, ExecutionPlanOptimizer op JoinType = QualifiedJoinType.Inner, }; + if (cteValidator.RecursiveQueries.Count > 1) + { + // Combine the results of each recursive query with a concat node + var concat = new ConcatenateNode(); + recurseLoop.RightSource = concat; + + foreach (var qry in cteValidator.RecursiveQueries) + concat.Sources.Add(ConvertRecursiveCTEQuery(qry)); + } + else + { + recurseLoop.RightSource = ConvertRecursiveCTEQuery(cteValidator.RecursiveQueries[0]); + } + // Ensure we don't get stuck in an infinite loop - var assert = new AssertNode + var maxRecursion = stmtWithCtes.OptimizerHints + .OfType() + .Where(hint => hint.HintKind == OptimizerHintKind.MaxRecursion) + .FirstOrDefault() + ?.Value + ?.Value + ?? "100"; + + if (!Int32.TryParse(maxRecursion, out var max) || max < 0) + throw new NotSupportedQueryFragmentException("Invalid MAXRECURSION hint", stmtWithCtes.OptimizerHints + .OfType() + .Where(hint => hint.HintKind == OptimizerHintKind.MaxRecursion) + .First()); + + if (max > 0) { - Source = recurseLoop, - Assertion = e => + var assert = new AssertNode { - var depth = e.GetAttributeValue(incrementedDepthField); - return depth.Value < 100; - }, - ErrorMessage = "Recursion depth exceeded" - }; + Source = recurseLoop, + Assertion = e => + { + var depth = e.GetAttributeValue(incrementedDepthField); + return depth.Value < max; + }, + ErrorMessage = "Recursion depth exceeded" + }; - // Combine the recursion results into the main results - recurseConcat.Sources.Add(assert); + // Combine the recursion results into the main results + recurseConcat.Sources.Add(assert); + } + else + { + recurseConcat.Sources.Add(recurseLoop); + } // TODO: Update the sources for each field in the concat node recurseConcat.ColumnSet.Last().SourceColumns.Add(incrementedDepthField);