public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { Visit(node.Left); Visit(node.Right); node.OuterReferences = AstUtil.GetOuterReferences(node); return(node); }
public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { node.Left = VisitAlgebraNode(node.Left); RowBufferEntry[] outerReferences = AstUtil.GetOuterReferences(node); if (outerReferences != null && outerReferences.Length > 0) { _outerReferences.Push(node.OuterReferences); } node.Right = VisitAlgebraNode(node.Right); if (outerReferences != null && outerReferences.Length > 0) { _outerReferences.Pop(); } return(node); }
public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { // Get declared tables of left and right RowBufferEntry[] leftDefinedValues = AstUtil.GetDefinedValueEntries(node.Left); RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(node.Right); // Replace outer joins by left-/right-/inner joins if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin || node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin) { if (IsAnyNullRejected(leftDefinedValues)) { if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin) { node.Op = JoinAlgebraNode.JoinOperator.InnerJoin; } else { node.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin; } } } if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin || node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin) { if (IsAnyNullRejected(rightDefinedValues)) { if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin) { node.Op = JoinAlgebraNode.JoinOperator.InnerJoin; } else { node.Op = JoinAlgebraNode.JoinOperator.RightOuterJoin; } } } // After converting an outer join to an inner one we can // sometimes eliminate the whole join. if (node.Op == JoinAlgebraNode.JoinOperator.InnerJoin) { // TODO: There is a problem. If the constant scan defines values this does not work. Acutally, // this is currently no problem as the only way to create such a plan is using derived // tables and in this phase the child will be a ResultNode. if (node.Left is ConstantScanAlgebraNode) { return(VisitAlgebraNode(WrapWithFilter(node.Right, node.Predicate))); } if (node.Right is ConstantScanAlgebraNode) { return(VisitAlgebraNode(WrapWithFilter(node.Left, node.Predicate))); } } // Analyze AND-parts of Condition if (node.Predicate == null) { // TODO: This does not work as the children are not yet rearranged. if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin || node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin) { bool hasOuterReferences = AstUtil.GetOuterReferences(node).Length == 0; if (!hasOuterReferences) { if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin && AstUtil.WillProduceAtLeastOneRow(node.Right) || node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin && AstUtil.WillProduceAtLeastOneRow(node.Left)) { node.Op = JoinAlgebraNode.JoinOperator.InnerJoin; return(VisitAlgebraNode(node)); } } } } else { foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate)) { if (node.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin) { // Check if we can derive from this AND-part that a table it depends on // is null-rejected. RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart); foreach (RowBufferEntry rowBufferEntry in rowBufferEntries) { if (AstUtil.ExpressionYieldsNullOrFalseIfRowBufferEntryNull(andPart, rowBufferEntry)) { if (ArrayHelpers.Contains(leftDefinedValues, rowBufferEntry) && node.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin) { AddNullRejectedTable(rowBufferEntry); } else if (ArrayHelpers.Contains(rightDefinedValues, rowBufferEntry) && node.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin) { AddNullRejectedTable(rowBufferEntry); } } } } } } // Visit children node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); return(node); }