// <summary> // Determines whether an applyNode can be rewritten into a projection with a scalar subquery. // It can be done if all of the following conditions hold: // 1. The right child or the apply has only one output // 2. The right child of the apply produces at most one row // 3. The right child of the apply produces at least one row, or the Apply operator in question is an OuterApply // </summary> private static bool CanRewriteApply(Node rightChild, ExtendedNodeInfo applyRightChildNodeInfo, OpType applyKind) { //Check whether it produces only one definition if (applyRightChildNodeInfo.Definitions.Count != 1) { return(false); } //Check whether it produces at most one row if (applyRightChildNodeInfo.MaxRows != RowCount.One) { return(false); } //For cross apply it must also return exactly one row if (applyKind == OpType.CrossApply && (applyRightChildNodeInfo.MinRows != RowCount.One)) { return(false); } //Dev10 #488632: Make sure the right child not only declares to produce only one definition, // but has exactly one output. For example, ScanTableOp really outputs all the columns from the table, // but in its ExtendedNodeInfo.Definitions only these that are referenced are shown. // This is to allow for projection pruning of the unreferenced columns. if (OutputCountVisitor.CountOutputs(rightChild) != 1) { return(false); } return(true); }
// <summary> // Calculates the number of output columns for the subtree // rooted at the given node // </summary> internal static int CountOutputs(Node node) { var visitor = new OutputCountVisitor(); return(visitor.VisitNode(node)); }