1 //---------------------------------------------------------------------
2 // <copyright file="OpCopier.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 // Interesting cases: Unnest
11 // More generally, note that any subtree that is left-correlated will stay as such.
14 namespace System.Data.Query.InternalTrees
17 using System.Collections.Generic;
18 using System.Diagnostics;
21 /// Handles copying of operators
23 internal class OpCopier : BasicOpVisitorOfNode
25 #region (pseudo) Public API
26 internal static Node Copy(Command cmd, Node n)
29 return Copy(cmd, n, out varMap);
33 /// Make a copy of the current node. Also return an ordered list of the new
34 /// Vars corresponding to the vars in "varList"
36 /// <param name="cmd">current command</param>
37 /// <param name="node">the node to clone</param>
38 /// <param name="varList">list of Vars</param>
39 /// <param name="newVarList">list of "new" Vars</param>
40 /// <returns>the cloned node</returns>
41 internal static Node Copy(Command cmd, Node node, VarList varList, out VarList newVarList)
44 Node newNode = Copy(cmd, node, out varMap);
45 newVarList = Command.CreateVarList();
46 foreach (Var v in varList)
48 Var newVar = varMap[v];
49 newVarList.Add(newVar);
54 internal static Node Copy(Command cmd, Node n, out VarMap varMap)
56 OpCopier oc = new OpCopier(cmd);
57 Node newNode = oc.CopyNode(n);
62 internal static List<SortKey> Copy(Command cmd, List<SortKey> sortKeys)
64 OpCopier oc = new OpCopier(cmd);
65 return oc.Copy(sortKeys);
70 // Everything below this line should be local to this class
74 private Command m_srcCmd;
75 protected Command m_destCmd;
76 // Map of var to cloned Var
77 protected VarMap m_varMap;
80 #region Constructors (private)
82 /// Constructor. Allows for cloning of nodes within the same command
84 /// <param name="cmd">The command</param>
85 protected OpCopier(Command cmd) : this(cmd, cmd) {}
88 /// Constructor. Allows for cloning of nodes across commands
90 /// <param name="destCommand">The Command to which Nodes to be cloned must belong</param>
91 /// <param name="sourceCommand">The Command to which cloned Nodes will belong</param>
92 private OpCopier(Command destCommand, Command sourceCommand)
94 m_srcCmd = sourceCommand;
95 m_destCmd = destCommand;
96 m_varMap = new VarMap();
100 #region Private State Management
103 /// Get the "cloned" var for a given Var.
104 /// If no cloned var exists, return the input Var itself
106 /// <param name="v">The Var for which the cloned Var should be retrieved</param>
107 /// <returns>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</returns>
108 private Var GetMappedVar(Var v)
113 // Return a mapping if there is one
115 if (m_varMap.TryGetValue(v, out mappedVar))
122 // If we're cloning to a different command, this is an error
124 if (m_destCmd != m_srcCmd)
126 throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UnknownVar, 6);
130 // otherwise return the current Var itself
136 /// Set the "cloned" var for a given Var
137 /// WARNING: If a mapping already exists, an exception is raised
139 /// <param name="v">The original Var</param>
140 /// <param name="mappedVar">The cloned Var</param>
141 private void SetMappedVar(Var v, Var mappedVar)
143 m_varMap.Add(v, mappedVar);
147 /// Maps columns of an existing table to those of the cloned table
149 /// <param name="newTable">The original Table</param>
150 /// <param name="oldTable">The cloned Table</param>
151 private void MapTable(Table newTable, Table oldTable)
153 // Map the corresponding columns of the table
154 // Now set up the column map
155 for (int i = 0; i < oldTable.Columns.Count; i++)
157 SetMappedVar(oldTable.Columns[i], newTable.Columns[i]);
162 /// Produce the "mapped" Vars for each Var in the input sequence, while
163 /// preserving the original order
165 /// <param name="vars">input var sequence</param>
166 /// <returns>output mapped vars</returns>
167 private IEnumerable<Var> MapVars(IEnumerable<Var> vars)
169 foreach (Var v in vars)
171 Var mappedVar = GetMappedVar(v);
172 yield return mappedVar;
177 /// Create a mapped varvec. A new varvec that "maps" all the Vars from
178 /// the original Varvec
180 /// <param name="vars">the varvec to clone</param>
181 /// <returns>a mapped varvec</returns>
182 private VarVec Copy(VarVec vars)
184 VarVec newVarVec = m_destCmd.CreateVarVec(MapVars(vars));
189 /// Create a mapped copy of the input VarList - each var from the input varlist
190 /// is represented by its mapped var (and in exactly the same order) in the output
193 /// <param name="varList">varList to map</param>
194 /// <returns>mapped varlist</returns>
195 private VarList Copy(VarList varList)
197 VarList newVarList = Command.CreateVarList(MapVars(varList));
204 /// <param name="sortKey">The SortKey to clone</param>
205 /// <returns>A new SortKey that is a clone of sortKey</returns>
206 private SortKey Copy(SortKey sortKey)
208 return Command.CreateSortKey(
209 GetMappedVar(sortKey.Var),
210 sortKey.AscendingSort,
216 /// Copies a list of Sortkeys
218 /// <param name="sortKeys">The list of SortKeys</param>
219 /// <returns>A new list containing clones of the specified SortKeys</returns>
220 private List<SortKey> Copy(List<SortKey> sortKeys)
222 List<SortKey> newSortKeys = new List<SortKey>();
223 foreach (SortKey k in sortKeys)
225 newSortKeys.Add(Copy(k));
232 #region Visitor Helpers
235 /// Simple wrapper for all copy operations
237 /// <param name="n">The Node to copy</param>
238 /// <returns>A new Node that is a copy of the specified Node</returns>
239 protected Node CopyNode(Node n)
241 return n.Op.Accept<Node>(this, n);
245 /// Copies all the Child Nodes of the specified Node
247 /// <param name="n">The Node for which the child Nodes should be copied</param>
248 /// <returns>A new list containing copies of the specified Node's children</returns>
249 private List<Node> ProcessChildren(Node n)
251 List<Node> children = new List<Node>();
252 foreach (Node chi in n.Children)
254 children.Add(CopyNode(chi));
260 /// Creates a new Node with the specified Op as its Op and the result of visiting the specified Node's children as its children
262 /// <param name="op">The Op that the new Node should reference</param>
263 /// <param name="original">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</param>
264 /// <returns>A new Node with the specified Op as its Op and the cloned child Nodes as its children</returns>
265 private Node CopyDefault(Op op, Node original)
267 return m_destCmd.CreateNode(op, ProcessChildren(original));
271 #region IOpVisitor<Node> Members
274 /// Default Visitor pattern method for unrecognized Ops
276 /// <param name="op">The unrecognized Op</param>
277 /// <param name="n">The Node that references the Op</param>
278 /// <returns>This method always throws NotSupportedException</returns>
279 /// <exception cref="NotSupportedException">By design to indicate that the Op was not recognized and is therefore unsupported</exception>
280 public override Node Visit(Op op, Node n)
282 throw new NotSupportedException(System.Data.Entity.Strings.Iqt_General_UnsupportedOp(op.GetType().FullName));
288 /// Copies a ConstantOp
290 /// <param name="op">The Op to Copy</param>
291 /// <param name="n">The Node that references the Op</param>
292 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
293 public override Node Visit(ConstantOp op, Node n)
295 ConstantBaseOp newOp = m_destCmd.CreateConstantOp(op.Type, op.Value);
296 return m_destCmd.CreateNode(newOp);
302 /// <param name="op">The Op to Copy</param>
303 /// <param name="n">The Node that references the Op</param>
304 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
305 public override Node Visit(NullOp op, Node n)
307 return m_destCmd.CreateNode(m_destCmd.CreateNullOp(op.Type));
311 /// Copies a ConstantPredicateOp
313 /// <param name="op">The Op to Copy</param>
314 /// <param name="n">The Node that references the Op</param>
315 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
316 public override Node Visit(ConstantPredicateOp op, Node n)
318 return m_destCmd.CreateNode(m_destCmd.CreateConstantPredicateOp(op.Value));
322 /// Copies an InternalConstantOp
324 /// <param name="op">The Op to Copy</param>
325 /// <param name="n">The Node that references the Op</param>
326 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
327 public override Node Visit(InternalConstantOp op, Node n)
329 InternalConstantOp newOp = m_destCmd.CreateInternalConstantOp(op.Type, op.Value);
330 return m_destCmd.CreateNode(newOp);
334 /// Copies a NullSentinelOp
336 /// <param name="op">The Op to Copy</param>
337 /// <param name="n">The Node that references the Op</param>
338 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
339 public override Node Visit(NullSentinelOp op, Node n)
341 NullSentinelOp newOp = m_destCmd.CreateNullSentinelOp();
342 return m_destCmd.CreateNode(newOp);
346 /// Copies a FunctionOp
348 /// <param name="op">The Op to Copy</param>
349 /// <param name="n">The Node that references the Op</param>
350 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
351 public override Node Visit(FunctionOp op, Node n)
353 return CopyDefault(m_destCmd.CreateFunctionOp(op.Function), n);
357 /// Copies a PropertyOp
359 /// <param name="op">The Op to Copy</param>
360 /// <param name="n">The Node that references the Op</param>
361 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
362 public override Node Visit(PropertyOp op, Node n)
364 return CopyDefault(m_destCmd.CreatePropertyOp(op.PropertyInfo), n);
368 /// Copies a RelPropertyOp
370 /// <param name="op">the RelPropertyOp to copy</param>
371 /// <param name="n">node tree corresponding to 'op'</param>
372 /// <returns>a copy of the node tree</returns>
373 public override Node Visit(RelPropertyOp op, Node n)
375 return CopyDefault(m_destCmd.CreateRelPropertyOp(op.PropertyInfo), n);
381 /// <param name="op">The Op to Copy</param>
382 /// <param name="n">The Node that references the Op</param>
383 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
384 public override Node Visit(CaseOp op, Node n)
386 return CopyDefault(m_destCmd.CreateCaseOp(op.Type), n);
390 /// Copies a ComparisonOp
392 /// <param name="op">The Op to Copy</param>
393 /// <param name="n">The Node that references the Op</param>
394 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
395 public override Node Visit(ComparisonOp op, Node n)
397 return CopyDefault(m_destCmd.CreateComparisonOp(op.OpType), n);
403 /// <param name="op">The Op to Copy</param>
404 /// <param name="n">The Node that references the Op</param>
405 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
406 public override Node Visit(LikeOp op, Node n)
408 return CopyDefault(m_destCmd.CreateLikeOp(), n);
412 /// Clone an aggregateop
414 /// <param name="op">The Op to Copy</param>
415 /// <param name="n">The Node that references the Op</param>
416 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
417 public override Node Visit(AggregateOp op, Node n)
419 return CopyDefault(m_destCmd.CreateAggregateOp(op.AggFunc, op.IsDistinctAggregate), n);
423 /// Copies a type constructor
425 /// <param name="op">The Op to Copy</param>
426 /// <param name="n">The Node that references the Op</param>
427 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
428 public override Node Visit(NewInstanceOp op, Node n)
430 return CopyDefault(m_destCmd.CreateNewInstanceOp(op.Type), n);
434 /// Copies a NewEntityOp
436 /// <param name="op">the NewEntityOp to copy</param>
437 /// <param name="n">node tree corresponding to the NewEntityOp</param>
438 /// <returns>a copy of the node tree</returns>
439 public override Node Visit(NewEntityOp op, Node n)
444 opCopy = m_destCmd.CreateScopedNewEntityOp(op.Type, op.RelationshipProperties, op.EntitySet);
448 Debug.Assert(op.EntitySet == null, "op.EntitySet must be null for the constructor that hasn't been scoped yet.");
449 opCopy = m_destCmd.CreateNewEntityOp(op.Type, op.RelationshipProperties);
451 return CopyDefault(opCopy, n);
455 /// Copies a discriminated type constructor
457 /// <param name="op">The Op to Copy</param>
458 /// <param name="n">The Node that references the Op</param>
459 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
460 public override Node Visit(DiscriminatedNewEntityOp op, Node n)
462 return CopyDefault(m_destCmd.CreateDiscriminatedNewEntityOp(op.Type, op.DiscriminatorMap, op.EntitySet, op.RelationshipProperties), n);
466 /// Copies a multiset constructor
468 /// <param name="op">The Op to Copy</param>
469 /// <param name="n">The Node that references the Op</param>
470 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
471 public override Node Visit(NewMultisetOp op, Node n)
473 return CopyDefault(m_destCmd.CreateNewMultisetOp(op.Type), n);
477 /// Copies a record constructor
479 /// <param name="op">The Op to Copy</param>
480 /// <param name="n">The Node that references the Op</param>
481 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
482 public override Node Visit(NewRecordOp op, Node n)
484 return CopyDefault(m_destCmd.CreateNewRecordOp(op.Type), n);
490 /// <param name="op">The Op to Copy</param>
491 /// <param name="n">The Node that references the Op</param>
492 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
493 public override Node Visit(RefOp op, Node n)
495 return CopyDefault(m_destCmd.CreateRefOp(op.EntitySet, op.Type), n);
499 /// Copies a VarRefOp
501 /// <param name="op">The Op to Copy</param>
502 /// <param name="n">The Node that references the Op</param>
503 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
504 public override Node Visit(VarRefOp op, Node n)
506 // Look up the newVar.
507 // If no var is available in the map, that implies that the Var is defined
508 // outside this subtree (and it is therefore safe to use it).
510 if (!m_varMap.TryGetValue(op.Var, out newVar))
512 // no children for a VarRef
513 return m_destCmd.CreateNode(m_destCmd.CreateVarRefOp(newVar));
517 /// Copies a ConditionalOp
519 /// <param name="op">The Op to Copy</param>
520 /// <param name="n">The Node that references the Op</param>
521 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
522 public override Node Visit(ConditionalOp op, Node n)
524 return CopyDefault(m_destCmd.CreateConditionalOp(op.OpType), n);
528 /// Copies an ArithmeticOp
530 /// <param name="op">The Op to Copy</param>
531 /// <param name="n">The Node that references the Op</param>
532 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
533 public override Node Visit(ArithmeticOp op, Node n)
535 return CopyDefault(m_destCmd.CreateArithmeticOp(op.OpType, op.Type), n);
541 /// <param name="op">The Op to Copy</param>
542 /// <param name="n">The Node that references the Op</param>
543 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
544 public override Node Visit(TreatOp op, Node n)
546 TreatOp newTreatOp = op.IsFakeTreat ? m_destCmd.CreateFakeTreatOp(op.Type) : m_destCmd.CreateTreatOp(op.Type);
547 return CopyDefault(newTreatOp, n);
553 /// <param name="op">The Op to Copy</param>
554 /// <param name="n">The Node that references the Op</param>
555 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
556 public override Node Visit(CastOp op, Node n)
558 return CopyDefault(m_destCmd.CreateCastOp(op.Type), n);
562 /// Copies a SoftCastOp
564 /// <param name="op">The Op to Copy</param>
565 /// <param name="n">The Node that references the Op</param>
566 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
567 public override Node Visit(SoftCastOp op, Node n)
569 return CopyDefault(m_destCmd.CreateSoftCastOp(op.Type), n);
575 /// <param name="op">the derefOp to copy</param>
576 /// <param name="n">the subtree</param>
577 /// <returns>a copy of the subtree</returns>
578 public override Node Visit(DerefOp op, Node n)
580 return CopyDefault(m_destCmd.CreateDerefOp(op.Type), n);
584 /// Copies a NavigateOp
586 /// <param name="op">the NavigateOp</param>
587 /// <param name="n">the subtree</param>
588 /// <returns>a copy of the subtree</returns>
589 public override Node Visit(NavigateOp op, Node n)
591 return CopyDefault(m_destCmd.CreateNavigateOp(op.Type, op.RelProperty), n);
597 /// <param name="op">The Op to Copy</param>
598 /// <param name="n">The Node that references the Op</param>
599 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
600 public override Node Visit(IsOfOp op, Node n)
603 return CopyDefault(m_destCmd.CreateIsOfOnlyOp(op.IsOfType), n);
605 return CopyDefault(m_destCmd.CreateIsOfOp(op.IsOfType), n);
609 /// Clone an ExistsOp
611 /// <param name="op">The Op to Copy</param>
612 /// <param name="n">The Node that references the Op</param>
613 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
614 public override Node Visit(ExistsOp op, Node n)
616 return CopyDefault(m_destCmd.CreateExistsOp(), n);
620 /// Clone an ElementOp
622 /// <param name="op">The Op to Copy</param>
623 /// <param name="n">The Node that references the Op</param>
624 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
625 public override Node Visit(ElementOp op, Node n)
627 return CopyDefault(m_destCmd.CreateElementOp(op.Type), n);
631 /// Copies a GetRefKeyOp
633 /// <param name="op">The Op to Copy</param>
634 /// <param name="n">The Node that references the Op</param>
635 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
636 public override Node Visit(GetRefKeyOp op, Node n)
638 return CopyDefault(m_destCmd.CreateGetRefKeyOp(op.Type), n);
642 /// Copies a GetEntityRefOp
644 /// <param name="op">The Op to Copy</param>
645 /// <param name="n">The Node that references the Op</param>
646 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
647 public override Node Visit(GetEntityRefOp op, Node n)
649 return CopyDefault(m_destCmd.CreateGetEntityRefOp(op.Type), n);
653 /// Copies a CollectOp
655 /// <param name="op">The Op to Copy</param>
656 /// <param name="n">The Node that references the Op</param>
657 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
658 public override Node Visit(CollectOp op, Node n)
660 return CopyDefault(m_destCmd.CreateCollectOp(op.Type), n);
668 /// Copies a ScanTableOp
670 /// <param name="op">The Op to Copy</param>
671 /// <param name="n">The Node that references the Op</param>
672 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
673 public override Node Visit(ScanTableOp op, Node n)
675 // First create a new ScanTableOp based on the metadata of the existing Op
676 ScanTableOp newScan = m_destCmd.CreateScanTableOp(op.Table.TableMetadata);
677 // Map the corresponding tables/columns
678 MapTable(newScan.Table, op.Table);
680 // Create the new node
681 Debug.Assert(!n.HasChild0);
682 return m_destCmd.CreateNode(newScan);
686 /// Copies a ScanViewOp
688 /// <param name="op">The Op to Copy</param>
689 /// <param name="n">The Node that references the Op</param>
690 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
691 public override Node Visit(ScanViewOp op, Node n)
693 // First create a new ScanViewOp based on the metadata of the existing Op
694 ScanViewOp newScan = m_destCmd.CreateScanViewOp(op.Table.TableMetadata);
695 // Map the corresponding tables/columns
696 MapTable(newScan.Table, op.Table);
698 // Create the new node
699 Debug.Assert(n.HasChild0);
700 List<Node> children = ProcessChildren(n);
701 return m_destCmd.CreateNode(newScan, children);
705 /// Clone an UnnestOp
707 /// <param name="op">The Op to Copy</param>
708 /// <param name="n">The Node that references the Op</param>
709 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
710 public override Node Visit(UnnestOp op, Node n)
712 // Visit the Node's children and map their Vars
713 List<Node> children = ProcessChildren(n);
715 // Get the mapped unnest-var
716 Var mappedVar = GetMappedVar(op.Var);
718 // Create a new unnestOp
719 Table newTable = m_destCmd.CreateTableInstance(op.Table.TableMetadata);
720 UnnestOp newUnnest = m_destCmd.CreateUnnestOp(mappedVar, newTable);
722 // Map the corresponding tables/columns
723 MapTable(newUnnest.Table, op.Table);
725 // create the unnest node
726 return m_destCmd.CreateNode(newUnnest, children);
730 /// Copies a ProjectOp
732 /// <param name="op">The Op to Copy</param>
733 /// <param name="n">The Node that references the Op</param>
734 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
735 public override Node Visit(ProjectOp op, Node n)
737 // Visit the Node's children and map their Vars
738 List<Node> children = ProcessChildren(n);
740 // Copy the ProjectOp's VarSet
741 VarVec newVarSet = Copy(op.Outputs);
743 // Create a new ProjectOp based on the copied VarSet
744 ProjectOp newProject = m_destCmd.CreateProjectOp(newVarSet);
746 // Return a new Node that references the copied ProjectOp and has the copied child Nodes as its children
747 return m_destCmd.CreateNode(newProject, children);
751 /// Copies a filterOp
753 /// <param name="op">The Op to Copy</param>
754 /// <param name="n">The Node that references the Op</param>
755 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
756 public override Node Visit(FilterOp op, Node n)
758 return CopyDefault(m_destCmd.CreateFilterOp(), n);
762 /// Copies a sort node
764 /// <param name="op">The Op to Copy</param>
765 /// <param name="n">The Node that references the Op</param>
766 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
767 public override Node Visit(SortOp op, Node n)
769 // Visit the Node's children and map their Vars
770 List<Node> children = ProcessChildren(n);
772 // Copy the SortOp's SortKeys
773 List<SortKey> newSortKeys = Copy(op.Keys);
775 // Create a new SortOp that uses the copied SortKeys
776 SortOp newSortOp = m_destCmd.CreateSortOp(newSortKeys);
778 // Return a new Node that references the copied SortOp and has the copied child Nodes as its children
779 return m_destCmd.CreateNode(newSortOp, children);
783 /// Copies a constrained sort node
785 /// <param name="op">The Op to Copy</param>
786 /// <param name="n">The Node that references the Op</param>
787 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
788 public override Node Visit(ConstrainedSortOp op, Node n)
790 // Visit the Node's children and map their Vars
791 List<Node> children = ProcessChildren(n);
793 // Copy the ConstrainedSortOp's SortKeys
794 List<SortKey> newSortKeys = Copy(op.Keys);
796 // Create a new ConstrainedSortOp that uses the copied SortKeys and the original Op's WithTies value
797 ConstrainedSortOp newSortOp = m_destCmd.CreateConstrainedSortOp(newSortKeys, op.WithTies);
799 // Return a new Node that references the copied SortOp and has the copied child Nodes as its children
800 return m_destCmd.CreateNode(newSortOp, children);
804 /// Copies a group-by node
806 /// <param name="op">The Op to Copy</param>
807 /// <param name="n">The Node that references the Op</param>
808 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
809 public override Node Visit(GroupByOp op, Node n)
811 // Visit the Node's children and map their Vars
812 List<Node> children = ProcessChildren(n);
814 // Create a new GroupByOp that uses copies of the Key and Output VarSets of the original GroupByOp
815 GroupByOp newGroupOp = m_destCmd.CreateGroupByOp(Copy(op.Keys), Copy(op.Outputs));
817 // Return a new Node that references the copied GroupByOp and has the copied child Nodes as its children
818 return m_destCmd.CreateNode(newGroupOp, children);
822 /// Copies a group by into node
824 /// <param name="op">The Op to Copy</param>
825 /// <param name="n">The Node that references the Op</param>
826 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
827 public override Node Visit(GroupByIntoOp op, Node n)
829 // Visit the Node's children and map their Vars
830 List<Node> children = ProcessChildren(n);
832 // Create a new GroupByOp that uses copies of the Key and Output VarSets of the original GroupByOp
833 GroupByIntoOp newGroupOp = m_destCmd.CreateGroupByIntoOp(Copy(op.Keys), Copy(op.Inputs), Copy(op.Outputs));
835 // Return a new Node that references the copied GroupByOp and has the copied child Nodes as its children
836 return m_destCmd.CreateNode(newGroupOp, children);
840 /// Copies a CrossJoinOp
842 /// <param name="op">The Op to Copy</param>
843 /// <param name="n">The Node that references the Op</param>
844 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
845 public override Node Visit(CrossJoinOp op, Node n)
847 return CopyDefault(m_destCmd.CreateCrossJoinOp(), n);
851 /// Copies an InnerJoinOp
853 /// <param name="op">The Op to Copy</param>
854 /// <param name="n">The Node that references the Op</param>
855 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
856 public override Node Visit(InnerJoinOp op, Node n)
858 return CopyDefault(m_destCmd.CreateInnerJoinOp(), n);
862 /// Copies a LeftOuterJoinOp
864 /// <param name="op">The Op to Copy</param>
865 /// <param name="n">The Node that references the Op</param>
866 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
867 public override Node Visit(LeftOuterJoinOp op, Node n)
869 return CopyDefault(m_destCmd.CreateLeftOuterJoinOp(), n);
873 /// Copies a FullOuterJoinOp
875 /// <param name="op">The Op to Copy</param>
876 /// <param name="n">The Node that references the Op</param>
877 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
878 public override Node Visit(FullOuterJoinOp op, Node n)
880 return CopyDefault(m_destCmd.CreateFullOuterJoinOp(), n);
884 /// Copies a crossApplyOp
886 /// <param name="op">The Op to Copy</param>
887 /// <param name="n">The Node that references the Op</param>
888 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
889 public override Node Visit(CrossApplyOp op, Node n)
891 return CopyDefault(m_destCmd.CreateCrossApplyOp(), n);
895 /// Clone an OuterApplyOp
897 /// <param name="op">The Op to Copy</param>
898 /// <param name="n">The Node that references the Op</param>
899 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
900 public override Node Visit(OuterApplyOp op, Node n)
902 return CopyDefault(m_destCmd.CreateOuterApplyOp(), n);
906 /// Common copy path for all SetOps
908 /// <param name="op">The SetOp to Copy (must be one of ExceptOp, IntersectOp, UnionAllOp)</param>
909 /// <param name="n">The Node that references the Op</param>
910 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
911 private Node CopySetOp(SetOp op, Node n)
913 // Visit the Node's children and map their Vars
914 List<Node> children = ProcessChildren(n);
916 VarMap leftMap = new VarMap();
917 VarMap rightMap = new VarMap();
920 foreach (KeyValuePair<Var, Var> kv in op.VarMap[0])
922 // Create a new output Var that is a copy of the original output Var
923 Var outputVar = m_destCmd.CreateSetOpVar(kv.Key.Type);
925 // Add a mapping for the new output var we've just created
926 SetMappedVar(kv.Key, outputVar);
928 // Add this output var's entries to the new VarMaps
929 leftMap.Add(outputVar, GetMappedVar(kv.Value));
930 rightMap.Add(outputVar, GetMappedVar((op.VarMap[1])[kv.Key]));
933 SetOp newSetOp = null;
936 case OpType.UnionAll:
938 Var branchDiscriminator = ((UnionAllOp)op).BranchDiscriminator;
939 if (null != branchDiscriminator)
941 branchDiscriminator = GetMappedVar(branchDiscriminator);
943 newSetOp = m_destCmd.CreateUnionAllOp(leftMap, rightMap, branchDiscriminator);
947 case OpType.Intersect:
949 newSetOp = m_destCmd.CreateIntersectOp(leftMap, rightMap);
955 newSetOp = m_destCmd.CreateExceptOp(leftMap, rightMap);
961 Debug.Assert(false, "Unexpected SetOpType");
966 return m_destCmd.CreateNode(newSetOp, children);
970 /// Copies a UnionAllOp
972 /// <param name="op">The Op to Copy</param>
973 /// <param name="n">The Node that references the Op</param>
974 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
975 public override Node Visit(UnionAllOp op, Node n)
977 return CopySetOp(op, n);
981 /// Copies an IntersectOp
983 /// <param name="op">The Op to Copy</param>
984 /// <param name="n">The Node that references the Op</param>
985 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
986 public override Node Visit(IntersectOp op, Node n)
988 return CopySetOp(op, n);
992 /// Copies an ExceptOp
994 /// <param name="op">The Op to Copy</param>
995 /// <param name="n">The Node that references the Op</param>
996 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
997 public override Node Visit(ExceptOp op, Node n)
999 return CopySetOp(op, n);
1003 /// Copies a DistinctOp
1005 /// <param name="op">The Op to Copy</param>
1006 /// <param name="n">The Node that references the Op</param>
1007 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
1008 public override Node Visit(DistinctOp op, Node n)
1010 // Visit the Node's children and map their Vars
1011 List<Node> children = ProcessChildren(n);
1013 // Copy the DistinctOp's Keys
1014 VarVec newDistinctKeys = Copy(op.Keys);
1016 // Create a new DistinctOp that uses the copied keys
1017 DistinctOp newDistinctOp = m_destCmd.CreateDistinctOp(newDistinctKeys);
1019 // Return a new Node that references the copied DistinctOp and has the copied child Nodes as its children
1020 return m_destCmd.CreateNode(newDistinctOp, children);
1023 public override Node Visit(SingleRowOp op, Node n)
1025 return CopyDefault(m_destCmd.CreateSingleRowOp(), n);
1028 public override Node Visit(SingleRowTableOp op, Node n)
1030 return CopyDefault(m_destCmd.CreateSingleRowTableOp(), n);
1035 #region AncillaryOps
1037 /// Copies a VarDefOp
1039 /// <param name="op">The Op to Copy</param>
1040 /// <param name="n">The Node that references the Op</param>
1041 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
1042 public override Node Visit(VarDefOp op, Node n)
1044 // First create a new Var
1045 List<Node> children = ProcessChildren(n);
1046 Debug.Assert(op.Var.VarType == VarType.Computed, "Unexpected VarType");
1047 Var newVar = m_destCmd.CreateComputedVar(op.Var.Type);
1048 SetMappedVar(op.Var, newVar);
1049 return m_destCmd.CreateNode(m_destCmd.CreateVarDefOp(newVar), children);
1053 /// Copies a VarDefListOp
1055 /// <param name="op">The Op to Copy</param>
1056 /// <param name="n">The Node that references the Op</param>
1057 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
1058 public override Node Visit(VarDefListOp op, Node n)
1060 return CopyDefault(m_destCmd.CreateVarDefListOp(), n);
1064 #region RulePatternOps
1068 private ColumnMap Copy(ColumnMap columnMap)
1070 return ColumnMapCopier.Copy(columnMap, m_varMap);
1074 /// Copies a PhysicalProjectOp
1076 /// <param name="op"></param>
1077 /// <param name="n"></param>
1078 /// <returns></returns>
1079 public override Node Visit(PhysicalProjectOp op, Node n)
1081 // Visit the Node's children and map their Vars
1082 List<Node> children = ProcessChildren(n);
1084 // Copy the ProjectOp's VarSet
1085 VarList newVarList = Copy(op.Outputs);
1087 SimpleCollectionColumnMap newColumnMap = Copy(op.ColumnMap) as SimpleCollectionColumnMap;
1088 Debug.Assert(newColumnMap != null, "Coping of a physical project's columnMap did not return a SimpleCollectionColumnMap" );
1089 // Create a new ProjectOp based on the copied VarSet
1090 PhysicalProjectOp newProject = m_destCmd.CreatePhysicalProjectOp(newVarList, newColumnMap);
1092 // Return a new Node that references the copied ProjectOp and has the copied child Nodes as its children
1093 return m_destCmd.CreateNode(newProject, children);
1096 private Node VisitNestOp(Node n)
1098 NestBaseOp op = n.Op as NestBaseOp;
1099 SingleStreamNestOp ssnOp = op as SingleStreamNestOp;
1100 Debug.Assert(op != null);
1102 // Visit the Node's children and map their Vars
1103 List<Node> newChildren = ProcessChildren(n);
1105 Var newDiscriminator = null;
1108 newDiscriminator = GetMappedVar(ssnOp.Discriminator);
1110 List<CollectionInfo> newCollectionInfoList = new List<CollectionInfo>();
1111 foreach (CollectionInfo ci in op.CollectionInfo)
1113 ColumnMap newColumnMap = Copy(ci.ColumnMap);
1115 Var newCollectionVar = m_destCmd.CreateComputedVar(ci.CollectionVar.Type);
1116 SetMappedVar(ci.CollectionVar, newCollectionVar);
1118 VarList newFlattendElementVars = Copy(ci.FlattenedElementVars);
1119 VarVec newKeys = Copy(ci.Keys);
1120 List<SortKey> newSortKeys = Copy(ci.SortKeys);
1121 CollectionInfo newCollectionInfo = Command.CreateCollectionInfo(newCollectionVar, newColumnMap, newFlattendElementVars, newKeys, newSortKeys, ci.DiscriminatorValue);
1122 newCollectionInfoList.Add(newCollectionInfo);
1125 VarVec newOutputs = Copy(op.Outputs);
1127 NestBaseOp newOp = null;
1128 List<SortKey> newPrefixSortKeys = Copy(op.PrefixSortKeys);
1131 VarVec newKeys = Copy(ssnOp.Keys);
1132 // Copy the SortOp's SortKeys
1133 List<SortKey> newPostfixSortKeys = Copy(ssnOp.PostfixSortKeys);
1134 newOp = m_destCmd.CreateSingleStreamNestOp(newKeys, newPrefixSortKeys, newPostfixSortKeys, newOutputs, newCollectionInfoList, newDiscriminator);
1138 newOp = m_destCmd.CreateMultiStreamNestOp(newPrefixSortKeys, newOutputs, newCollectionInfoList);
1141 return m_destCmd.CreateNode(newOp, newChildren);
1145 /// Copies a singleStreamNestOp
1147 /// <param name="op"></param>
1148 /// <param name="n"></param>
1149 /// <returns></returns>
1150 public override Node Visit(SingleStreamNestOp op, Node n)
1152 return VisitNestOp(n);
1156 /// Copies a multiStreamNestOp
1158 /// <param name="op"></param>
1159 /// <param name="n"></param>
1160 /// <returns></returns>
1161 public override Node Visit(MultiStreamNestOp op, Node n)
1163 return VisitNestOp(n);