// <summary> // Converts a Apply(X,Y) => Project(X, Y1), where Y1 is a scalar subquery version of Y // The transformation is valid only if all of the following conditions hold: // 1. Y produces only one output // 2. Y produces at most one row // 3. Y produces at least one row, or the Apply operator in question is an OuterApply // </summary> // <param name="context"> Rule processing context </param> // <param name="applyNode"> The ApplyOp subtree </param> // <param name="newNode"> transformed subtree </param> // <returns> the transformation status </returns> private static bool ProcessApplyIntoScalarSubquery(RuleProcessingContext context, Node applyNode, out Node newNode) { var command = context.Command; var applyRightChildNodeInfo = command.GetExtendedNodeInfo(applyNode.Child1); var applyKind = applyNode.Op.OpType; if (!CanRewriteApply(applyNode.Child1, applyRightChildNodeInfo, applyKind)) { newNode = applyNode; return(false); } // Create the project node over the original input with element over the apply as new projected var var applyLeftChildNodeInfo = command.GetExtendedNodeInfo(applyNode.Child0); var oldVar = applyRightChildNodeInfo.Definitions.First; // Project all the outputs from the left child var projectOpOutputs = command.CreateVarVec(applyLeftChildNodeInfo.Definitions); // // Remap the var defining tree to get it into a consistent state // and then remove all references to oldVar from it to avoid them being wrongly remapped to newVar // in subsequent remappings. // var trc = (TransformationRulesContext)context; trc.RemapSubtree(applyNode.Child1); VarDefinitionRemapper.RemapSubtree(applyNode.Child1, command, oldVar); var elementNode = command.CreateNode(command.CreateElementOp(oldVar.Type), applyNode.Child1); Var newVar; var varDefListNode = command.CreateVarDefListNode(elementNode, out newVar); projectOpOutputs.Set(newVar); newNode = command.CreateNode( command.CreateProjectOp(projectOpOutputs), applyNode.Child0, varDefListNode); // Add the var mapping from oldVar to newVar trc.AddVarMapping(oldVar, newVar); return(true); }
// <summary> // Public entry point. // Remaps the subtree rooted at the given tree // </summary> internal static void RemapSubtree(Node root, Command command, Var oldVar) { var remapper = new VarDefinitionRemapper(oldVar, command); remapper.RemapSubtree(root); }