// <summary> // Converts a GroupBy(Project(X, c1,..ck), agg1, agg2, .. aggm) => // GroupBy(X, agg1', agg2', .. aggm') // where agg1', agg2', .. aggm' are the "mapped" versions // of agg1, agg2, .. aggm, such that the references to c1, ... ck are // replaced by their definitions. // We only do this if each c1, ..ck is refereneced (in aggregates) at most once or it is a constant. // </summary> // <param name="context"> Rule processing context </param> // <param name="n"> Current ProjectOp node </param> // <param name="newNode"> modified subtree </param> // <returns> Transformation status </returns> private static bool ProcessGroupByOverProject(RuleProcessingContext context, Node n, out Node newNode) { newNode = n; var op = (GroupByOp)n.Op; var command = (context).Command; var projectNode = n.Child0; var projectNodeVarDefList = projectNode.Child1; var keys = n.Child1; var aggregates = n.Child2; // If there are any keys, we should not remove the inner project if (keys.Children.Count > 0) { return(false); } //Get a list of all defining vars var projectDefinitions = command.GetExtendedNodeInfo(projectNode).LocalDefinitions; //If any of the defined vars is output, than we need the extra project anyway. if (op.Outputs.Overlaps(projectDefinitions)) { return(false); } var createdNewProjectDefinitions = false; //If there are any constants remove them from the list that needs to be tested, //These can safely be replaced for (var i = 0; i < projectNodeVarDefList.Children.Count; i++) { var varDefNode = projectNodeVarDefList.Children[i]; if (varDefNode.Child0.Op.OpType == OpType.Constant || varDefNode.Child0.Op.OpType == OpType.InternalConstant || varDefNode.Child0.Op.OpType == OpType.NullSentinel) { //We shouldn't modify the original project definitions, thus we copy it // the first time we encounter a constant if (!createdNewProjectDefinitions) { projectDefinitions = command.CreateVarVec(projectDefinitions); createdNewProjectDefinitions = true; } projectDefinitions.Clear(((VarDefOp)varDefNode.Op).Var); } } if (VarRefUsageFinder.AnyVarUsedMoreThanOnce(projectDefinitions, aggregates, command)) { return(false); } //If we got here it means that all vars were either constants, or used at most once // Create a dictionary to be used for remapping the keys and the aggregates var varToDefiningNode = new Dictionary <Var, Node>(projectNodeVarDefList.Children.Count); for (var j = 0; j < projectNodeVarDefList.Children.Count; j++) { var varDefNode = projectNodeVarDefList.Children[j]; var var = ((VarDefOp)varDefNode.Op).Var; varToDefiningNode.Add(var, varDefNode.Child0); } newNode.Child2 = VarRefReplacer.Replace(varToDefiningNode, aggregates, command); newNode.Child0 = projectNode.Child0; return(true); }
// <summary> // "Public" entry point. In the subtree rooted at the given root, // replace each occurance of the given vars with their definitions, // where each key-value pair in the dictionary is a var-definition pair. // </summary> internal static Node Replace(Dictionary <Var, Node> varReplacementTable, Node root, Command command) { var replacer = new VarRefReplacer(varReplacementTable, command); return(replacer.VisitNode(root)); }
/// <summary> /// "Public" entry point. In the subtree rooted at the given root, /// replace each occurance of the given vars with their definitions, /// where each key-value pair in the dictionary is a var-definition pair. /// </summary> /// <param name="varReplacementTable"> </param> /// <param name="root"> </param> /// <param name="command"> </param> /// <returns> </returns> internal static Node Replace(Dictionary<Var, Node> varReplacementTable, Node root, Command command) { var replacer = new VarRefReplacer(varReplacementTable, command); return replacer.VisitNode(root); }