/// <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);
        }
Exemple #2
0
 /// <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));
 }
Exemple #3
0
 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);
 }
Exemple #5
0
 // <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);
 }