private static FilterAlgebraNode GetFilterFromAndParts(IList <ExpressionNode> andParts, AlgebraNode input) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = input; filterAlgebraNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, andParts); return(filterAlgebraNode); }
private AlgebraNode MergeWithFilter(FilterAlgebraNode node) { // The input is also a filter, so we can merge this predicate with // the input filter. FilterAlgebraNode inputNode = (FilterAlgebraNode)node.Input; inputNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, inputNode.Predicate, node.Predicate); return(VisitAlgebraNode(inputNode)); }
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); // Analyze AND-parts of Condition if (node.Predicate != null) { 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)) { // Check if we can push this AND-part down. if (AstUtil.AllowsLeftPushDown(node.Op) && AstUtil.ExpressionDoesNotReference(andPart, rightDefinedValues)) { leftAndParts.Add(andPart); } else if (AstUtil.AllowsRightPushDown(node.Op) && AstUtil.ExpressionDoesNotReference(andPart, leftDefinedValues)) { rightAndParts.Add(andPart); } else { remainingAndParts.Add(andPart); } } if (leftAndParts.Count > 0) { node.Left = GetFilterFromAndParts(leftAndParts, node.Left); } if (rightAndParts.Count > 0) { node.Right = GetFilterFromAndParts(rightAndParts, node.Right); } node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts); } // Visit children node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); return(node); }
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); }
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) { // Check if node only consists of INNER join nodes and simple table reference nodes. // This algorithm assumes that the table references have been lineraized so that // // - JoinedTableReference appear on the LHS only (the last one must be NamedTableReference ovbiviously) // - NamedTableReference appear on the RHS only // // While scanning the node's children we create a list of all JoinedTableReferences and // NamedTableReferences. InnerJoinTableExtractor innerJoinTableExtractor = new InnerJoinTableExtractor(); innerJoinTableExtractor.Visit(node); if (!innerJoinTableExtractor.ConsistsOnlyOfInnerJoinsFiltersAndTables) { node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); return(node); } else { TableAlgebraNode[] algebraNodes = innerJoinTableExtractor.GetTableNodes(); Dictionary <TableRefBinding, TableAlgebraNode> tableRefToNodeDictionary = new Dictionary <TableRefBinding, TableAlgebraNode>(); List <TableRefBinding> tableList = new List <TableRefBinding>(); foreach (TableAlgebraNode algebraNode in algebraNodes) { tableRefToNodeDictionary.Add(algebraNode.TableRefBinding, algebraNode); tableList.Add(algebraNode.TableRefBinding); } // Create a mapping RowBufferEntry -> ColumnRefBinding Dictionary <RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary = new Dictionary <RowBufferEntry, ColumnRefBinding>(); foreach (TableRefBinding tableRefBinding in tableList) { foreach (ColumnRefBinding columnRefBinding in tableRefBinding.ColumnRefs) { rowBufferColumnDictionary.Add(columnRefBinding.ValueDefinition.Target, columnRefBinding); } } // Create list of all possible join conditions and remaining AND-parts. List <JoinCondition> joinConditionList = new List <JoinCondition>(); List <ExpressionNode> andPartList = new List <ExpressionNode>(); ExpressionNode filter = AstUtil.CombineConditions(LogicalOperator.And, innerJoinTableExtractor.GetFilters()); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, filter)) { JoinCondition joinCondition = ConvertToJoinCondition(rowBufferColumnDictionary, andPart); if (joinCondition != null) { joinConditionList.Add(joinCondition); } else { andPartList.Add(andPart); } } // After creating the list of all join conditions and AND-parts we have all we need to create // an optimimal join order between all tables of this part of the table tree. JoinOrder bestJoinOrder = GetBestJoinOrder(tableList.ToArray(), joinConditionList.ToArray(), andPartList.ToArray()); // Get all tables that are introduced by this join order Dictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns = GetIntroducedColumns(bestJoinOrder); // Combine AND-part list with all unused join conditions. andPartList.AddRange(bestJoinOrder.UnusedConditions); // Now we will re-create this part of the tree using the this join order. AlgebraNode lastAlgebraNode = null; for (int joinIndex = 0; joinIndex < bestJoinOrder.Joins.Length; joinIndex++) { Join join = bestJoinOrder.Joins[joinIndex]; AlgebraNode tableInput; TableAlgebraNode tableNode = tableRefToNodeDictionary[join.TableRefBinding]; ExpressionNode tableFilter = ExtractConditionsApplicableToTable(introducedColumns, andPartList, join.TableRefBinding); if (tableFilter == null) { tableInput = tableNode; } else { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = tableNode; filterAlgebraNode.Predicate = tableFilter; tableInput = filterAlgebraNode; } if (lastAlgebraNode == null) { // This was the first one. lastAlgebraNode = tableInput; } else { // Not the first one, we can create a join with the current table reference // and last table reference. // Get all AND-parts that can be applied to the tables already joined. // This expression is merged to one condition. ExpressionNode[] applicableAndParts = GetAndPartsApplicableToJoin(introducedColumns, bestJoinOrder, joinIndex, andPartList, true); ExpressionNode condition = AstUtil.CombineConditions(LogicalOperator.And, applicableAndParts); ExpressionNode joinCondition; if (join.JoinCondition == null) { joinCondition = null; } else { joinCondition = join.JoinCondition.ToExpression(); } ExpressionNode completeCondition = AstUtil.CombineConditions(LogicalOperator.And, condition, joinCondition); JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode(); joinAlgebraNode.Op = JoinAlgebraNode.JoinOperator.InnerJoin; joinAlgebraNode.Left = lastAlgebraNode; joinAlgebraNode.Right = tableInput; joinAlgebraNode.Predicate = completeCondition; // Next time this newly created join is the last table reference. lastAlgebraNode = joinAlgebraNode; } } return(lastAlgebraNode); } }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); ExpressionNode originalPredicate = (ExpressionNode)node.Predicate.Clone(); SpoolExpressionExtractor spoolExpressionExtractor = new SpoolExpressionExtractor(_outerReferences); // HACK: This hack ensures that TRUE literals introduced by SpoolExpressionExtractor are removed. node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, spoolExpressionExtractor.VisitExpression(node.Predicate)); SpoolExpression[] spoolExpressions = spoolExpressionExtractor.GetSpoolExpressions(); // Now we must check that the remaining filter incl. input to the filter don't reference any other // outer reference. bool remainingFilterHasDependenciesToOuterReferences = CheckIfNodeHasDependenciesToOuterReferences(node); if (remainingFilterHasDependenciesToOuterReferences) { // OK; we cannot insert a spool operation here. Undo the expression replacement. node.Predicate = originalPredicate; } else if (spoolExpressions.Length > 0) { SpoolExpression spoolExpression = spoolExpressions[0]; AlgebraNode currentInput; if (node.Predicate is ConstantExpression) { currentInput = node.Input; } else { currentInput = node; } RowBufferEntry indexEntry; RowBufferEntryExpression indexExpressionAsRowBufferEntryExpression = spoolExpression.IndexExpression as RowBufferEntryExpression; if (indexExpressionAsRowBufferEntryExpression != null) { indexEntry = indexExpressionAsRowBufferEntryExpression.RowBufferEntry; } else { indexEntry = new RowBufferEntry(spoolExpression.IndexExpression.ExpressionType); ComputedValueDefinition definedValue = new ComputedValueDefinition(); definedValue.Target = indexEntry; definedValue.Expression = spoolExpression.IndexExpression; ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = currentInput; computeScalarAlgebraNode.DefinedValues = new ComputedValueDefinition[] { definedValue }; currentInput = computeScalarAlgebraNode; } IndexSpoolAlgebraNode indexSpoolAlgebraNode = new IndexSpoolAlgebraNode(); indexSpoolAlgebraNode.Input = currentInput; indexSpoolAlgebraNode.IndexEntry = indexEntry; indexSpoolAlgebraNode.ProbeExpression = spoolExpression.ProbeExpression; return(indexSpoolAlgebraNode); } return(node); }
public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); // Get defined values of left and right RowBufferEntry[] leftDefinedValues = AstUtil.GetDefinedValueEntries(node.Left); RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(node.Right); List <ExpressionNode> andPartsWithinJoin = new List <ExpressionNode>(); // Try to pull up AND-parts that contain outer references from a left sided filter and combine // them with the join predicate. // // NOTE: This is only possible if the join is not a LEFT OUTER or FULL OUTER JOIN since this // operation would change the join's semantic. if (node.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin && node.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin) { FilterAlgebraNode leftAsFilter = node.Left as FilterAlgebraNode; if (leftAsFilter != null) { List <ExpressionNode> remainingAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, leftAsFilter.Predicate)) { if (AndPartHasOuterReference(andPart, leftDefinedValues)) { andPartsWithinJoin.Add(andPart); } else { remainingAndParts.Add(andPart); } } leftAsFilter.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts); if (leftAsFilter.Predicate == null) { node.Left = leftAsFilter.Input; } } } // Try to pull up AND-parts that contain outer references from a right sided filter and combine // them with the join predicate. // // NOTE: This is only possible if the join is not a RIGHT OUTER or FULL OUTER JOIN since this // operation would change the join's semantic. if (node.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin && node.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin) { FilterAlgebraNode rightAsFilter = node.Right as FilterAlgebraNode; if (rightAsFilter != null) { List <ExpressionNode> remainingAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, rightAsFilter.Predicate)) { if (AndPartHasOuterReference(andPart, rightDefinedValues)) { andPartsWithinJoin.Add(andPart); } else { remainingAndParts.Add(andPart); } } rightAsFilter.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts); if (rightAsFilter.Predicate == null) { node.Right = rightAsFilter.Input; } } } // If we found any AND-parts that could be pulled up, merge them with the join predicate. if (andPartsWithinJoin.Count > 0) { node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, node.Predicate, AstUtil.CombineConditions(LogicalOperator.And, andPartsWithinJoin)); } // Now we try to extract AND-parts that contain outer references from the join predicate itself. // // NOTE: This is only possible if the node is not an OUTER JOIN. If the node is a SEMI JOIN the // operation is only legal if the AND-part does not reference any columns from the side that is // is used as filter criteria (i.e. for LSJ this is the right side, for RSJ this is the left // side). if (node.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin && node.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin && node.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin && node.Predicate != null) { List <ExpressionNode> andPartsAboveJoin = new List <ExpressionNode>(); List <ExpressionNode> remainingAndParts = new List <ExpressionNode>(); foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate)) { if (AndPartHasOuterReference(andPart, leftDefinedValues, rightDefinedValues) && SemiJoinDoesNotDependOn(node.Op, andPart, leftDefinedValues, rightDefinedValues)) { andPartsAboveJoin.Add(andPart); } else { remainingAndParts.Add(andPart); } } node.Predicate = AstUtil.CombineConditions(LogicalOperator.And, remainingAndParts); if (andPartsAboveJoin.Count > 0) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Predicate = AstUtil.CombineConditions(LogicalOperator.And, andPartsAboveJoin); filterAlgebraNode.Input = node; return(filterAlgebraNode); } } return(node); }
public override ExpressionNode VisitBinaryExpression(BinaryExpression expression) { if (expression.Op != BinaryOperator.LogicalAnd && expression.Op != BinaryOperator.LogicalOr) { return(base.VisitBinaryExpression(expression)); } if (expression.Op == BinaryOperator.LogicalAnd) { // AND expression.Left = VisitExpression(expression.Left); expression.Right = VisitExpression(expression.Right); return(expression); } else { // OR AlgebraNode input = GetAndResetLastNode(); _probingEnabledStack.Push(false); List <ExpressionNode> scalarOrParts = new List <ExpressionNode>(); List <AlgebraNode> algebrizedOrParts = new List <AlgebraNode>(); foreach (ExpressionNode orPart in AstUtil.SplitCondition(LogicalOperator.Or, expression)) { if (!AstUtil.ContainsSubselect(orPart)) { scalarOrParts.Add(orPart); } else { ExpressionNode replacedOrPart = VisitExpression(orPart); FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetAndResetLastNode(); filterAlgebraNode.Predicate = replacedOrPart; algebrizedOrParts.Add(filterAlgebraNode); } } if (scalarOrParts.Count > 0) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Predicate = AstUtil.CombineConditions(LogicalOperator.Or, scalarOrParts); filterAlgebraNode.Input = CreateConstantScan(); algebrizedOrParts.Insert(0, filterAlgebraNode); } _probingEnabledStack.Pop(); ConcatAlgebraNode concat = new ConcatAlgebraNode(); concat.DefinedValues = new UnitedValueDefinition[0]; concat.Inputs = algebrizedOrParts.ToArray(); RowBufferEntry probeColumn = CreateProbeColumn(); JoinAlgebraNode leftSemiJoinBetweenInputAndConcat = new JoinAlgebraNode(); leftSemiJoinBetweenInputAndConcat.Op = JoinAlgebraNode.JoinOperator.LeftSemiJoin; leftSemiJoinBetweenInputAndConcat.PassthruPredicate = CurrentPassthruPredicate; leftSemiJoinBetweenInputAndConcat.ProbeBufferEntry = probeColumn; leftSemiJoinBetweenInputAndConcat.Left = input; leftSemiJoinBetweenInputAndConcat.Right = concat; SetLastAlgebraNode(leftSemiJoinBetweenInputAndConcat); return(CreateProbeColumnRef(probeColumn)); } }
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); }