/// <summary>
        /// Rewrite a NavigateOp subtree.  
        /// We call RewriteNavigateOp to return a subtree (and an optional outputVar). 
        /// If the outputVar is null, then we simply return the subtree produced by those calls. 
        /// Otherwise, we add the subtree to the "parent" relop (to be outer-applied), and then use the outputVar
        /// in its place. 
        /// 
        /// As an example, 
        ///    select navigate(e) from T
        /// gets rewritten into
        ///    select v from T OuterApply X
        /// where X is the subtree returned from the RewriteXXX calls, and "v" is the output var produced by X
        /// 
        /// </summary>
        /// <param name="op">the navigateOp</param>
        /// <param name="n">the navigateOp subtree</param>
        /// <returns>the rewritten tree</returns>
        public override Node Visit(NavigateOp op, Node n)
        {
            VisitScalarOpDefault(op, n);
            Var outputVar;
            var ret = RewriteNavigateOp(n, op, out outputVar);
            ret = VisitNode(ret);

            // Move subquery to parent relop if necessary
            if (outputVar != null)
            {
                ret = AddSubqueryToParentRelOp(outputVar, ret);
            }
            return ret;
        }
        private Node RewriteNavigateOp(Node navigateOpNode, NavigateOp navigateOp, out Var outputVar)
        {
            outputVar = null;

            //
            // Currently, navigation of composition relationships is not supported.
            //
            if (!Helper.IsAssociationType(navigateOp.Relationship))
            {
                throw new NotSupportedException(Strings.Cqt_RelNav_NoCompositions);
            }

            //
            // If the input to the navigateOp is a GetEntityRefOp, and the navigation
            // is to the 1-end of the relationship, convert this into a RelPropertyOp instead - operating on the
            // input child to the GetEntityRefOp
            //
            if (navigateOpNode.Child0.Op.OpType == OpType.GetEntityRef
                &&
                (navigateOp.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne ||
                 navigateOp.ToEnd.RelationshipMultiplicity == RelationshipMultiplicity.One))
            {
                PlanCompiler.Assert(
                    m_command.IsRelPropertyReferenced(navigateOp.RelProperty),
                    "Unreferenced rel property? " + navigateOp.RelProperty);
                Op relPropertyOp = m_command.CreateRelPropertyOp(navigateOp.RelProperty);
                var relPropertyNode = m_command.CreateNode(
                    relPropertyOp,
                    navigateOpNode.Child0.Child0);
                return relPropertyNode;
            }

            var relationshipSets = GetRelationshipSets(navigateOp.Relationship);

            //
            // Special case: when no relationshipsets can be found. Return NULL or an empty multiset,
            //   depending on the multiplicity of the toEnd
            //
            if (relationshipSets.Count == 0)
            {
                // 
                // If we're navigating to the 1-end of the relationship, then simply return a null constant
                //
                if (navigateOp.ToEnd.RelationshipMultiplicity
                    != RelationshipMultiplicity.Many)
                {
                    return m_command.CreateNode(m_command.CreateNullOp(navigateOp.Type));
                }
                else // return an empty set
                {
                    return m_command.CreateNode(m_command.CreateNewMultisetOp(navigateOp.Type));
                }
            }

            //
            // Build up a UNION-ALL ladder over all the relationshipsets
            // 
            var scanTableNodes = new List<Node>();
            var scanTableVars = new List<Var>();
            foreach (var relSet in relationshipSets)
            {
                var tableMD = Command.CreateTableDefinition(relSet);
                var tableOp = m_command.CreateScanTableOp(tableMD);
                var branchNode = m_command.CreateNode(tableOp);
                var branchVar = tableOp.Table.Columns[0];
                scanTableVars.Add(branchVar);
                scanTableNodes.Add(branchNode);
            }

            Node unionAllNode = null;
            Var unionAllVar;
            m_command.BuildUnionAllLadder(scanTableNodes, scanTableVars, out unionAllNode, out unionAllVar);

            //
            // Now build up the predicate
            //
            var targetEnd = m_command.CreateNode(
                m_command.CreatePropertyOp(navigateOp.ToEnd),
                m_command.CreateNode(m_command.CreateVarRefOp(unionAllVar)));
            var sourceEnd = m_command.CreateNode(
                m_command.CreatePropertyOp(navigateOp.FromEnd),
                m_command.CreateNode(m_command.CreateVarRefOp(unionAllVar)));
            var predicateNode = m_command.BuildComparison(OpType.EQ, navigateOpNode.Child0, sourceEnd);
            var filterNode = m_command.CreateNode(
                m_command.CreateFilterOp(),
                unionAllNode, predicateNode);
            Var projectVar;
            var projectNode = m_command.BuildProject(filterNode, targetEnd, out projectVar);

            //
            // Finally, some magic about single-valued vs collection-valued ends
            //
            Node ret;
            if (navigateOp.ToEnd.RelationshipMultiplicity
                == RelationshipMultiplicity.Many)
            {
                ret = m_command.BuildCollect(projectNode, projectVar);
            }
            else
            {
                ret = projectNode;
                outputVar = projectVar;
            }

            return ret;
        }
 public override void Visit(NavigateOp op, Node n)
 {
     VisitScalarOpDefault(op, n);
 }
示例#4
0
 /// <summary>
 /// Copies a NavigateOp
 /// </summary>
 /// <param name="op">the NavigateOp</param>
 /// <param name="n">the subtree</param>
 /// <returns>a copy of the subtree</returns>
 public override Node Visit(NavigateOp op, Node n)
 {
     return(CopyDefault(m_destCmd.CreateNavigateOp(op.Type, op.RelProperty), n));
 }
 public virtual void Visit(NavigateOp op, Node n)
 {
     VisitScalarOpDefault(op, n);
 }
示例#6
0
 // <summary>
 // Copies a NavigateOp
 // </summary>
 // <param name="op"> the NavigateOp </param>
 // <param name="n"> the subtree </param>
 // <returns> a copy of the subtree </returns>
 public override Node Visit(NavigateOp op, Node n)
 {
     return CopyDefault(m_destCmd.CreateNavigateOp(op.Type, op.RelProperty), n);
 }
示例#7
0
 public override void Visit(NavigateOp op, Node n)
 {
     VisitScalarOpDefault(op, n);
 }