/// <summary> /// Handles a newMultiset constructor. Converts this into /// select a from dual union all select b from dual union all ... /// Handles a NewMultiset constructor, i.e. {x, y, z} /// 1. Empty multiset constructors are simply converted into: /// /// select x from singlerowtable as x where false /// /// 2. Mulltset constructors with only one element or with multiple elements all of /// which are constants or nulls are converted into: /// /// select x from dual union all select y from dual union all select z /// /// 3. All others are converted into: /// /// select case when d = 0 then x when d = 1 then y else z end /// from ( select 0 as d from single_row_table /// union all /// select 1 as d from single_row_table /// union all /// select 2 as d from single_row_table ) /// /// NOTE: The translation for 2 is valid for 3 too. We choose different translation /// in order to avoid correlation inside the union all, /// which would prevent us from removing apply operators /// /// Do this before processing the children, and then /// call Visit on the result to handle the elements /// </summary> /// <param name="op">the new instance op</param> /// <param name="n">the current subtree</param> /// <returns>the modified subtree</returns> public override Node Visit(NewMultisetOp op, Node n) { Node resultNode = null; Var resultVar = null; var collectionType = TypeHelpers.GetEdmType<CollectionType>(op.Type); // // Empty multiset constructors are simply converted into // Project(Filter(SingleRowTableOp(), false) // if (!n.HasChild0) { var singleRowTableNode = m_command.CreateNode(m_command.CreateSingleRowTableOp()); var filterNode = m_command.CreateNode( m_command.CreateFilterOp(), singleRowTableNode, m_command.CreateNode(m_command.CreateFalseOp())); var fakeChild = m_command.CreateNode(m_command.CreateNullOp(collectionType.TypeUsage)); Var newVar; var projectNode = m_command.BuildProject(filterNode, fakeChild, out newVar); resultNode = projectNode; resultVar = newVar; } // // Multiset constructors with only one elment or with multiple elments all of // which are constants or nulls are converted into: // // UnionAll(Project(SingleRowTable, e1), Project(SingleRowTable, e2), ...) // // The degenerate case when the collection has only one element does not require an // outer unionAll node // else if (n.Children.Count == 1 || AreAllConstantsOrNulls(n.Children)) { var inputNodes = new List<Node>(); var inputVars = new List<Var>(); foreach (var chi in n.Children) { var singleRowTableNode = m_command.CreateNode(m_command.CreateSingleRowTableOp()); Var newVar; var projectNode = m_command.BuildProject(singleRowTableNode, chi, out newVar); inputNodes.Add(projectNode); inputVars.Add(newVar); } // Build the union-all ladder m_command.BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out resultVar); } // // All other cases: // // select case when d = 0 then x when d = 1 then y else z end // from ( select 0 as d from single_row_table // union all // select 1 as d from single_row_table // union all // select 2 as d from single_row_table ) // else { var inputNodes = new List<Node>(); var inputVars = new List<Var>(); //Create the union all lather first for (var i = 0; i < n.Children.Count; i++) { var singleRowTableNode = m_command.CreateNode(m_command.CreateSingleRowTableOp()); // the discriminator for this branch var discriminatorNode = m_command.CreateNode(m_command.CreateInternalConstantOp(m_command.IntegerType, i)); Var newVar; var projectNode = m_command.BuildProject(singleRowTableNode, discriminatorNode, out newVar); inputNodes.Add(projectNode); inputVars.Add(newVar); } // Build the union-all ladder now m_command.BuildUnionAllLadder(inputNodes, inputVars, out resultNode, out resultVar); //Now create the case statement for the projection var caseArgNodes = new List<Node>(n.Children.Count * 2 + 1); for (var i = 0; i < n.Children.Count; i++) { //For all but the last we need a when if (i != (n.Children.Count - 1)) { var equalsOp = m_command.CreateComparisonOp(OpType.EQ); var whenNode = m_command.CreateNode( equalsOp, m_command.CreateNode(m_command.CreateVarRefOp(resultVar)), m_command.CreateNode( m_command.CreateConstantOp(m_command.IntegerType, i))); caseArgNodes.Add(whenNode); } //Add the then/else node caseArgNodes.Add(n.Children[i]); } //Create the project var caseNode = m_command.CreateNode(m_command.CreateCaseOp(collectionType.TypeUsage), caseArgNodes); resultNode = m_command.BuildProject(resultNode, caseNode, out resultVar); } // So, I've finally built up a complex query corresponding to the constructor. // Now, cap this with a physicalprojectOp, and then with a CollectOp var physicalProjectOp = m_command.CreatePhysicalProjectOp(resultVar); var physicalProjectNode = m_command.CreateNode(physicalProjectOp, resultNode); var collectOp = m_command.CreateCollectOp(op.Type); var collectNode = m_command.CreateNode(collectOp, physicalProjectNode); return VisitNode(collectNode); }
/// <summary> /// Copies a multiset constructor /// </summary> /// <param name="op">The Op to Copy</param> /// <param name="n">The Node that references the Op</param> /// <returns>A copy of the original Node that references a copy of the original Op</returns> public override Node Visit(NewMultisetOp op, Node n) { return(CopyDefault(m_destCmd.CreateNewMultisetOp(op.Type), n)); }
public override void Visit(NewMultisetOp op, Node n) { VisitNewOp(op, n); }
/// <summary> /// Visitor pattern method for NewMultisetOp /// </summary> /// <param name="op"> The NewMultisetOp being visited </param> /// <param name="n"> The Node that references the Op </param> public virtual void Visit(NewMultisetOp op, Node n) { VisitScalarOpDefault(op, n); }
// <summary> // Copies a multiset constructor // </summary> // <param name="op"> The Op to Copy </param> // <param name="n"> The Node that references the Op </param> // <returns> A copy of the original Node that references a copy of the original Op </returns> public override Node Visit(NewMultisetOp op, Node n) { return CopyDefault(m_destCmd.CreateNewMultisetOp(op.Type), n); }