/// <summary> /// Convert a SingleStreamNestOp into a massive UnionAllOp /// </summary> /// <param name="nestOp"></param> /// <param name="nestNode"></param> /// <param name="drivingNodeVars"></param> /// <param name="discriminatorVarList"></param> /// <param name="discriminatorVar"></param> /// <param name="varMapList"></param> /// <returns></returns> private Node BuildUnionAllSubqueryForNestOp( NestBaseOp nestOp, Node nestNode, VarList drivingNodeVars, VarList discriminatorVarList, out Var discriminatorVar, out List<Dictionary<Var, Var>> varMapList) { var drivingNode = nestNode.Child0; // For each of the NESTED collections... Node unionAllNode = null; VarList unionAllOutputs = null; for (var i = 1; i < nestNode.Children.Count; i++) { // Ensure we only use the driving collection tree once, so other // transformations do not unintentionally change more than one path. // To prevent nodes in the tree from being used in multiple paths, // we copy the driving input on successive nodes. VarList newDrivingNodeVars; Node newDrivingNode; VarList newFlattenedElementVars; Op op; if (i > 1) { newDrivingNode = OpCopier.Copy(Command, drivingNode, drivingNodeVars, out newDrivingNodeVars); // // Bug 450245: If we copied the driver node, then references to driver node vars // from the collection subquery must be patched up // var varRemapper = new VarRemapper(Command); for (var j = 0; j < drivingNodeVars.Count; j++) { varRemapper.AddMapping(drivingNodeVars[j], newDrivingNodeVars[j]); } // Remap all references in the current subquery varRemapper.RemapSubtree(nestNode.Children[i]); // Bug 479183: Remap the flattened element vars newFlattenedElementVars = varRemapper.RemapVarList(nestOp.CollectionInfo[i - 1].FlattenedElementVars); // Create a cross apply for all but the first collection op = Command.CreateCrossApplyOp(); } else { newDrivingNode = drivingNode; newDrivingNodeVars = drivingNodeVars; newFlattenedElementVars = nestOp.CollectionInfo[i - 1].FlattenedElementVars; // Create an outer apply for the first collection, // that way we ensure at least one row for each row in the driver node. op = Command.CreateOuterApplyOp(); } // Create an outer apply with the driver node and the nested collection. var applyNode = Command.CreateNode(op, newDrivingNode, nestNode.Children[i]); // Now create a ProjectOp that augments the output from the OuterApplyOp // with nulls for each column from other collections // Build the VarDefList (the list of vars) for the Project, starting // with the collection discriminator var var varDefListChildren = new List<Node>(); var projectOutputs = Command.CreateVarList(); // Add the collection discriminator var to the output. projectOutputs.Add(discriminatorVarList[i]); // Add all columns from the driving node projectOutputs.AddRange(newDrivingNodeVars); // Add all the vars from all the nested collections; for (var j = 1; j < nestNode.Children.Count; j++) { var otherCollectionInfo = nestOp.CollectionInfo[j - 1]; // For the current nested collection, we just pick the var that's // coming from there and don't need have a new var defined, but for // the rest we construct null values. if (i == j) { projectOutputs.AddRange(newFlattenedElementVars); } else { foreach (var v in otherCollectionInfo.FlattenedElementVars) { var nullOp = Command.CreateNullOp(v.Type); var nullOpNode = Command.CreateNode(nullOp); Var nullOpVar; var nullOpVarDefNode = Command.CreateVarDefNode(nullOpNode, out nullOpVar); varDefListChildren.Add(nullOpVarDefNode); projectOutputs.Add(nullOpVar); } } } var varDefListNode = Command.CreateNode(Command.CreateVarDefListOp(), varDefListChildren); // Now, build up the projectOp var projectOutputsVarSet = Command.CreateVarVec(projectOutputs); var projectOp = Command.CreateProjectOp(projectOutputsVarSet); var projectNode = Command.CreateNode(projectOp, applyNode, varDefListNode); // finally, build the union all if (unionAllNode == null) { unionAllNode = projectNode; unionAllOutputs = projectOutputs; } else { var unionAllMap = new VarMap(); var projectMap = new VarMap(); for (var idx = 0; idx < unionAllOutputs.Count; idx++) { Var outputVar = Command.CreateSetOpVar(unionAllOutputs[idx].Type); unionAllMap.Add(outputVar, unionAllOutputs[idx]); projectMap.Add(outputVar, projectOutputs[idx]); } var unionAllOp = Command.CreateUnionAllOp(unionAllMap, projectMap); unionAllNode = Command.CreateNode(unionAllOp, unionAllNode, projectNode); // Get the output vars from the union-op. This must be in the same order // as the original list of Vars unionAllOutputs = GetUnionOutputs(unionAllOp, unionAllOutputs); } } // We're done building the node, but now we have to build a mapping from // the before-Vars to the after-Vars varMapList = new List<Dictionary<Var, Var>>(); IEnumerator<Var> outputVarsEnumerator = unionAllOutputs.GetEnumerator(); if (!outputVarsEnumerator.MoveNext()) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 4, null); // more columns from children than are on the unionAll? } // The discriminator var is always first discriminatorVar = outputVarsEnumerator.Current; // Build a map for each input for (var i = 0; i < nestNode.Children.Count; i++) { var varMap = new Dictionary<Var, Var>(); var varList = (i == 0) ? drivingNodeVars : nestOp.CollectionInfo[i - 1].FlattenedElementVars; foreach (var v in varList) { if (!outputVarsEnumerator.MoveNext()) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 5, null); // more columns from children than are on the unionAll? } varMap[v] = outputVarsEnumerator.Current; } varMapList.Add(varMap); } if (outputVarsEnumerator.MoveNext()) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 6, null); // at this point, we better be done with both lists... } return unionAllNode; }
private NestPullup(PlanCompiler compilerState) { m_compilerState = compilerState; m_varRemapper = new VarRemapper(compilerState.Command); }
/// <summary> /// Try to push the given function aggregate candidate to the corresponding group into node. /// The candidate can be pushed if all ancestors of the group into node up to the least common /// ancestor between the group into node and the function aggregate have one of the following node op types: /// Project /// Filter /// ConstraintSortOp /// </summary> /// <param name="command"></param> /// <param name="candidate"></param> /// <param name="groupAggregateVarInfo"></param> /// <param name="m_childToParent"></param> private void TryProcessCandidate( KeyValuePair <Node, Node> candidate, GroupAggregateVarInfo groupAggregateVarInfo) { IList <Node> functionAncestors; IList <Node> groupByAncestors; Node definingGroupNode = groupAggregateVarInfo.DefiningGroupNode; FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out functionAncestors, out groupByAncestors); //Check whether all ancestors of the GroupByInto node are of type that we support propagating through if (!AreAllNodesSupportedForPropagation(groupByAncestors)) { return; } //Add the function to the group by node GroupByIntoOp definingGroupOp = (GroupByIntoOp)definingGroupNode.Op; PlanCompiler.Assert(definingGroupOp.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage"); Var inputVar = definingGroupOp.Inputs.First; FunctionOp functionOp = (FunctionOp)candidate.Key.Op; // // Remap the template from referencing the groupAggregate var to reference the input to // the group by into // Node argumentNode = OpCopier.Copy(m_command, candidate.Value); Dictionary <Var, Var> dictionary = new Dictionary <Var, Var>(1); dictionary.Add(groupAggregateVarInfo.GroupAggregateVar, inputVar); VarRemapper remapper = new VarRemapper(m_command, dictionary); remapper.RemapSubtree(argumentNode); Node newFunctionDefiningNode = m_command.CreateNode( m_command.CreateAggregateOp(functionOp.Function, false), argumentNode); Var newFunctionVar; Node varDefNode = m_command.CreateVarDefNode(newFunctionDefiningNode, out newFunctionVar); // Add the new aggregate to the list of aggregates definingGroupNode.Child2.Children.Add(varDefNode); GroupByIntoOp groupByOp = (GroupByIntoOp)definingGroupNode.Op; groupByOp.Outputs.Set(newFunctionVar); //Propagate the new var throught the ancestors of the GroupByInto for (int i = 0; i < groupByAncestors.Count; i++) { Node groupByAncestor = groupByAncestors[i]; if (groupByAncestor.Op.OpType == OpType.Project) { ProjectOp ancestorProjectOp = (ProjectOp)groupByAncestor.Op; ancestorProjectOp.Outputs.Set(newFunctionVar); } } //Update the functionNode candidate.Key.Op = m_command.CreateVarRefOp(newFunctionVar); candidate.Key.Children.Clear(); }
private JoinElimination(PlanCompiler compilerState) { m_compilerState = compilerState; m_varRemapper = new VarRemapper(m_compilerState.Command); m_varRefManager = new VarRefManager(m_compilerState.Command); }
/// <summary> /// Remap the given varList using the given varMap /// </summary> /// <param name="command"></param> /// <param name="varMap"></param> /// <param name="varList"></param> internal static VarList RemapVarList(Command command, Dictionary<Var, Var> varMap, VarList varList) { VarRemapper varRemapper = new VarRemapper(command, varMap); return varRemapper.RemapVarList(varList); }
/// <summary> /// Try to push the given function aggregate candidate to the corresponding group into node. /// The candidate can be pushed if all ancestors of the group into node up to the least common /// ancestor between the group into node and the function aggregate have one of the following node op types: /// Project /// Filter /// ConstraintSortOp /// </summary> /// <param name="command"></param> /// <param name="candidate"></param> /// <param name="groupAggregateVarInfo"></param> /// <param name="m_childToParent"></param> private void TryProcessCandidate( KeyValuePair<Node, Node> candidate, GroupAggregateVarInfo groupAggregateVarInfo) { IList<Node> functionAncestors; IList<Node> groupByAncestors; Node definingGroupNode = groupAggregateVarInfo.DefiningGroupNode; FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out functionAncestors, out groupByAncestors); //Check whether all ancestors of the GroupByInto node are of type that we support propagating through if (!AreAllNodesSupportedForPropagation(groupByAncestors)) { return; } //Add the function to the group by node GroupByIntoOp definingGroupOp = (GroupByIntoOp)definingGroupNode.Op; PlanCompiler.Assert(definingGroupOp.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage"); Var inputVar = definingGroupOp.Inputs.First; FunctionOp functionOp = (FunctionOp)candidate.Key.Op; // // Remap the template from referencing the groupAggregate var to reference the input to // the group by into // Node argumentNode = OpCopier.Copy(m_command, candidate.Value); Dictionary<Var, Var> dictionary = new Dictionary<Var, Var>(1); dictionary.Add(groupAggregateVarInfo.GroupAggregateVar, inputVar); VarRemapper remapper = new VarRemapper(m_command, dictionary); remapper.RemapSubtree(argumentNode); Node newFunctionDefiningNode = m_command.CreateNode( m_command.CreateAggregateOp(functionOp.Function, false), argumentNode); Var newFunctionVar; Node varDefNode = m_command.CreateVarDefNode(newFunctionDefiningNode, out newFunctionVar); // Add the new aggregate to the list of aggregates definingGroupNode.Child2.Children.Add(varDefNode); GroupByIntoOp groupByOp = (GroupByIntoOp)definingGroupNode.Op; groupByOp.Outputs.Set(newFunctionVar); //Propagate the new var throught the ancestors of the GroupByInto for (int i = 0; i < groupByAncestors.Count; i++) { Node groupByAncestor = groupByAncestors[i]; if (groupByAncestor.Op.OpType == OpType.Project) { ProjectOp ancestorProjectOp = (ProjectOp)groupByAncestor.Op; ancestorProjectOp.Outputs.Set(newFunctionVar); } } //Update the functionNode candidate.Key.Op = m_command.CreateVarRefOp(newFunctionVar); candidate.Key.Children.Clear(); }
/// <summary> /// Remap the given varList using the given varMap /// </summary> /// <param name="command"></param> /// <param name="varMap"></param> /// <param name="varList"></param> internal static VarList RemapVarList(Command command, Dictionary <Var, Var> varMap, VarList varList) { VarRemapper varRemapper = new VarRemapper(command, varMap); return(varRemapper.RemapVarList(varList)); }
internal TransformationRulesContext(PlanCompiler compilerState) : base(compilerState.Command) { m_compilerState = compilerState; m_remapper = new VarRemapper(compilerState.Command); m_suppressions = new Dictionary<Node, Node>(); m_remappedVars = compilerState.Command.CreateVarVec(); }