/// <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); }
/// <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); }
// <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); }