private AlgebraNode PushOverJoin(ComputeScalarAlgebraNode node) { JoinAlgebraNode joinAlgebraNode = (JoinAlgebraNode)node.Input; RowBufferEntry[] leftDefinedValues = AstUtil.GetDefinedValueEntries(joinAlgebraNode.Left); RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(joinAlgebraNode.Right); List <ComputedValueDefinition> remainingValueDefinitions = new List <ComputedValueDefinition>(); List <ComputedValueDefinition> leftPushedValueDefinitions = new List <ComputedValueDefinition>(); List <ComputedValueDefinition> rightPushedValueDefinitions = new List <ComputedValueDefinition>(); bool canPushToLeftSide = joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin && joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin; bool canPushToRightSide = joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin && joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin; foreach (ComputedValueDefinition valueDefinition in node.DefinedValues) { RowBufferEntry[] referencedValues = AstUtil.GetRowBufferEntryReferences(valueDefinition.Expression); bool referencesProbeColumn = ArrayHelpers.Contains(referencedValues, joinAlgebraNode.ProbeBufferEntry); if (!referencesProbeColumn && canPushToLeftSide && AstUtil.DoesNotReference(referencedValues, rightDefinedValues)) { leftPushedValueDefinitions.Add(valueDefinition); } else if (!referencesProbeColumn && canPushToRightSide && AstUtil.DoesNotReference(referencedValues, leftDefinedValues)) { rightPushedValueDefinitions.Add(valueDefinition); } else { remainingValueDefinitions.Add(valueDefinition); } } if (leftPushedValueDefinitions.Count > 0) { ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.DefinedValues = leftPushedValueDefinitions.ToArray(); computeScalarAlgebraNode.Input = joinAlgebraNode.Left; joinAlgebraNode.Left = VisitAlgebraNode(computeScalarAlgebraNode); } if (rightPushedValueDefinitions.Count > 0) { ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.DefinedValues = rightPushedValueDefinitions.ToArray(); computeScalarAlgebraNode.Input = joinAlgebraNode.Right; joinAlgebraNode.Right = VisitAlgebraNode(computeScalarAlgebraNode); } if (remainingValueDefinitions.Count == 0) { return(joinAlgebraNode); } node.DefinedValues = remainingValueDefinitions.ToArray(); return(node); }
private void AddNeededRowBufferEntryReferences(ExpressionNode expression) { RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression); foreach (RowBufferEntry rowBufferEntry in rowBufferEntries) { AddNeededRowBufferEntry(rowBufferEntry); } }
private static bool AndPartHasOuterReference(ExpressionNode andPart, RowBufferEntry[] definedValues) { RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart); foreach (RowBufferEntry rowBufferEntry in rowBufferEntries) { if (!ArrayHelpers.Contains(definedValues, rowBufferEntry)) { return(true); } } return(false); }
private static ExpressionNode[] GetAndPartsApplicableToJoin(IDictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns, JoinOrder joinOrder, int joinIndex, ICollection <ExpressionNode> andParts, bool removeApplicableAndParts) { List <RowBufferEntry> columnsInJoin = new List <RowBufferEntry>(); for (int i = 0; i <= joinIndex; i++) { foreach (ColumnRefBinding columnRefBinding in joinOrder.Joins[i].TableRefBinding.ColumnRefs) { columnsInJoin.Add(columnRefBinding.ValueDefinition.Target); } } List <ExpressionNode> applicableAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in andParts) { RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart); bool allDependenciesInJoin = true; foreach (RowBufferEntry entry in rowBufferEntries) { if (!columnsInJoin.Contains(entry)) { // Row buffer entry not available in the join the current position. // It could be an outer reference. Check if the row buffer entry // is in the set of introduced row buffer entries. if (introducedColumns.ContainsKey(entry)) { allDependenciesInJoin = false; break; } } } if (allDependenciesInJoin) { applicableAndParts.Add(andPart); } } if (removeApplicableAndParts) { foreach (ExpressionNode andPart in applicableAndParts) { andParts.Remove(andPart); } } return(applicableAndParts.ToArray()); }
private bool CheckIfNodeHasDependenciesToOuterReferences(AlgebraNode node) { foreach (RowBufferEntry rowBufferEntryReference in AstUtil.GetRowBufferEntryReferences(node)) { foreach (RowBufferEntry[] outerReferences in _outerReferences) { if (ArrayHelpers.Contains(outerReferences, rowBufferEntryReference)) { return(true); } } } return(false); }
public override ExpressionNode VisitBinaryExpression(BinaryExpression expression) { if (expression.Op == BinaryOperator.LogicalAnd) { return(base.VisitBinaryExpression(expression)); } else if (expression.Op == BinaryOperator.Equal) { RowBufferEntry[] leftRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Left); RowBufferEntry[] rightRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Right); if (leftRowBufferEntries.Length == 1 && rightRowBufferEntries.Length == 1) { RowBufferEntry leftRowBufferEntry = leftRowBufferEntries[0]; RowBufferEntry rightRowBufferEntry = rightRowBufferEntries[0]; if (leftRowBufferEntry != rightRowBufferEntry) { // Both expressions depend on extactly one row buffer entry but // they are not refering to the same row buffer entry. bool leftDependsOnLeft = ArrayHelpers.Contains(_leftDefinedEntries, leftRowBufferEntry); bool rightDependsOnRight = ArrayHelpers.Contains(_rightDefinedEntries, rightRowBufferEntry); bool leftDependsOnRight = ArrayHelpers.Contains(_rightDefinedEntries, leftRowBufferEntry); bool rightDependsOnLeft = ArrayHelpers.Contains(_leftDefinedEntries, rightRowBufferEntry); if (leftDependsOnRight && rightDependsOnLeft) { ExpressionNode oldLeft = expression.Left; expression.Left = expression.Right; expression.Right = oldLeft; leftDependsOnLeft = true; rightDependsOnRight = true; } if (leftDependsOnLeft && rightDependsOnRight) { _equalPredicates.Add(expression); return(LiteralExpression.FromBoolean(true)); } } } } return(expression); }
private AlgebraNode PushOverValueDefininingUnary(IEnumerable <ValueDefinition> definedValues, FilterAlgebraNode node) { UnaryAlgebraNode inputNode = (UnaryAlgebraNode)node.Input; List <ExpressionNode> nonDependingAndParts = new List <ExpressionNode>(); List <ExpressionNode> dependingAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate)) { RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart); bool dependsOnDefinedValue = false; foreach (ValueDefinition definedValue in definedValues) { if (ArrayHelpers.Contains(rowBufferEntries, definedValue.Target)) { dependsOnDefinedValue = true; break; } } if (dependsOnDefinedValue) { dependingAndParts.Add(andPart); } else { nonDependingAndParts.Add(andPart); } } if (nonDependingAndParts.Count > 0) { node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, dependingAndParts); inputNode.Input = GetFilterFromAndParts(nonDependingAndParts, inputNode.Input); if (node.Predicate == null) { node.Input = inputNode.Input; inputNode.Input = VisitAlgebraNode(node); return(inputNode); } } node.Input = VisitAlgebraNode(node.Input); return(node); }
public override ExpressionNode VisitBinaryExpression(BinaryExpression expression) { if (expression.Op == BinaryOperator.LogicalAnd) { return(base.VisitBinaryExpression(expression)); } else if (expression.Op == BinaryOperator.Equal) { RowBufferEntry[] leftRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Left); RowBufferEntry[] rightRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Right); if (leftRowBufferEntries.Length == 1 && rightRowBufferEntries.Length == 1) { RowBufferEntry leftRowBufferEntry = leftRowBufferEntries[0]; RowBufferEntry rightRowBufferEntry = rightRowBufferEntries[0]; bool leftIsOuter = IsOuterReference(leftRowBufferEntry); bool rightIsOuter = IsOuterReference(rightRowBufferEntry); if (leftRowBufferEntry != rightRowBufferEntry && leftIsOuter ^ rightIsOuter) { // Both expressions depend on extactly one row buffer entry but // they are not refering to the same row buffer entry and // only one is an outer reference. SpoolExpression spoolExpression = new SpoolExpression(); if (leftIsOuter) { spoolExpression.IndexExpression = expression.Right; spoolExpression.ProbeExpression = expression.Left; } else { spoolExpression.IndexExpression = expression.Left; spoolExpression.ProbeExpression = expression.Right; } _spoolExpressions.Add(spoolExpression); return(LiteralExpression.FromBoolean(true)); } } } return(expression); }
private static TableRefBinding[] GetTableReferences(IDictionary <RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary, ExpressionNode expression) { List <TableRefBinding> result = new List <TableRefBinding>(); RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression); foreach (RowBufferEntry rowBufferEntry in rowBufferEntries) { ColumnRefBinding columnRefBinding; if (rowBufferColumnDictionary.TryGetValue(rowBufferEntry, out columnRefBinding)) { if (!result.Contains(columnRefBinding.TableRefBinding)) { result.Add(columnRefBinding.TableRefBinding); } } } return(result.ToArray()); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { // Check for null rejecting conditions. foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate)) { RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart); foreach (RowBufferEntry rowBufferEntry in rowBufferEntries) { if (AstUtil.ExpressionYieldsNullOrFalseIfRowBufferEntryNull(andPart, rowBufferEntry)) { AddNullRejectedTable(rowBufferEntry); } } } return(base.VisitFilterAlgebraNode(node)); }
private static ExpressionNode ExtractConditionsApplicableToTable(IDictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns, IList <ExpressionNode> conditionList, TableRefBinding tableRefBinding) { List <ExpressionNode> applicableConditionList = new List <ExpressionNode>(); for (int i = conditionList.Count - 1; i >= 0; i--) { ExpressionNode condition = conditionList[i]; RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(condition); bool dependentOnOtherTable = false; foreach (RowBufferEntry rowBufferEntry in rowBufferEntries) { ColumnValueDefinition columnValueDefinition; if (introducedColumns.TryGetValue(rowBufferEntry, out columnValueDefinition)) { if (columnValueDefinition.ColumnRefBinding.TableRefBinding != tableRefBinding) { dependentOnOtherTable = true; break; } } } if (!dependentOnOtherTable) { conditionList.RemoveAt(i); applicableConditionList.Add(condition); } } if (applicableConditionList.Count == 0) { return(null); } ExpressionNode[] applicableConditions = applicableConditionList.ToArray(); return(AstUtil.CombineConditions(LogicalOperator.And, applicableConditions)); }
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); }
private AlgebraNode PushOverJoin(FilterAlgebraNode node) { JoinAlgebraNode inputNode = (JoinAlgebraNode)node.Input; // Get declared tables of left and right RowBufferEntry[] leftDefinedValues = AstUtil.GetDefinedValueEntries(inputNode.Left); RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(inputNode.Right); // Obviously, we cannot merge the filter with the join if the join is an outer join // (since it would change the join's semantics). // // Another less obvious restriction is that we cannot merge a filter with the join if // the join has a passthru predicate. In case the passthru predicte evaluates to true // the filter would not be applied. However, we are allowed to push the filter the over // join. bool canMerge = inputNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin && inputNode.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin && inputNode.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin && inputNode.PassthruPredicate == null; if (canMerge) { // We can merge the filter with the condition of the join. // // However, we have to make sure that the predicate does not reference the probe column. // Since not having a probe column is the most common case, we don't always split the // predicate into conjuncts. if (inputNode.ProbeBufferEntry == null || !ArrayHelpers.Contains(AstUtil.GetRowBufferEntryReferences(node.Predicate), inputNode.ProbeBufferEntry)) { // Either there is no probe column defined or the filter does not reference it. That means // no splitting necessary, we can just merge the whole predicate with the join predicate. inputNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, inputNode.Predicate, node.Predicate); return(VisitAlgebraNode(inputNode)); } else { // Unfortunately, the filter references the probe column. Now let's check whether we can merge // conjuncts of the predicate. List <ExpressionNode> remainingAndParts = new List <ExpressionNode>(); List <ExpressionNode> mergableAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate)) { bool andPartReferencesProbeColumn = ArrayHelpers.Contains(AstUtil.GetRowBufferEntryReferences(andPart), inputNode.ProbeBufferEntry); if (andPartReferencesProbeColumn) { remainingAndParts.Add(andPart); } else { mergableAndParts.Add(andPart); } } if (mergableAndParts.Count > 0) { ExpressionNode combinedMergableAndParts = AstUtil.CombineConditions(LogicalOperator.And, mergableAndParts.ToArray()); inputNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, inputNode.Predicate, combinedMergableAndParts); node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts); if (node.Predicate == null) { return(VisitAlgebraNode(inputNode)); } } } } else { // The condition cannot be merged. Now we try to push AND-parts over the join. List <ExpressionNode> leftAndParts = new List <ExpressionNode>(); List <ExpressionNode> rightAndParts = new List <ExpressionNode>(); List <ExpressionNode> remainingAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate)) { bool andPartReferencesProbeColumn = inputNode.ProbeBufferEntry != null && ArrayHelpers.Contains(AstUtil.GetRowBufferEntryReferences(andPart), inputNode.ProbeBufferEntry); if (!andPartReferencesProbeColumn && AstUtil.AllowsLeftPushOver(inputNode.Op) && AstUtil.ExpressionDoesNotReference(andPart, rightDefinedValues)) { // The AND-part depends only on the LHS and the join is inner/left. // So we are allowed to push this AND-part down. leftAndParts.Add(andPart); } else if (!andPartReferencesProbeColumn && AstUtil.AllowsRightPushOver(inputNode.Op) && AstUtil.ExpressionDoesNotReference(andPart, leftDefinedValues)) { // The AND-part depends only on the RHS and the join is inner/right. // So we are allowed to push this AND-part down. rightAndParts.Add(andPart); } else { remainingAndParts.Add(andPart); } } if (leftAndParts.Count > 0) { inputNode.Left = GetFilterFromAndParts(leftAndParts, inputNode.Left); } if (rightAndParts.Count > 0) { inputNode.Right = GetFilterFromAndParts(rightAndParts, inputNode.Right); } node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts); if (node.Predicate == null) { return(VisitAlgebraNode(inputNode)); } } node.Input = VisitAlgebraNode(node.Input); return(node); }