public override ExpressionNode VisitExistsSubselect(ExistsSubselect expression) { AlgebraNode input = GetAndResetLastNode(); ResultAlgebraNode algebrizedQuery = Algebrizer.Convert(expression.Query); if (!expression.Negated && AstUtil.WillProduceAtLeastOneRow(algebrizedQuery)) { if (input == null) { SetLastAlgebraNode(CreateConstantScan()); } else { SetLastAlgebraNode(input); } return(LiteralExpression.FromBoolean(true)); } if (!expression.Negated && !ProbingEnabled && input == null) { SetLastAlgebraNode(algebrizedQuery); return(LiteralExpression.FromBoolean(true)); } else { if (input == null) { input = CreateConstantScan(); } RowBufferEntry probeColumn = CreateProbeColumn(); JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode(); joinAlgebraNode.PassthruPredicate = CurrentPassthruPredicate; joinAlgebraNode.ProbeBufferEntry = probeColumn; joinAlgebraNode.Left = input; joinAlgebraNode.Right = algebrizedQuery; joinAlgebraNode.Op = expression.Negated ? JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin : JoinAlgebraNode.JoinOperator.LeftSemiJoin; SetLastAlgebraNode(joinAlgebraNode); return(CreateProbeColumnRef(probeColumn)); } }
public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); bool leftIsNull = node.Left is NullScanAlgebraNode; bool rightIsNull = node.Right is NullScanAlgebraNode; bool joinConditionAlwaysFalse = false; if (node.Predicate != null) { ExpressionNode predicate = node.Predicate; ConstantExpression predicateAsConstant = predicate as ConstantExpression; if (predicateAsConstant != null) { if (predicateAsConstant.AsBoolean) { node.Predicate = null; } else { joinConditionAlwaysFalse = true; } } } if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin || node.Op == JoinAlgebraNode.JoinOperator.RightSemiJoin || node.Op == JoinAlgebraNode.JoinOperator.RightAntiSemiJoin) { node.SwapSides(); } switch (node.Op) { case JoinAlgebraNode.JoinOperator.InnerJoin: if (joinConditionAlwaysFalse || leftIsNull || rightIsNull) { return(CreateNullScan(node.OutputList)); } break; case JoinAlgebraNode.JoinOperator.FullOuterJoin: if (leftIsNull && rightIsNull) { return(CreateNullScan(node.OutputList)); } if (leftIsNull) { return(PadRightWithNullsOnLeftSide(node, RowBufferCreationMode.KeepExisting)); } if (rightIsNull) { return(PadLeftWithNullsOnRightSide(node, RowBufferCreationMode.KeepExisting)); } if (joinConditionAlwaysFalse) { AlgebraNode left = PadLeftWithNullsOnRightSide(node, RowBufferCreationMode.CreateNew); AlgebraNode right = PadRightWithNullsOnLeftSide(node, RowBufferCreationMode.CreateNew); ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode(); concatAlgebraNode.Inputs = new AlgebraNode[] { left, right }; List <RowBufferEntry> outputList = new List <RowBufferEntry>(); List <UnitedValueDefinition> definedValues = new List <UnitedValueDefinition>(); for (int i = 0; i < node.Left.OutputList.Length; i++) { int leftIndex = i; int rightIndex = node.Right.OutputList.Length + i; UnitedValueDefinition definedValue = new UnitedValueDefinition(); definedValue.Target = node.Left.OutputList[leftIndex]; definedValue.DependendEntries = new RowBufferEntry[] { left.OutputList[leftIndex], right.OutputList[rightIndex] }; definedValues.Add(definedValue); outputList.Add(definedValue.Target); } for (int i = 0; i < node.Right.OutputList.Length; i++) { int leftIndex = node.Left.OutputList.Length + i; int rightIndex = i; UnitedValueDefinition definedValue = new UnitedValueDefinition(); definedValue.Target = node.Right.OutputList[rightIndex]; definedValue.DependendEntries = new RowBufferEntry[] { left.OutputList[leftIndex], right.OutputList[rightIndex] }; definedValues.Add(definedValue); outputList.Add(definedValue.Target); } concatAlgebraNode.DefinedValues = definedValues.ToArray(); concatAlgebraNode.OutputList = outputList.ToArray(); return(concatAlgebraNode); } break; case JoinAlgebraNode.JoinOperator.LeftOuterJoin: if (leftIsNull) { return(CreateNullScan(node.OutputList)); } if (rightIsNull || joinConditionAlwaysFalse) { return(PadLeftWithNullsOnRightSide(node, RowBufferCreationMode.KeepExisting)); } break; case JoinAlgebraNode.JoinOperator.LeftSemiJoin: if (leftIsNull || rightIsNull || joinConditionAlwaysFalse) { return(CreateNullScan(node.OutputList)); } if (node.Predicate == null && AstUtil.WillProduceAtLeastOneRow(node.Right)) { return(node.Left); } break; case JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin: if (leftIsNull) { return(CreateNullScan(node.OutputList)); } if (rightIsNull || joinConditionAlwaysFalse) { return(node.Left); } if (node.Predicate == null && AstUtil.WillProduceAtLeastOneRow(node.Right)) { return(CreateNullScan(node.OutputList)); } break; } 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); }