private void Map(List <SortKey> sortKeys) { VarVec varVec = this.m_command.CreateVarVec(); bool flag = false; foreach (SortKey sortKey in sortKeys) { sortKey.Var = this.Map(sortKey.Var); if (varVec.IsSet(sortKey.Var)) { flag = true; } varVec.Set(sortKey.Var); } if (!flag) { return; } List <SortKey> sortKeyList = new List <SortKey>((IEnumerable <SortKey>)sortKeys); sortKeys.Clear(); varVec.Clear(); foreach (SortKey sortKey in sortKeyList) { if (!varVec.IsSet(sortKey.Var)) { sortKeys.Add(sortKey); } varVec.Set(sortKey.Var); } }
private void RemoveRedundantConstantKeys(VarVec keyVec, VarVec outputVec, System.Data.Entity.Core.Query.InternalTrees.Node varDefListNode) { List <System.Data.Entity.Core.Query.InternalTrees.Node> constantKeys = varDefListNode.Children.Where <System.Data.Entity.Core.Query.InternalTrees.Node>((Func <System.Data.Entity.Core.Query.InternalTrees.Node, bool>)(d => { if (d.Op.OpType == OpType.VarDef) { return(PlanCompilerUtil.IsConstantBaseOp(d.Child0.Op.OpType)); } return(false); })).ToList <System.Data.Entity.Core.Query.InternalTrees.Node>(); VarVec constantKeyVars = this.m_command.CreateVarVec(constantKeys.Select <System.Data.Entity.Core.Query.InternalTrees.Node, Var>((Func <System.Data.Entity.Core.Query.InternalTrees.Node, Var>)(d => ((VarDefOp)d.Op).Var))); constantKeyVars.Minus(this.m_referencedVars); keyVec.Minus(constantKeyVars); outputVec.Minus(constantKeyVars); varDefListNode.Children.RemoveAll((Predicate <System.Data.Entity.Core.Query.InternalTrees.Node>)(c => { if (constantKeys.Contains(c)) { return(constantKeyVars.IsSet(((VarDefOp)c.Op).Var)); } return(false); })); if (keyVec.Count != 0) { return; } System.Data.Entity.Core.Query.InternalTrees.Node node = constantKeys.First <System.Data.Entity.Core.Query.InternalTrees.Node>(); Var var = ((VarDefOp)node.Op).Var; keyVec.Set(var); outputVec.Set(var); varDefListNode.Children.Add(node); }
/// <summary> /// Helper method for removing redundant constant keys from GroupByOp and DistictOp. /// It only examines the keys defined in the given varDefListNode. /// It removes all constant and null keys that are not referenced elsewhere, /// but ensuring that at least one key is left. /// It should not be called with empty keyVec. /// </summary> /// <param name="keyVec"> The keys </param> /// <param name="outputVec"> The var vec that needs to be updated along with the keys </param> /// <param name="varDefListNode"> Var def list node for the keys </param> private void RemoveRedundantConstantKeys(VarVec keyVec, VarVec outputVec, Node varDefListNode) { //Find all the keys that are nulls and constants var constantKeys = varDefListNode.Children.Where( d => d.Op.OpType == OpType.VarDef && PlanCompilerUtil.IsConstantBaseOp(d.Child0.Op.OpType)).ToList(); var constantKeyVars = m_command.CreateVarVec(constantKeys.Select(d => ((VarDefOp)d.Op).Var)); //Get the list of unreferenced constant keys constantKeyVars.Minus(m_referencedVars); //Remove the unreferenced constant keys keyVec.Minus(constantKeyVars); outputVec.Minus(constantKeyVars); varDefListNode.Children.RemoveAll(c => constantKeys.Contains(c) && constantKeyVars.IsSet(((VarDefOp)c.Op).Var)); //If no keys are left add one. if (keyVec.Count == 0) { var keyNode = constantKeys.First(); var keyVar = ((VarDefOp)keyNode.Op).Var; keyVec.Set(keyVar); outputVec.Set(keyVar); varDefListNode.Children.Add(keyNode); } }
internal Table(Command command, TableMD tableMetadata, int tableId) { m_tableMetadata = tableMetadata; m_columns = Command.CreateVarList(); m_keys = command.CreateVarVec(); m_nonnullableColumns = command.CreateVarVec(); m_tableId = tableId; var columnVarMap = new Dictionary<string, ColumnVar>(); foreach (var c in tableMetadata.Columns) { var v = command.CreateColumnVar(this, c); columnVarMap[c.Name] = v; if (!c.IsNullable) { m_nonnullableColumns.Set(v); } } foreach (var c in tableMetadata.Keys) { var v = columnVarMap[c.Name]; m_keys.Set(v); } m_referencedColumns = command.CreateVarVec(m_columns); }
private static bool ProcessApplyIntoScalarSubquery( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node applyNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { Command command = context.Command; ExtendedNodeInfo extendedNodeInfo1 = command.GetExtendedNodeInfo(applyNode.Child1); OpType opType = applyNode.Op.OpType; if (!ApplyOpRules.CanRewriteApply(applyNode.Child1, extendedNodeInfo1, opType)) { newNode = applyNode; return(false); } ExtendedNodeInfo extendedNodeInfo2 = command.GetExtendedNodeInfo(applyNode.Child0); Var first = extendedNodeInfo1.Definitions.First; VarVec varVec = command.CreateVarVec(extendedNodeInfo2.Definitions); TransformationRulesContext transformationRulesContext = (TransformationRulesContext)context; transformationRulesContext.RemapSubtree(applyNode.Child1); ApplyOpRules.VarDefinitionRemapper.RemapSubtree(applyNode.Child1, command, first); System.Data.Entity.Core.Query.InternalTrees.Node node = command.CreateNode((Op)command.CreateElementOp(first.Type), applyNode.Child1); Var computedVar; System.Data.Entity.Core.Query.InternalTrees.Node varDefListNode = command.CreateVarDefListNode(node, out computedVar); varVec.Set(computedVar); newNode = command.CreateNode((Op)command.CreateProjectOp(varVec), applyNode.Child0, varDefListNode); transformationRulesContext.AddVarMapping(first, computedVar); return(true); }
private Node VisitCollectionAggregateFunction(FunctionOp op, Node n) { TypeUsage type = (TypeUsage)null; Node child0 = n.Child0; if (OpType.SoftCast == child0.Op.OpType) { type = TypeHelpers.GetEdmType <CollectionType>(child0.Op.Type).TypeUsage; child0 = child0.Child0; while (OpType.SoftCast == child0.Op.OpType) { child0 = child0.Child0; } } Node node1 = this.BuildUnnest(child0); Var column = (node1.Op as UnnestOp).Table.Columns[0]; AggregateOp aggregateOp = this.m_command.CreateAggregateOp(op.Function, false); Node node2 = this.m_command.CreateNode((Op)this.m_command.CreateVarRefOp(column)); if (type != null) { node2 = this.m_command.CreateNode((Op)this.m_command.CreateSoftCastOp(type), node2); } Node node3 = this.m_command.CreateNode((Op)aggregateOp, node2); VarVec varVec1 = this.m_command.CreateVarVec(); Node node4 = this.m_command.CreateNode((Op)this.m_command.CreateVarDefListOp()); VarVec varVec2 = this.m_command.CreateVarVec(); Var computedVar; Node varDefListNode = this.m_command.CreateVarDefListNode(node3, out computedVar); varVec2.Set(computedVar); Node node5 = this.m_command.CreateNode((Op)this.m_command.CreateGroupByOp(varVec1, varVec2), node1, node4, varDefListNode); return(this.AddSubqueryToParentRelOp(computedVar, node5)); }
private static VarVec CreateVarVec(params int[] bits) { var command = new Mock<Command>(); var vec = new VarVec(command.Object); bits.Each(b => { var v = CreateVar(b); vec.Set(v); command.Setup(m => m.GetVar(b)).Returns(v); }); return vec; }
private void Map(List <InternalTrees.SortKey> sortKeys) { VarVec sortVars = m_command.CreateVarVec(); bool hasDuplicates = false; // // Map each var in the sort list. Remapping may introduce duplicates, and // we should get rid of duplicates, since sql doesn't like them // foreach (InternalTrees.SortKey sk in sortKeys) { sk.Var = Map(sk.Var); if (sortVars.IsSet(sk.Var)) { hasDuplicates = true; } sortVars.Set(sk.Var); } // // Get rid of any duplicates // if (hasDuplicates) { List <InternalTrees.SortKey> newSortKeys = new List <SortKey>(sortKeys); sortKeys.Clear(); sortVars.Clear(); foreach (InternalTrees.SortKey sk in newSortKeys) { if (!sortVars.IsSet(sk.Var)) { sortKeys.Add(sk); } sortVars.Set(sk.Var); } } }
public override void Visit(VarRefOp op, Node n) { var referencedVar = op.Var; if (m_varVec.IsSet(referencedVar)) { if (m_usedVars.IsSet(referencedVar)) { m_anyUsedMoreThenOnce = true; } else { m_usedVars.Set(referencedVar); } } }
/// <summary> /// Converts a collection aggregate function count(X), where X is a collection into /// two parts. Part A is a groupby subquery that looks like /// GroupBy(Unnest(X), empty, count(y)) /// where "empty" describes the fact that the groupby has no keys, and y is an /// element var of the Unnest /// /// Part 2 is a VarRef that refers to the aggregate var for count(y) described above. /// /// Logically, we would replace the entire functionOp by element(GroupBy...). However, /// since we also want to translate element() into single-row-subqueries, we do this /// here as well. /// /// The function itself is replaced by the VarRef, and the GroupBy is added to the list /// of scalar subqueries for the current relOp node on the stack /// /// </summary> /// <param name="op">the functionOp for the collection agg</param> /// <param name="n">current subtree</param> /// <returns>the VarRef node that should replace the function</returns> private Node VisitCollectionAggregateFunction(FunctionOp op, Node n) { TypeUsage softCastType = null; Node argNode = n.Child0; if (OpType.SoftCast == argNode.Op.OpType) { softCastType = TypeHelpers.GetEdmType <CollectionType>(argNode.Op.Type).TypeUsage; argNode = argNode.Child0; while (OpType.SoftCast == argNode.Op.OpType) { argNode = argNode.Child0; } } Node unnestNode = BuildUnnest(argNode); UnnestOp unnestOp = unnestNode.Op as UnnestOp; Var unnestOutputVar = unnestOp.Table.Columns[0]; AggregateOp aggregateOp = m_command.CreateAggregateOp(op.Function, false); VarRefOp unnestVarRefOp = m_command.CreateVarRefOp(unnestOutputVar); Node unnestVarRefNode = m_command.CreateNode(unnestVarRefOp); if (softCastType != null) { unnestVarRefNode = m_command.CreateNode(m_command.CreateSoftCastOp(softCastType), unnestVarRefNode); } Node aggExprNode = m_command.CreateNode(aggregateOp, unnestVarRefNode); VarVec keyVars = m_command.CreateVarVec(); // empty keys Node keyVarDefListNode = m_command.CreateNode(m_command.CreateVarDefListOp()); VarVec gbyOutputVars = m_command.CreateVarVec(); Var aggVar; Node aggVarDefListNode = m_command.CreateVarDefListNode(aggExprNode, out aggVar); gbyOutputVars.Set(aggVar); GroupByOp gbyOp = m_command.CreateGroupByOp(keyVars, gbyOutputVars); Node gbySubqueryNode = m_command.CreateNode(gbyOp, unnestNode, keyVarDefListNode, aggVarDefListNode); // "Move" this subquery to my parent relop Node ret = AddSubqueryToParentRelOp(aggVar, gbySubqueryNode); return(ret); }
// <summary> // Convert a CollectOp subtree (when used as the defining expression for a // VarDefOp) into a reasonable input to a NestOp. // </summary> // <remarks> // There are a couple of cases that we handle here: // (a) PhysicalProject(X) ==> X // (b) PhysicalProject(Sort(X)) ==> Sort(X) // </remarks> // <param name="physicalProjectNode"> the child of the CollectOp </param> // <param name="collectionVar"> the collectionVar being defined </param> // <param name="collectionInfoList"> where to append the new collectionInfo </param> // <param name="collectionNodes"> where to append the collectionNode </param> // <param name="externalReferences"> a bit vector of external references of the physicalProject </param> // <param name="collectionReferences"> a bit vector of collection vars </param> private void ConvertToNestOpInput( Node physicalProjectNode, Var collectionVar, List<CollectionInfo> collectionInfoList, List<Node> collectionNodes, VarVec externalReferences, VarVec collectionReferences) { // Keep track of any external references the physicalProjectOp has externalReferences.Or(Command.GetNodeInfo(physicalProjectNode).ExternalReferences); // Case: (a) PhysicalProject(X) ==> X var nestOpInput = physicalProjectNode.Child0; // Now build the collectionInfo for this input, including the flattened // list of vars, which is essentially the outputs from the physicalProject // with the sortKey vars that aren't already in the outputs we already // have. var physicalProjectOp = (PhysicalProjectOp)physicalProjectNode.Op; var flattenedElementVarList = Command.CreateVarList(physicalProjectOp.Outputs); var flattenedElementVarVec = Command.CreateVarVec(flattenedElementVarList); // Use a VarVec to make the lookups faster List<SortKey> sortKeys = null; if (OpType.Sort == nestOpInput.Op.OpType) { // Case: (b) PhysicalProject(Sort(X)) ==> Sort(X) var sortOp = (SortOp)nestOpInput.Op; sortKeys = OpCopier.Copy(Command, sortOp.Keys); foreach (var sk in sortKeys) { if (!flattenedElementVarVec.IsSet(sk.Var)) { flattenedElementVarList.Add(sk.Var); flattenedElementVarVec.Set(sk.Var); } } } else { sortKeys = new List<SortKey>(); } // Get the keys for the collection var keyVars = Command.GetExtendedNodeInfo(nestOpInput).Keys.KeyVars; //Check whether all key are projected var keyVarsClone = keyVars.Clone(); keyVarsClone.Minus(flattenedElementVarVec); var keys = (keyVarsClone.IsEmpty) ? keyVars.Clone() : Command.CreateVarVec(); // Create the collectionInfo var collectionInfo = Command.CreateCollectionInfo( collectionVar, physicalProjectOp.ColumnMap.Element, flattenedElementVarList, keys, sortKeys, null /*discriminatorValue*/); // Now update the collections we're tracking. collectionInfoList.Add(collectionInfo); collectionNodes.Add(nestOpInput); collectionReferences.Set(collectionVar); }
// <summary> // If we're going to eat the ProjectNode, then we at least need to make // sure we remap any vars it defines as varRefs, and ensure that any // references to them are switched. // </summary> private void EnsureReferencedVarsAreRemoved(List<Node> referencedVars, VarVec outputVars) { foreach (var chi in referencedVars) { var varDefOp = (VarDefOp)chi.Op; var defVar = varDefOp.Var; var refVar = ResolveVarReference(defVar); m_varRemapper.AddMapping(defVar, refVar); outputVars.Clear(defVar); outputVars.Set(refVar); } }
/// <summary> /// Comments from Murali: /// /// There are several cases to consider here. /// /// Case 0: /// Let’s assume that K1 is the set of keys ({k1, k2, ..., kn}) for the /// first input, and K2 ({l1, l2, …}) is the set of keys for the second /// input. /// /// The best case is when both K1 and K2 have the same cardinality (hopefully /// greater than 0), and the keys are in the same locations (ie) the corresponding /// positions in the select-list. Even in this case, its not enough to take /// the keys, and treat them as the keys of the union-all. What we’ll need to /// do is to add a “branch” discriminator constant for each branch of the /// union-all, and use this as the prefix for the keys. /// /// For example, if I had: /// /// Select c1, c2, c3... from ... /// Union all /// Select d1, d2, d3... from ... /// /// And for the sake of argument, lets say that {c2} and {d2} are the keys of /// each of the branches. What you’ll need to do is to translate this into /// /// Select 0 as bd, c1, c2, c3... from ... /// Union all /// Select 1 as bd, d1, d2, d3... from ... /// /// And then treat {bd, c2/d2} as the key of the union-all /// /// Case 1: (actually, a subcase of Case 0): /// Now, if the keys don’t align, then we can simply take the union of the /// corresponding positions, and make them all the keys (we would still need /// the branch discriminator) /// /// Case 2: /// Finally, if you need to “pull” up keys from either of the branches, it is /// possible that the branches get out of whack. We will then need to push up /// the keys (with nulls if the other branch doesn’t have the corresponding key) /// into the union-all. (We still need the branch discriminator). /// /// Now, unfortunately, whenever we've got polymorphic entity types, we'll end up /// in case 2 way more often than we really want to, because when we're pulling up /// keys, we don't want to reason about a caseop (which is how polymorphic types /// wrap their key value). /// /// To simplify all of this, we: /// /// (1) Pulling up the keys for both branches of the UnionAll, and computing which /// keys are in the outputs and which are missing from the outputs. /// /// (2) Accumulate all the missing keys. /// /// (3) Slap a projectOp around each branch, adding a branch discriminator /// var and all the missing keys. When keys are missing from a different /// branch, we'll construct null ops for them on the other branches. If /// a branch already has a branch descriminator, we'll re-use it instead /// of constructing a new one. (Of course, if there aren't any keys to /// add and it's already including the branch discriminator we won't /// need the projectOp) /// /// </summary> /// <param name="op">the UnionAllOp</param> /// <param name="n">current subtree</param> public override void Visit(UnionAllOp op, Node n) { #if DEBUG string input = Dump.ToXml(m_command, n); #endif //DEBUG // Ensure we have keys pulled up on each branch of the union all. VisitChildren(n); // Create the setOp var we'll use to output the branch discriminator value; if // any of the branches are already surfacing a branchDiscriminator var to the // output of this operation then we won't need to use this but we construct it // early to simplify logic. Var outputBranchDiscriminatorVar = m_command.CreateSetOpVar(m_command.IntegerType); // Now ensure that we're outputting the key vars from this op as well. VarList allKeyVarsMissingFromOutput = Command.CreateVarList(); VarVec[] keyVarsMissingFromOutput = new VarVec[n.Children.Count]; for (int i = 0; i < n.Children.Count; i++) { Node branchNode = n.Children[i]; ExtendedNodeInfo branchNodeInfo = m_command.GetExtendedNodeInfo(branchNode); // Identify keys that aren't in the output list of this operation. We // determine these by remapping the keys that are found through the node's // VarMap, which gives us the keys in the same "varspace" as the outputs // of the UnionAll, then we subtract out the outputs of this UnionAll op, // leaving things that are not in the output vars. Of course, if they're // not in the output vars, then we didn't really remap. VarVec existingKeyVars = branchNodeInfo.Keys.KeyVars.Remap(op.VarMap[i]); keyVarsMissingFromOutput[i] = m_command.CreateVarVec(existingKeyVars); keyVarsMissingFromOutput[i].Minus(op.Outputs); // Special Case: if the branch is a UnionAll, it will already have it's // branch discriminator var added in the keys; we don't want to add that // a second time... if (OpType.UnionAll == branchNode.Op.OpType) { UnionAllOp branchUnionAllOp = (UnionAllOp)branchNode.Op; keyVarsMissingFromOutput[i].Clear(branchUnionAllOp.BranchDiscriminator); } allKeyVarsMissingFromOutput.AddRange(keyVarsMissingFromOutput[i]); } // Construct the setOp vars we're going to map to output. VarList allKeyVarsToAddToOutput = Command.CreateVarList(); foreach (Var v in allKeyVarsMissingFromOutput) { Var newKeyVar = m_command.CreateSetOpVar(v.Type); allKeyVarsToAddToOutput.Add(newKeyVar); } // Now that we've identified all the keys we need to add, ensure that each branch // has both the branch discrimination var and the all the keys in them, even when // the keys are just going to null (which we construct, as needed) for (int i = 0; i < n.Children.Count; i++) { Node branchNode = n.Children[i]; ExtendedNodeInfo branchNodeInfo = m_command.GetExtendedNodeInfo(branchNode); VarVec branchOutputVars = m_command.CreateVarVec(); List <Node> varDefNodes = new List <Node>(); // If the branch is a UnionAllOp that has a branch discriminator var then we can // use it, otherwise we'll construct a new integer constant with the next value // of the branch discriminator value from the command object. Var branchDiscriminatorVar; if (OpType.UnionAll == branchNode.Op.OpType && null != ((UnionAllOp)branchNode.Op).BranchDiscriminator) { branchDiscriminatorVar = ((UnionAllOp)branchNode.Op).BranchDiscriminator; // If the branch has a discriminator var, but we haven't added it to the // varmap yet, then we do so now. if (!op.VarMap[i].ContainsValue(branchDiscriminatorVar)) { op.VarMap[i].Add(outputBranchDiscriminatorVar, branchDiscriminatorVar); // We don't need to add this to the branch outputs, because it's already there, // otherwise we wouln't have gotten here, yes? } else { // In this case, we're already outputting the branch discriminator var -- we'll // just use it for both sides. We should never have a case where only one of the // two branches are outputting the branch discriminator var, because it can only // be constructed in this method, and we wouldn't need it for any other purpose. PlanCompiler.Assert(0 == i, "right branch has a discriminator var that the left branch doesn't have?"); VarMap reverseVarMap = op.VarMap[i].GetReverseMap(); outputBranchDiscriminatorVar = reverseVarMap[branchDiscriminatorVar]; } } else { // Not a unionAll -- we have to add a BranchDiscriminator var. varDefNodes.Add( m_command.CreateVarDefNode( m_command.CreateNode( m_command.CreateConstantOp(m_command.IntegerType, m_command.NextBranchDiscriminatorValue)), out branchDiscriminatorVar)); branchOutputVars.Set(branchDiscriminatorVar); op.VarMap[i].Add(outputBranchDiscriminatorVar, branchDiscriminatorVar); } // Append all the missing keys to the branch outputs. If the missing key // is not from this branch then create a null. for (int j = 0; j < allKeyVarsMissingFromOutput.Count; j++) { Var keyVar = allKeyVarsMissingFromOutput[j]; if (!keyVarsMissingFromOutput[i].IsSet(keyVar)) { varDefNodes.Add( m_command.CreateVarDefNode( m_command.CreateNode( m_command.CreateNullOp(keyVar.Type)), out keyVar)); branchOutputVars.Set(keyVar); } // In all cases, we're adding a key to the output so we need to update the // varmap. op.VarMap[i].Add(allKeyVarsToAddToOutput[j], keyVar); } // If we got this far and didn't add anything to the branch, then we're done. // Otherwise we'll have to construct the new projectOp around the input branch // to add the stuff we've added. if (branchOutputVars.IsEmpty) { // Actually, we're not quite done -- we need to update the key vars for the // branch to include the branch discriminator var we branchNodeInfo.Keys.KeyVars.Set(branchDiscriminatorVar); } else { PlanCompiler.Assert(varDefNodes.Count != 0, "no new nodes?"); // Start by ensuring all the existing outputs from the branch are in the list. foreach (Var v in op.VarMap[i].Values) { branchOutputVars.Set(v); } // Now construct a project op to project out everything we've added, and // replace the branchNode with it in the flattened ladder. n.Children[i] = m_command.CreateNode(m_command.CreateProjectOp(branchOutputVars), branchNode, m_command.CreateNode(m_command.CreateVarDefListOp(), varDefNodes)); // Finally, ensure that we update the Key info for the projectOp to include // the original branch's keys, along with the branch discriminator var. m_command.RecomputeNodeInfo(n.Children[i]); ExtendedNodeInfo projectNodeInfo = m_command.GetExtendedNodeInfo(n.Children[i]); projectNodeInfo.Keys.KeyVars.InitFrom(branchNodeInfo.Keys.KeyVars); projectNodeInfo.Keys.KeyVars.Set(branchDiscriminatorVar); } } // All done with the branches, now it's time to update the UnionAll op to indicate // that we've got a branch discriminator var. n.Op = m_command.CreateUnionAllOp(op.VarMap[0], op.VarMap[1], outputBranchDiscriminatorVar); // Finally, the thing we've all been waiting for -- computing the keys. We cheat here and let // nodeInfo do it so we don't have to duplicate the logic... m_command.RecomputeNodeInfo(n); #if DEBUG input = input.Trim(); string output = Dump.ToXml(m_command, n); #endif //DEBUG }
/// <summary> /// Adds a reference to this Var /// </summary> /// <param name="v"> </param> private void AddReference(Var v) { m_referencedVars.Set(v); }
private static bool ProcessJoinOverProject( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node joinNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = joinNode; TransformationRulesContext transformationRulesContext = (TransformationRulesContext)context; Command command = transformationRulesContext.Command; System.Data.Entity.Core.Query.InternalTrees.Node node1 = joinNode.HasChild2 ? joinNode.Child2 : (System.Data.Entity.Core.Query.InternalTrees.Node)null; Dictionary <Var, int> varRefMap = new Dictionary <Var, int>(); if (node1 != null && !transformationRulesContext.IsScalarOpTree(node1, varRefMap)) { return(false); } VarVec varVec1 = command.CreateVarVec(); List <System.Data.Entity.Core.Query.InternalTrees.Node> args = new List <System.Data.Entity.Core.Query.InternalTrees.Node>(); if (joinNode.Op.OpType != OpType.LeftOuterJoin && joinNode.Child0.Op.OpType == OpType.Project && joinNode.Child1.Op.OpType == OpType.Project) { ProjectOp op1 = (ProjectOp)joinNode.Child0.Op; ProjectOp op2 = (ProjectOp)joinNode.Child1.Op; Dictionary <Var, System.Data.Entity.Core.Query.InternalTrees.Node> varMap1 = transformationRulesContext.GetVarMap(joinNode.Child0.Child1, varRefMap); Dictionary <Var, System.Data.Entity.Core.Query.InternalTrees.Node> varMap2 = transformationRulesContext.GetVarMap(joinNode.Child1.Child1, varRefMap); if (varMap1 == null || varMap2 == null) { return(false); } System.Data.Entity.Core.Query.InternalTrees.Node node2; if (node1 != null) { System.Data.Entity.Core.Query.InternalTrees.Node node3 = transformationRulesContext.ReMap(node1, varMap1); System.Data.Entity.Core.Query.InternalTrees.Node node4 = transformationRulesContext.ReMap(node3, varMap2); node2 = context.Command.CreateNode(joinNode.Op, joinNode.Child0.Child0, joinNode.Child1.Child0, node4); } else { node2 = context.Command.CreateNode(joinNode.Op, joinNode.Child0.Child0, joinNode.Child1.Child0); } varVec1.InitFrom(op1.Outputs); foreach (Var output in op2.Outputs) { varVec1.Set(output); } ProjectOp projectOp = command.CreateProjectOp(varVec1); args.AddRange((IEnumerable <System.Data.Entity.Core.Query.InternalTrees.Node>)joinNode.Child0.Child1.Children); args.AddRange((IEnumerable <System.Data.Entity.Core.Query.InternalTrees.Node>)joinNode.Child1.Child1.Children); System.Data.Entity.Core.Query.InternalTrees.Node node5 = command.CreateNode((Op)command.CreateVarDefListOp(), args); System.Data.Entity.Core.Query.InternalTrees.Node node6 = command.CreateNode((Op)projectOp, node2, node5); newNode = node6; return(true); } int index1; int index2; if (joinNode.Child0.Op.OpType == OpType.Project) { index1 = 0; index2 = 1; } else { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(joinNode.Op.OpType != OpType.LeftOuterJoin, "unexpected non-LeftOuterJoin"); index1 = 1; index2 = 0; } System.Data.Entity.Core.Query.InternalTrees.Node child = joinNode.Children[index1]; ProjectOp op = child.Op as ProjectOp; Dictionary <Var, System.Data.Entity.Core.Query.InternalTrees.Node> varMap = transformationRulesContext.GetVarMap(child.Child1, varRefMap); if (varMap == null) { return(false); } ExtendedNodeInfo extendedNodeInfo = command.GetExtendedNodeInfo(joinNode.Children[index2]); VarVec varVec2 = command.CreateVarVec(op.Outputs); varVec2.Or(extendedNodeInfo.Definitions); op.Outputs.InitFrom(varVec2); if (node1 != null) { System.Data.Entity.Core.Query.InternalTrees.Node node2 = transformationRulesContext.ReMap(node1, varMap); joinNode.Child2 = node2; } joinNode.Children[index1] = child.Child0; context.Command.RecomputeNodeInfo(joinNode); newNode = context.Command.CreateNode((Op)op, joinNode, child.Child1); return(true); }
public override void Visit(UnionAllOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitChildren(n); Var var1 = (Var)this.m_command.CreateSetOpVar(this.m_command.IntegerType); VarList varList1 = Command.CreateVarList(); VarVec[] varVecArray = new VarVec[n.Children.Count]; for (int index = 0; index < n.Children.Count; ++index) { System.Data.Entity.Core.Query.InternalTrees.Node child = n.Children[index]; VarVec v = this.m_command.GetExtendedNodeInfo(child).Keys.KeyVars.Remap((Dictionary <Var, Var>)op.VarMap[index]); varVecArray[index] = this.m_command.CreateVarVec(v); varVecArray[index].Minus(op.Outputs); if (OpType.UnionAll == child.Op.OpType) { UnionAllOp op1 = (UnionAllOp)child.Op; varVecArray[index].Clear(op1.BranchDiscriminator); } varList1.AddRange((IEnumerable <Var>)varVecArray[index]); } VarList varList2 = Command.CreateVarList(); foreach (Var var2 in (List <Var>)varList1) { Var setOpVar = (Var)this.m_command.CreateSetOpVar(var2.Type); varList2.Add(setOpVar); } for (int index1 = 0; index1 < n.Children.Count; ++index1) { System.Data.Entity.Core.Query.InternalTrees.Node child = n.Children[index1]; ExtendedNodeInfo extendedNodeInfo1 = this.m_command.GetExtendedNodeInfo(child); VarVec varVec = this.m_command.CreateVarVec(); List <System.Data.Entity.Core.Query.InternalTrees.Node> args = new List <System.Data.Entity.Core.Query.InternalTrees.Node>(); Var computedVar1; if (OpType.UnionAll == child.Op.OpType && ((UnionAllOp)child.Op).BranchDiscriminator != null) { computedVar1 = ((UnionAllOp)child.Op).BranchDiscriminator; if (!op.VarMap[index1].ContainsValue(computedVar1)) { op.VarMap[index1].Add(var1, computedVar1); } else { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(0 == index1, "right branch has a discriminator var that the left branch doesn't have?"); var1 = op.VarMap[index1].GetReverseMap()[computedVar1]; } } else { args.Add(this.m_command.CreateVarDefNode(this.m_command.CreateNode((Op)this.m_command.CreateConstantOp(this.m_command.IntegerType, (object)this.m_command.NextBranchDiscriminatorValue)), out computedVar1)); varVec.Set(computedVar1); op.VarMap[index1].Add(var1, computedVar1); } for (int index2 = 0; index2 < varList1.Count; ++index2) { Var computedVar2 = varList1[index2]; if (!varVecArray[index1].IsSet(computedVar2)) { args.Add(this.m_command.CreateVarDefNode(this.m_command.CreateNode((Op)this.m_command.CreateNullOp(computedVar2.Type)), out computedVar2)); varVec.Set(computedVar2); } op.VarMap[index1].Add(varList2[index2], computedVar2); } if (varVec.IsEmpty) { extendedNodeInfo1.Keys.KeyVars.Set(computedVar1); } else { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(args.Count != 0, "no new nodes?"); foreach (Var v in op.VarMap[index1].Values) { varVec.Set(v); } n.Children[index1] = this.m_command.CreateNode((Op)this.m_command.CreateProjectOp(varVec), child, this.m_command.CreateNode((Op)this.m_command.CreateVarDefListOp(), args)); this.m_command.RecomputeNodeInfo(n.Children[index1]); ExtendedNodeInfo extendedNodeInfo2 = this.m_command.GetExtendedNodeInfo(n.Children[index1]); extendedNodeInfo2.Keys.KeyVars.InitFrom(extendedNodeInfo1.Keys.KeyVars); extendedNodeInfo2.Keys.KeyVars.Set(computedVar1); } } n.Op = (Op)this.m_command.CreateUnionAllOp(op.VarMap[0], op.VarMap[1], var1); this.m_command.RecomputeNodeInfo(n); }