//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner Microsoft // @backupOwner Microsoft //--------------------------------------------------------------------- // Interesting cases: Unnest // More generally, note that any subtree that is left-correlated will stay as such. // namespace System.Data.Query.InternalTrees { using System; using System.Collections.Generic; using System.Diagnostics; /// /// Handles copying of operators /// internal class OpCopier : BasicOpVisitorOfNode { #region (pseudo) Public API internal static Node Copy(Command cmd, Node n) { VarMap varMap; return Copy(cmd, n, out varMap); } /// /// Make a copy of the current node. Also return an ordered list of the new /// Vars corresponding to the vars in "varList" /// /// current command /// the node to clone /// list of Vars /// list of "new" Vars /// the cloned node internal static Node Copy(Command cmd, Node node, VarList varList, out VarList newVarList) { VarMap varMap; Node newNode = Copy(cmd, node, out varMap); newVarList = Command.CreateVarList(); foreach (Var v in varList) { Var newVar = varMap[v]; newVarList.Add(newVar); } return newNode; } internal static Node Copy(Command cmd, Node n, out VarMap varMap) { OpCopier oc = new OpCopier(cmd); Node newNode = oc.CopyNode(n); varMap = oc.m_varMap; return newNode; } internal static List Copy(Command cmd, List sortKeys) { OpCopier oc = new OpCopier(cmd); return oc.Copy(sortKeys); } #endregion // WARNING // Everything below this line should be local to this class // WARNING #region Private State private Command m_srcCmd; protected Command m_destCmd; // Map of var to cloned Var protected VarMap m_varMap; #endregion #region Constructors (private) /// /// Constructor. Allows for cloning of nodes within the same command /// /// The command protected OpCopier(Command cmd) : this(cmd, cmd) {} /// /// Constructor. Allows for cloning of nodes across commands /// /// The Command to which Nodes to be cloned must belong /// The Command to which cloned Nodes will belong private OpCopier(Command destCommand, Command sourceCommand) { m_srcCmd = sourceCommand; m_destCmd = destCommand; m_varMap = new VarMap(); } #endregion #region Private State Management /// /// Get the "cloned" var for a given Var. /// If no cloned var exists, return the input Var itself /// /// The Var for which the cloned Var should be retrieved /// The cloned Var that corresponds to the specified Var if this OpCopier is cloning across two different Commands; otherwise it is safe to return the specified Var itself private Var GetMappedVar(Var v) { Var mappedVar; // // Return a mapping if there is one // if (m_varMap.TryGetValue(v, out mappedVar)) { return mappedVar; } // // No mapping found. // If we're cloning to a different command, this is an error // if (m_destCmd != m_srcCmd) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UnknownVar, 6); } // // otherwise return the current Var itself // return v; } /// /// Set the "cloned" var for a given Var /// WARNING: If a mapping already exists, an exception is raised /// /// The original Var /// The cloned Var private void SetMappedVar(Var v, Var mappedVar) { m_varMap.Add(v, mappedVar); } /// /// Maps columns of an existing table to those of the cloned table /// /// The original Table /// The cloned Table private void MapTable(Table newTable, Table oldTable) { // Map the corresponding columns of the table // Now set up the column map for (int i = 0; i < oldTable.Columns.Count; i++) { SetMappedVar(oldTable.Columns[i], newTable.Columns[i]); } } /// /// Produce the "mapped" Vars for each Var in the input sequence, while /// preserving the original order /// /// input var sequence /// output mapped vars private IEnumerable MapVars(IEnumerable vars) { foreach (Var v in vars) { Var mappedVar = GetMappedVar(v); yield return mappedVar; } } /// /// Create a mapped varvec. A new varvec that "maps" all the Vars from /// the original Varvec /// /// the varvec to clone /// a mapped varvec private VarVec Copy(VarVec vars) { VarVec newVarVec = m_destCmd.CreateVarVec(MapVars(vars)); return newVarVec; } /// /// Create a mapped copy of the input VarList - each var from the input varlist /// is represented by its mapped var (and in exactly the same order) in the output /// varlist /// /// varList to map /// mapped varlist private VarList Copy(VarList varList) { VarList newVarList = Command.CreateVarList(MapVars(varList)); return newVarList; } /// /// Copies a sortkey /// /// The SortKey to clone /// A new SortKey that is a clone of sortKey private SortKey Copy(SortKey sortKey) { return Command.CreateSortKey( GetMappedVar(sortKey.Var), sortKey.AscendingSort, sortKey.Collation ); } /// /// Copies a list of Sortkeys /// /// The list of SortKeys /// A new list containing clones of the specified SortKeys private List Copy(List sortKeys) { List newSortKeys = new List(); foreach (SortKey k in sortKeys) { newSortKeys.Add(Copy(k)); } return newSortKeys; } #endregion #region Visitor Helpers /// /// Simple wrapper for all copy operations /// /// The Node to copy /// A new Node that is a copy of the specified Node protected Node CopyNode(Node n) { return n.Op.Accept(this, n); } /// /// Copies all the Child Nodes of the specified Node /// /// The Node for which the child Nodes should be copied /// A new list containing copies of the specified Node's children private List ProcessChildren(Node n) { List children = new List(); foreach (Node chi in n.Children) { children.Add(CopyNode(chi)); } return children; } /// /// Creates a new Node with the specified Op as its Op and the result of visiting the specified Node's children as its children /// /// The Op that the new Node should reference /// The Node for which the children should be visited and the resulting cloned Nodes used as the children of the new Node returned by this method /// A new Node with the specified Op as its Op and the cloned child Nodes as its children private Node CopyDefault(Op op, Node original) { return m_destCmd.CreateNode(op, ProcessChildren(original)); } #endregion #region IOpVisitor Members /// /// Default Visitor pattern method for unrecognized Ops /// /// The unrecognized Op /// The Node that references the Op /// This method always throws NotSupportedException /// By design to indicate that the Op was not recognized and is therefore unsupported public override Node Visit(Op op, Node n) { throw new NotSupportedException(System.Data.Entity.Strings.Iqt_General_UnsupportedOp(op.GetType().FullName)); } #region ScalarOps /// /// Copies a ConstantOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ConstantOp op, Node n) { ConstantBaseOp newOp = m_destCmd.CreateConstantOp(op.Type, op.Value); return m_destCmd.CreateNode(newOp); } /// /// Copies a NullOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(NullOp op, Node n) { return m_destCmd.CreateNode(m_destCmd.CreateNullOp(op.Type)); } /// /// Copies a ConstantPredicateOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ConstantPredicateOp op, Node n) { return m_destCmd.CreateNode(m_destCmd.CreateConstantPredicateOp(op.Value)); } /// /// Copies an InternalConstantOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(InternalConstantOp op, Node n) { InternalConstantOp newOp = m_destCmd.CreateInternalConstantOp(op.Type, op.Value); return m_destCmd.CreateNode(newOp); } /// /// Copies a NullSentinelOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(NullSentinelOp op, Node n) { NullSentinelOp newOp = m_destCmd.CreateNullSentinelOp(); return m_destCmd.CreateNode(newOp); } /// /// Copies a FunctionOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(FunctionOp op, Node n) { return CopyDefault(m_destCmd.CreateFunctionOp(op.Function), n); } /// /// Copies a PropertyOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(PropertyOp op, Node n) { return CopyDefault(m_destCmd.CreatePropertyOp(op.PropertyInfo), n); } /// /// Copies a RelPropertyOp /// /// the RelPropertyOp to copy /// node tree corresponding to 'op' /// a copy of the node tree public override Node Visit(RelPropertyOp op, Node n) { return CopyDefault(m_destCmd.CreateRelPropertyOp(op.PropertyInfo), n); } /// /// Copies a CaseOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(CaseOp op, Node n) { return CopyDefault(m_destCmd.CreateCaseOp(op.Type), n); } /// /// Copies a ComparisonOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ComparisonOp op, Node n) { return CopyDefault(m_destCmd.CreateComparisonOp(op.OpType), n); } /// /// Copies a like-op /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(LikeOp op, Node n) { return CopyDefault(m_destCmd.CreateLikeOp(), n); } /// /// Clone an aggregateop /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(AggregateOp op, Node n) { return CopyDefault(m_destCmd.CreateAggregateOp(op.AggFunc, op.IsDistinctAggregate), n); } /// /// Copies a type constructor /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(NewInstanceOp op, Node n) { return CopyDefault(m_destCmd.CreateNewInstanceOp(op.Type), n); } /// /// Copies a NewEntityOp /// /// the NewEntityOp to copy /// node tree corresponding to the NewEntityOp /// a copy of the node tree public override Node Visit(NewEntityOp op, Node n) { NewEntityOp opCopy; if (op.Scoped) { opCopy = m_destCmd.CreateScopedNewEntityOp(op.Type, op.RelationshipProperties, op.EntitySet); } else { Debug.Assert(op.EntitySet == null, "op.EntitySet must be null for the constructor that hasn't been scoped yet."); opCopy = m_destCmd.CreateNewEntityOp(op.Type, op.RelationshipProperties); } return CopyDefault(opCopy, n); } /// /// Copies a discriminated type constructor /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(DiscriminatedNewEntityOp op, Node n) { return CopyDefault(m_destCmd.CreateDiscriminatedNewEntityOp(op.Type, op.DiscriminatorMap, op.EntitySet, op.RelationshipProperties), n); } /// /// Copies a multiset constructor /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(NewMultisetOp op, Node n) { return CopyDefault(m_destCmd.CreateNewMultisetOp(op.Type), n); } /// /// Copies a record constructor /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(NewRecordOp op, Node n) { return CopyDefault(m_destCmd.CreateNewRecordOp(op.Type), n); } /// /// Copies a RefOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(RefOp op, Node n) { return CopyDefault(m_destCmd.CreateRefOp(op.EntitySet, op.Type), n); } /// /// Copies a VarRefOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(VarRefOp op, Node n) { // Look up the newVar. // If no var is available in the map, that implies that the Var is defined // outside this subtree (and it is therefore safe to use it). Var newVar; if (!m_varMap.TryGetValue(op.Var, out newVar)) newVar = op.Var; // no children for a VarRef return m_destCmd.CreateNode(m_destCmd.CreateVarRefOp(newVar)); } /// /// Copies a ConditionalOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ConditionalOp op, Node n) { return CopyDefault(m_destCmd.CreateConditionalOp(op.OpType), n); } /// /// Copies an ArithmeticOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ArithmeticOp op, Node n) { return CopyDefault(m_destCmd.CreateArithmeticOp(op.OpType, op.Type), n); } /// /// Copies a TreatOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(TreatOp op, Node n) { TreatOp newTreatOp = op.IsFakeTreat ? m_destCmd.CreateFakeTreatOp(op.Type) : m_destCmd.CreateTreatOp(op.Type); return CopyDefault(newTreatOp, n); } /// /// Copies a CastOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(CastOp op, Node n) { return CopyDefault(m_destCmd.CreateCastOp(op.Type), n); } /// /// Copies a SoftCastOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(SoftCastOp op, Node n) { return CopyDefault(m_destCmd.CreateSoftCastOp(op.Type), n); } /// /// Copies a DerefOp /// /// the derefOp to copy /// the subtree /// a copy of the subtree public override Node Visit(DerefOp op, Node n) { return CopyDefault(m_destCmd.CreateDerefOp(op.Type), n); } /// /// Copies a NavigateOp /// /// the NavigateOp /// the subtree /// a copy of the subtree public override Node Visit(NavigateOp op, Node n) { return CopyDefault(m_destCmd.CreateNavigateOp(op.Type, op.RelProperty), n); } /// /// Clone an IsOfOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(IsOfOp op, Node n) { if (op.IsOfOnly) return CopyDefault(m_destCmd.CreateIsOfOnlyOp(op.IsOfType), n); else return CopyDefault(m_destCmd.CreateIsOfOp(op.IsOfType), n); } /// /// Clone an ExistsOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ExistsOp op, Node n) { return CopyDefault(m_destCmd.CreateExistsOp(), n); } /// /// Clone an ElementOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ElementOp op, Node n) { return CopyDefault(m_destCmd.CreateElementOp(op.Type), n); } /// /// Copies a GetRefKeyOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(GetRefKeyOp op, Node n) { return CopyDefault(m_destCmd.CreateGetRefKeyOp(op.Type), n); } /// /// Copies a GetEntityRefOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(GetEntityRefOp op, Node n) { return CopyDefault(m_destCmd.CreateGetEntityRefOp(op.Type), n); } /// /// Copies a CollectOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(CollectOp op, Node n) { return CopyDefault(m_destCmd.CreateCollectOp(op.Type), n); } #endregion #region RelOps /// /// Copies a ScanTableOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ScanTableOp op, Node n) { // First create a new ScanTableOp based on the metadata of the existing Op ScanTableOp newScan = m_destCmd.CreateScanTableOp(op.Table.TableMetadata); // Map the corresponding tables/columns MapTable(newScan.Table, op.Table); // Create the new node Debug.Assert(!n.HasChild0); return m_destCmd.CreateNode(newScan); } /// /// Copies a ScanViewOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ScanViewOp op, Node n) { // First create a new ScanViewOp based on the metadata of the existing Op ScanViewOp newScan = m_destCmd.CreateScanViewOp(op.Table.TableMetadata); // Map the corresponding tables/columns MapTable(newScan.Table, op.Table); // Create the new node Debug.Assert(n.HasChild0); List children = ProcessChildren(n); return m_destCmd.CreateNode(newScan, children); } /// /// Clone an UnnestOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(UnnestOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Get the mapped unnest-var Var mappedVar = GetMappedVar(op.Var); // Create a new unnestOp Table newTable = m_destCmd.CreateTableInstance(op.Table.TableMetadata); UnnestOp newUnnest = m_destCmd.CreateUnnestOp(mappedVar, newTable); // Map the corresponding tables/columns MapTable(newUnnest.Table, op.Table); // create the unnest node return m_destCmd.CreateNode(newUnnest, children); } /// /// Copies a ProjectOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ProjectOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Copy the ProjectOp's VarSet VarVec newVarSet = Copy(op.Outputs); // Create a new ProjectOp based on the copied VarSet ProjectOp newProject = m_destCmd.CreateProjectOp(newVarSet); // Return a new Node that references the copied ProjectOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newProject, children); } /// /// Copies a filterOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(FilterOp op, Node n) { return CopyDefault(m_destCmd.CreateFilterOp(), n); } /// /// Copies a sort node /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(SortOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Copy the SortOp's SortKeys List newSortKeys = Copy(op.Keys); // Create a new SortOp that uses the copied SortKeys SortOp newSortOp = m_destCmd.CreateSortOp(newSortKeys); // Return a new Node that references the copied SortOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newSortOp, children); } /// /// Copies a constrained sort node /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ConstrainedSortOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Copy the ConstrainedSortOp's SortKeys List newSortKeys = Copy(op.Keys); // Create a new ConstrainedSortOp that uses the copied SortKeys and the original Op's WithTies value ConstrainedSortOp newSortOp = m_destCmd.CreateConstrainedSortOp(newSortKeys, op.WithTies); // Return a new Node that references the copied SortOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newSortOp, children); } /// /// Copies a group-by node /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(GroupByOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Create a new GroupByOp that uses copies of the Key and Output VarSets of the original GroupByOp GroupByOp newGroupOp = m_destCmd.CreateGroupByOp(Copy(op.Keys), Copy(op.Outputs)); // Return a new Node that references the copied GroupByOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newGroupOp, children); } /// /// Copies a group by into node /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(GroupByIntoOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Create a new GroupByOp that uses copies of the Key and Output VarSets of the original GroupByOp GroupByIntoOp newGroupOp = m_destCmd.CreateGroupByIntoOp(Copy(op.Keys), Copy(op.Inputs), Copy(op.Outputs)); // Return a new Node that references the copied GroupByOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newGroupOp, children); } /// /// Copies a CrossJoinOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(CrossJoinOp op, Node n) { return CopyDefault(m_destCmd.CreateCrossJoinOp(), n); } /// /// Copies an InnerJoinOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(InnerJoinOp op, Node n) { return CopyDefault(m_destCmd.CreateInnerJoinOp(), n); } /// /// Copies a LeftOuterJoinOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(LeftOuterJoinOp op, Node n) { return CopyDefault(m_destCmd.CreateLeftOuterJoinOp(), n); } /// /// Copies a FullOuterJoinOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(FullOuterJoinOp op, Node n) { return CopyDefault(m_destCmd.CreateFullOuterJoinOp(), n); } /// /// Copies a crossApplyOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(CrossApplyOp op, Node n) { return CopyDefault(m_destCmd.CreateCrossApplyOp(), n); } /// /// Clone an OuterApplyOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(OuterApplyOp op, Node n) { return CopyDefault(m_destCmd.CreateOuterApplyOp(), n); } /// /// Common copy path for all SetOps /// /// The SetOp to Copy (must be one of ExceptOp, IntersectOp, UnionAllOp) /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op private Node CopySetOp(SetOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); VarMap leftMap = new VarMap(); VarMap rightMap = new VarMap(); foreach (KeyValuePair kv in op.VarMap[0]) { // Create a new output Var that is a copy of the original output Var Var outputVar = m_destCmd.CreateSetOpVar(kv.Key.Type); // Add a mapping for the new output var we've just created SetMappedVar(kv.Key, outputVar); // Add this output var's entries to the new VarMaps leftMap.Add(outputVar, GetMappedVar(kv.Value)); rightMap.Add(outputVar, GetMappedVar((op.VarMap[1])[kv.Key])); } SetOp newSetOp = null; switch(op.OpType) { case OpType.UnionAll: { Var branchDiscriminator = ((UnionAllOp)op).BranchDiscriminator; if (null != branchDiscriminator) { branchDiscriminator = GetMappedVar(branchDiscriminator); } newSetOp = m_destCmd.CreateUnionAllOp(leftMap, rightMap, branchDiscriminator); } break; case OpType.Intersect: { newSetOp = m_destCmd.CreateIntersectOp(leftMap, rightMap); } break; case OpType.Except: { newSetOp = m_destCmd.CreateExceptOp(leftMap, rightMap); } break; default: { Debug.Assert(false, "Unexpected SetOpType"); } break; } return m_destCmd.CreateNode(newSetOp, children); } /// /// Copies a UnionAllOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(UnionAllOp op, Node n) { return CopySetOp(op, n); } /// /// Copies an IntersectOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(IntersectOp op, Node n) { return CopySetOp(op, n); } /// /// Copies an ExceptOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(ExceptOp op, Node n) { return CopySetOp(op, n); } /// /// Copies a DistinctOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(DistinctOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Copy the DistinctOp's Keys VarVec newDistinctKeys = Copy(op.Keys); // Create a new DistinctOp that uses the copied keys DistinctOp newDistinctOp = m_destCmd.CreateDistinctOp(newDistinctKeys); // Return a new Node that references the copied DistinctOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newDistinctOp, children); } public override Node Visit(SingleRowOp op, Node n) { return CopyDefault(m_destCmd.CreateSingleRowOp(), n); } public override Node Visit(SingleRowTableOp op, Node n) { return CopyDefault(m_destCmd.CreateSingleRowTableOp(), n); } #endregion #region AncillaryOps /// /// Copies a VarDefOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(VarDefOp op, Node n) { // First create a new Var List children = ProcessChildren(n); Debug.Assert(op.Var.VarType == VarType.Computed, "Unexpected VarType"); Var newVar = m_destCmd.CreateComputedVar(op.Var.Type); SetMappedVar(op.Var, newVar); return m_destCmd.CreateNode(m_destCmd.CreateVarDefOp(newVar), children); } /// /// Copies a VarDefListOp /// /// The Op to Copy /// The Node that references the Op /// A copy of the original Node that references a copy of the original Op public override Node Visit(VarDefListOp op, Node n) { return CopyDefault(m_destCmd.CreateVarDefListOp(), n); } #endregion #region RulePatternOps #endregion #region PhysicalOps private ColumnMap Copy(ColumnMap columnMap) { return ColumnMapCopier.Copy(columnMap, m_varMap); } /// /// Copies a PhysicalProjectOp /// /// /// /// public override Node Visit(PhysicalProjectOp op, Node n) { // Visit the Node's children and map their Vars List children = ProcessChildren(n); // Copy the ProjectOp's VarSet VarList newVarList = Copy(op.Outputs); SimpleCollectionColumnMap newColumnMap = Copy(op.ColumnMap) as SimpleCollectionColumnMap; Debug.Assert(newColumnMap != null, "Coping of a physical project's columnMap did not return a SimpleCollectionColumnMap" ); // Create a new ProjectOp based on the copied VarSet PhysicalProjectOp newProject = m_destCmd.CreatePhysicalProjectOp(newVarList, newColumnMap); // Return a new Node that references the copied ProjectOp and has the copied child Nodes as its children return m_destCmd.CreateNode(newProject, children); } private Node VisitNestOp(Node n) { NestBaseOp op = n.Op as NestBaseOp; SingleStreamNestOp ssnOp = op as SingleStreamNestOp; Debug.Assert(op != null); // Visit the Node's children and map their Vars List newChildren = ProcessChildren(n); Var newDiscriminator = null; if (ssnOp != null) { newDiscriminator = GetMappedVar(ssnOp.Discriminator); } List newCollectionInfoList = new List(); foreach (CollectionInfo ci in op.CollectionInfo) { ColumnMap newColumnMap = Copy(ci.ColumnMap); Var newCollectionVar = m_destCmd.CreateComputedVar(ci.CollectionVar.Type); SetMappedVar(ci.CollectionVar, newCollectionVar); VarList newFlattendElementVars = Copy(ci.FlattenedElementVars); VarVec newKeys = Copy(ci.Keys); List newSortKeys = Copy(ci.SortKeys); CollectionInfo newCollectionInfo = Command.CreateCollectionInfo(newCollectionVar, newColumnMap, newFlattendElementVars, newKeys, newSortKeys, ci.DiscriminatorValue); newCollectionInfoList.Add(newCollectionInfo); } VarVec newOutputs = Copy(op.Outputs); NestBaseOp newOp = null; List newPrefixSortKeys = Copy(op.PrefixSortKeys); if (ssnOp != null) { VarVec newKeys = Copy(ssnOp.Keys); // Copy the SortOp's SortKeys List newPostfixSortKeys = Copy(ssnOp.PostfixSortKeys); newOp = m_destCmd.CreateSingleStreamNestOp(newKeys, newPrefixSortKeys, newPostfixSortKeys, newOutputs, newCollectionInfoList, newDiscriminator); } else { newOp = m_destCmd.CreateMultiStreamNestOp(newPrefixSortKeys, newOutputs, newCollectionInfoList); } return m_destCmd.CreateNode(newOp, newChildren); } /// /// Copies a singleStreamNestOp /// /// /// /// public override Node Visit(SingleStreamNestOp op, Node n) { return VisitNestOp(n); } /// /// Copies a multiStreamNestOp /// /// /// /// public override Node Visit(MultiStreamNestOp op, Node n) { return VisitNestOp(n); } #endregion #endregion } }