public virtual AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); node.Predicate = VisitExpression(node.Predicate); return(node); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { switch (node.Input.NodeType) { case AstNodeType.SortAlgebraNode: case AstNodeType.ResultAlgebraNode: case AstNodeType.TopAlgebraNode: return(PushOverUnary(node)); case AstNodeType.FilterAlgebraNode: return(MergeWithFilter(node)); case AstNodeType.ComputeScalarAlgebraNode: return(PushOverComputeScalar(node)); case AstNodeType.AggregateAlgebraNode: return(PushOverAggregate(node)); case AstNodeType.JoinAlgebraNode: return(PushOverJoin(node)); case AstNodeType.ConcatAlgebraNode: return(PushOverConcat(node)); default: return(base.VisitFilterAlgebraNode(node)); } }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { switch (node.Input.NodeType) { case AstNodeType.SortAlgebraNode: case AstNodeType.ResultAlgebraNode: case AstNodeType.TopAlgebraNode: return PushOverUnary(node); case AstNodeType.FilterAlgebraNode: return MergeWithFilter(node); case AstNodeType.ComputeScalarAlgebraNode: return PushOverComputeScalar(node); case AstNodeType.AggregateAlgebraNode: return PushOverAggregate(node); case AstNodeType.JoinAlgebraNode: return PushOverJoin(node); case AstNodeType.ConcatAlgebraNode: return PushOverConcat(node); default: return base.VisitFilterAlgebraNode(node); } }
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; }
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 PushOverUnary(FilterAlgebraNode node) { UnaryAlgebraNode inputNode = (UnaryAlgebraNode)node.Input; node.Input = inputNode.Input; inputNode.Input = VisitAlgebraNode(node); return(inputNode); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.OutputList = RemovedUnneededRowBufferColumns(node.OutputList); AddNeededRowBufferEntryReferences(node.Predicate); return(base.VisitFilterAlgebraNode(node)); }
private AlgebraNode PushOverComputeScalar(FilterAlgebraNode node) { // Predicates can be pushed over a compute scalar if it does not contain any row buffer entries // that are defined by the compute scalar node. ComputeScalarAlgebraNode inputNode = (ComputeScalarAlgebraNode)node.Input; return(PushOverValueDefininingUnary(inputNode.DefinedValues, node)); }
public override AstElement Clone(Dictionary<AstElement, AstElement> alreadyClonedElements) { FilterAlgebraNode result = new FilterAlgebraNode(); result.StatisticsIterator = StatisticsIterator; result.OutputList = ArrayHelpers.Clone(OutputList); result.Input = (AlgebraNode)Input.Clone(alreadyClonedElements); result.Predicate = (ExpressionNode)_predicate.Clone(alreadyClonedElements); return result; }
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 AstElement Clone(Dictionary <AstElement, AstElement> alreadyClonedElements) { FilterAlgebraNode result = new FilterAlgebraNode(); result.StatisticsIterator = StatisticsIterator; result.OutputList = ArrayHelpers.Clone(OutputList); result.Input = (AlgebraNode)Input.Clone(alreadyClonedElements); result.Predicate = (ExpressionNode)_predicate.Clone(alreadyClonedElements); return(result); }
private static AlgebraNode WrapWithFilter(AlgebraNode input, ExpressionNode predicate) { if (predicate == null) return input; FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = input; filterAlgebraNode.Predicate = predicate; return filterAlgebraNode; }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { _xmlWriter.WriteStartElement("filterAlgebraNode"); WriteAstNode("input", node.Input); WriteAstNode("predicate", node.Predicate); _xmlWriter.WriteEndElement(); return(node); }
private AlgebraNode PushOverFilter(ComputeScalarAlgebraNode node) { FilterAlgebraNode filterAlgebraNode = (FilterAlgebraNode)node.Input; if (filterAlgebraNode.Input is TableAlgebraNode) { // We don't push a compute scalar over the input if this is already a table scan. return(node); } return(PushOverUnary(node)); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); SetLastAlgebraNode(node.Input); _probingEnabledStack.Push(false); node.Predicate = VisitExpression(node.Predicate); _probingEnabledStack.Pop(); node.Input = GetAndResetLastNode(); return(node); }
private static AlgebraNode WrapWithFilter(AlgebraNode input, ExpressionNode predicate) { if (predicate == null) { return(input); } FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = input; filterAlgebraNode.Predicate = predicate; return(filterAlgebraNode); }
private AlgebraNode PushOverAggregate(FilterAlgebraNode node) { // TODO: It is not that easy. // For example this condition can be pushed 'GroupCol = Value' while this can't: 'GroupCol = Value OR Func(const) = const' // Formally, a predicate can be pushed over an aggregate if and only if all disjuncts of the predicate's CNF do reference // at least one grouping column. // Since this requires cloning of the predicate and heavy rewriting this is not done (yet). return(base.VisitFilterAlgebraNode(node)); /* * // Predicates can be pushed over an aggregation if it does not contain any aggregate function. * AggregateAlgebraNode inputNode = (AggregateAlgebraNode)node.Input; * return PushOverValueDefininingUnary(inputNode.DefinedValues, node); */ }
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 AlgebraNode PullFilterUp(UnaryAlgebraNode unaryAlgebraNode) { unaryAlgebraNode.Input = VisitAlgebraNode(unaryAlgebraNode.Input); FilterAlgebraNode filterAlgebraNode = unaryAlgebraNode.Input as FilterAlgebraNode; if (filterAlgebraNode == null) { return(unaryAlgebraNode); } else { unaryAlgebraNode.Input = filterAlgebraNode.Input; filterAlgebraNode.Input = unaryAlgebraNode; return(filterAlgebraNode); } }
private AlgebraNode PushOverConcat(FilterAlgebraNode node) { ConcatAlgebraNode inputNode = (ConcatAlgebraNode)node.Input; for (int i = 0; i < inputNode.Inputs.Length; i++) { ExpressionNode predicate = (ExpressionNode)node.Predicate.Clone(); ConcatRowBufferEntryReplacer concatRowBufferEntryReplacer = new ConcatRowBufferEntryReplacer(inputNode.DefinedValues, i); predicate = concatRowBufferEntryReplacer.VisitExpression(predicate); FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = inputNode.Inputs[i]; filterAlgebraNode.Predicate = predicate; inputNode.Inputs[i] = VisitAlgebraNode(filterAlgebraNode); } return(inputNode); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { ShowPlanElement inputElement = ConvertNode(node.Input); PropertyListBuilder propertyListBuilder = new PropertyListBuilder(); AddRowBufferEntries(propertyListBuilder, Resources.ShowPlanGroupOutputList, node.OutputList); AddStatistics(propertyListBuilder, node.StatisticsIterator); propertyListBuilder.Write(Resources.ShowPlanKeyPredicate, node.Predicate.GenerateSource()); IList <ShowPlanProperty> properties = propertyListBuilder.ToList(); ShowPlanElement element = new ShowPlanElement(ShowPlanOperator.Filter, properties, inputElement); _currentElement = element; return(node); }
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)); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); ConstantExpression predicateAsConstant = node.Predicate as ConstantExpression; if (predicateAsConstant != null) { if (predicateAsConstant.AsBoolean) { return(node.Input); } else { return(CreateNullScan(node.OutputList)); } } return(NullScanIfInputIsNullScan(node)); }
public override TableReference VisitJoinedTableReference(JoinedTableReference node) { TableReference nonCteTableRef; if (IsTableReferenceToCurrentCommonTableBinding(node.Left)) { nonCteTableRef = node.Right; } else if (IsTableReferenceToCurrentCommonTableBinding(node.Right)) { nonCteTableRef = node.Left; } else { nonCteTableRef = null; } if (nonCteTableRef != null) { Debug.Assert(node.JoinType == JoinType.Inner); AlgebraNode algebrizedPath = ConvertAstNode(nonCteTableRef); SetLastAlgebraNode(algebrizedPath); if (node.Condition != null) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetLastAlgebraNode(); filterAlgebraNode.Predicate = node.Condition; SetLastAlgebraNode(filterAlgebraNode); } return(node); } JoinAlgebraNode algebraNode = new JoinAlgebraNode(); algebraNode.Left = ConvertAstNode(node.Left); algebraNode.Right = ConvertAstNode(node.Right); algebraNode.Predicate = node.Condition; switch (node.JoinType) { case JoinType.Inner: algebraNode.Op = JoinAlgebraNode.JoinOperator.InnerJoin; break; case JoinType.LeftOuter: algebraNode.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin; break; case JoinType.RightOuter: algebraNode.Op = JoinAlgebraNode.JoinOperator.RightOuterJoin; break; case JoinType.FullOuter: algebraNode.Op = JoinAlgebraNode.JoinOperator.FullOuterJoin; break; } SetLastAlgebraNode(algebraNode); return(node); }
public override QueryNode VisitSelectQuery(SelectQuery query) { // Calculate needed row buffers RowBufferCalculator rowBufferCalculator = query.RowBufferCalculator; // Emit FROM if (query.TableReferences != null) { Visit(query.TableReferences); } else { ConstantScanAlgebraNode constantScanAlgebraNode = new ConstantScanAlgebraNode(); constantScanAlgebraNode.DefinedValues = new ComputedValueDefinition[0]; SetLastAlgebraNode(constantScanAlgebraNode); } // Emit WHERE if (query.WhereClause != null) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetLastAlgebraNode(); filterAlgebraNode.Predicate = query.WhereClause; SetLastAlgebraNode(filterAlgebraNode); } // Emit GROUP BY if (query.GroupByColumns != null || query.IsAggregated) { EmitComputeScalarIfNeeded(rowBufferCalculator.ComputedGroupColumns); List <AggregatedValueDefinition> definedValues = new List <AggregatedValueDefinition>(); foreach (AggregateExpression aggregateDependency in query.AggregateDependencies) { definedValues.Add(aggregateDependency.ValueDefinition); } if (query.GroupByColumns != null) { SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = rowBufferCalculator.GroupColumns; sortAlgebraNode.SortOrders = CreateAscendingSortOrders(sortAlgebraNode.SortEntries.Length); SetLastAlgebraNode(sortAlgebraNode); } AggregateAlgebraNode algebraNode = new AggregateAlgebraNode(); algebraNode.Input = GetLastAlgebraNode(); algebraNode.DefinedValues = definedValues.ToArray(); algebraNode.Groups = rowBufferCalculator.GroupColumns; SetLastAlgebraNode(algebraNode); } // Emit HAVING if (query.HavingClause != null) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetLastAlgebraNode(); filterAlgebraNode.Predicate = query.HavingClause; SetLastAlgebraNode(filterAlgebraNode); } // Emit compute scalar to calculate expressions needed in SELECT and ORDER BY EmitComputeScalarIfNeeded(rowBufferCalculator.ComputedSelectAndOrderColumns); // Emit DISTINCT and ORDER BY if (query.IsDistinct && query.OrderByColumns != null) { List <RowBufferEntry> sortEntries = new List <RowBufferEntry>(); List <SortOrder> sortOrderList = new List <SortOrder>(); for (int i = 0; i < query.OrderByColumns.Length; i++) { sortEntries.Add(rowBufferCalculator.OrderColumns[i]); sortOrderList.Add(query.OrderByColumns[i].SortOrder); } foreach (RowBufferEntry selectColumn in rowBufferCalculator.SelectColumns) { bool selectColumnMustBeSorted = !sortEntries.Contains(selectColumn); if (selectColumnMustBeSorted) { sortEntries.Add(selectColumn); sortOrderList.Add(SortOrder.Ascending); } } SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Distinct = true; sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = sortEntries.ToArray(); sortAlgebraNode.SortOrders = sortOrderList.ToArray(); SetLastAlgebraNode(sortAlgebraNode); } else { if (query.IsDistinct) { SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Distinct = true; sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = rowBufferCalculator.SelectColumns; sortAlgebraNode.SortOrders = CreateAscendingSortOrders(sortAlgebraNode.SortEntries.Length); SetLastAlgebraNode(sortAlgebraNode); } if (query.OrderByColumns != null) { List <SortOrder> sortOrderList = new List <SortOrder>(); foreach (OrderByColumn orderByColumn in query.OrderByColumns) { sortOrderList.Add(orderByColumn.SortOrder); } SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = rowBufferCalculator.OrderColumns; sortAlgebraNode.SortOrders = sortOrderList.ToArray(); SetLastAlgebraNode(sortAlgebraNode); } } // Emit TOP if (query.TopClause != null) { TopAlgebraNode algebraNode = new TopAlgebraNode(); algebraNode.Input = GetLastAlgebraNode(); algebraNode.Limit = query.TopClause.Value; if (query.TopClause.WithTies) { algebraNode.TieEntries = rowBufferCalculator.OrderColumns; } SetLastAlgebraNode(algebraNode); } // Emit select list List <string> columnNames = new List <string>(); foreach (SelectColumn columnSource in query.SelectColumns) { if (columnSource.Alias != null) { columnNames.Add(columnSource.Alias.Text); } else { columnNames.Add(null); } } ResultAlgebraNode resultAlgebraNode = new ResultAlgebraNode(); resultAlgebraNode.Input = GetLastAlgebraNode(); resultAlgebraNode.OutputList = rowBufferCalculator.SelectColumns; resultAlgebraNode.ColumnNames = columnNames.ToArray(); SetLastAlgebraNode(resultAlgebraNode); return(query); }
public virtual AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); node.Predicate = VisitExpression(node.Predicate); 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); }
public override TableReference VisitJoinedTableReference(JoinedTableReference node) { TableReference nonCteTableRef; if (IsTableReferenceToCurrentCommonTableBinding(node.Left)) nonCteTableRef = node.Right; else if (IsTableReferenceToCurrentCommonTableBinding(node.Right)) nonCteTableRef = node.Left; else nonCteTableRef = null; if (nonCteTableRef != null) { Debug.Assert(node.JoinType == JoinType.Inner); AlgebraNode algebrizedPath = ConvertAstNode(nonCteTableRef); SetLastAlgebraNode(algebrizedPath); if (node.Condition != null) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetLastAlgebraNode(); filterAlgebraNode.Predicate = node.Condition; SetLastAlgebraNode(filterAlgebraNode); } return node; } JoinAlgebraNode algebraNode = new JoinAlgebraNode(); algebraNode.Left = ConvertAstNode(node.Left); algebraNode.Right = ConvertAstNode(node.Right); algebraNode.Predicate = node.Condition; switch (node.JoinType) { case JoinType.Inner: algebraNode.Op = JoinAlgebraNode.JoinOperator.InnerJoin; break; case JoinType.LeftOuter: algebraNode.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin; break; case JoinType.RightOuter: algebraNode.Op = JoinAlgebraNode.JoinOperator.RightOuterJoin; break; case JoinType.FullOuter: algebraNode.Op = JoinAlgebraNode.JoinOperator.FullOuterJoin; break; } SetLastAlgebraNode(algebraNode); return node; }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); SetLastAlgebraNode(node.Input); _probingEnabledStack.Push(false); node.Predicate = VisitExpression(node.Predicate); _probingEnabledStack.Pop(); node.Input = GetAndResetLastNode(); return node; }
private AlgebraNode PushOverUnary(FilterAlgebraNode node) { UnaryAlgebraNode inputNode = (UnaryAlgebraNode) node.Input; node.Input = inputNode.Input; inputNode.Input = VisitAlgebraNode(node); return inputNode; }
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)); } }
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) { // 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 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; }
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 VisitAllAnySubselect(AllAnySubselect expression) { expression.Left = VisitExpression(expression.Left); ResultAlgebraNode algebrizedQuery = Algebrizer.Convert(expression.Query); ExpressionNode leftExpression = expression.Left; RowBufferEntryExpression rightExpression = new RowBufferEntryExpression(); rightExpression.RowBufferEntry = algebrizedQuery.OutputList[0]; ExpressionBuilder expressionBuilder = new ExpressionBuilder(); expressionBuilder.Push(leftExpression); expressionBuilder.Push(rightExpression); expressionBuilder.PushBinary(expression.Op); bool negated = (expression.Type == AllAnySubselect.AllAnyType.All); if (negated) { expressionBuilder.PushUnary(UnaryOperator.LogicalNot); expressionBuilder.Push(leftExpression); expressionBuilder.PushIsNull(); expressionBuilder.Push(rightExpression); expressionBuilder.PushIsNull(); expressionBuilder.PushNAry(LogicalOperator.Or); } ExpressionNode filterPredicate = expressionBuilder.Pop(); FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = algebrizedQuery; filterAlgebraNode.Predicate = filterPredicate; AlgebraNode input = GetAndResetLastNode(); if (!negated && !ProbingEnabled && input == null) { SetLastAlgebraNode(filterAlgebraNode); 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 = filterAlgebraNode; joinAlgebraNode.Op = negated ? JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin : JoinAlgebraNode.JoinOperator.LeftSemiJoin; SetLastAlgebraNode(joinAlgebraNode); return CreateProbeColumnRef(probeColumn); } }
public override QueryNode VisitSelectQuery(SelectQuery query) { // Calculate needed row buffers RowBufferCalculator rowBufferCalculator = query.RowBufferCalculator; // Emit FROM if (query.TableReferences != null) { Visit(query.TableReferences); } else { ConstantScanAlgebraNode constantScanAlgebraNode = new ConstantScanAlgebraNode(); constantScanAlgebraNode.DefinedValues = new ComputedValueDefinition[0]; SetLastAlgebraNode(constantScanAlgebraNode); } // Emit WHERE if (query.WhereClause != null) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetLastAlgebraNode(); filterAlgebraNode.Predicate = query.WhereClause; SetLastAlgebraNode(filterAlgebraNode); } // Emit GROUP BY if (query.GroupByColumns != null || query.IsAggregated) { EmitComputeScalarIfNeeded(rowBufferCalculator.ComputedGroupColumns); List<AggregatedValueDefinition> definedValues = new List<AggregatedValueDefinition>(); foreach (AggregateExpression aggregateDependency in query.AggregateDependencies) definedValues.Add(aggregateDependency.ValueDefinition); if (query.GroupByColumns != null) { SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = rowBufferCalculator.GroupColumns; sortAlgebraNode.SortOrders = CreateAscendingSortOrders(sortAlgebraNode.SortEntries.Length); SetLastAlgebraNode(sortAlgebraNode); } AggregateAlgebraNode algebraNode = new AggregateAlgebraNode(); algebraNode.Input = GetLastAlgebraNode(); algebraNode.DefinedValues = definedValues.ToArray(); algebraNode.Groups = rowBufferCalculator.GroupColumns; SetLastAlgebraNode(algebraNode); } // Emit HAVING if (query.HavingClause != null) { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = GetLastAlgebraNode(); filterAlgebraNode.Predicate = query.HavingClause; SetLastAlgebraNode(filterAlgebraNode); } // Emit compute scalar to calculate expressions needed in SELECT and ORDER BY EmitComputeScalarIfNeeded(rowBufferCalculator.ComputedSelectAndOrderColumns); // Emit DISTINCT and ORDER BY if (query.IsDistinct && query.OrderByColumns != null) { List<RowBufferEntry> sortEntries = new List<RowBufferEntry>(); List<SortOrder> sortOrderList = new List<SortOrder>(); for (int i = 0; i < query.OrderByColumns.Length; i++) { sortEntries.Add(rowBufferCalculator.OrderColumns[i]); sortOrderList.Add(query.OrderByColumns[i].SortOrder); } foreach (RowBufferEntry selectColumn in rowBufferCalculator.SelectColumns) { bool selectColumnMustBeSorted = !sortEntries.Contains(selectColumn); if (selectColumnMustBeSorted) { sortEntries.Add(selectColumn); sortOrderList.Add(SortOrder.Ascending); } } SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Distinct = true; sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = sortEntries.ToArray(); sortAlgebraNode.SortOrders = sortOrderList.ToArray(); SetLastAlgebraNode(sortAlgebraNode); } else { if (query.IsDistinct) { SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Distinct = true; sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = rowBufferCalculator.SelectColumns; sortAlgebraNode.SortOrders = CreateAscendingSortOrders(sortAlgebraNode.SortEntries.Length); SetLastAlgebraNode(sortAlgebraNode); } if (query.OrderByColumns != null) { List<SortOrder> sortOrderList = new List<SortOrder>(); foreach (OrderByColumn orderByColumn in query.OrderByColumns) sortOrderList.Add(orderByColumn.SortOrder); SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = rowBufferCalculator.OrderColumns; sortAlgebraNode.SortOrders = sortOrderList.ToArray(); SetLastAlgebraNode(sortAlgebraNode); } } // Emit TOP if (query.TopClause != null) { TopAlgebraNode algebraNode = new TopAlgebraNode(); algebraNode.Input = GetLastAlgebraNode(); algebraNode.Limit = query.TopClause.Value; if (query.TopClause.WithTies) algebraNode.TieEntries = rowBufferCalculator.OrderColumns; SetLastAlgebraNode(algebraNode); } // Emit select list List<string> columnNames = new List<string>(); foreach (SelectColumn columnSource in query.SelectColumns) { if (columnSource.Alias != null) columnNames.Add(columnSource.Alias.Text); else columnNames.Add(null); } ResultAlgebraNode resultAlgebraNode = new ResultAlgebraNode(); resultAlgebraNode.Input = GetLastAlgebraNode(); resultAlgebraNode.OutputList = rowBufferCalculator.SelectColumns; resultAlgebraNode.ColumnNames = columnNames.ToArray(); SetLastAlgebraNode(resultAlgebraNode); return query; }
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 AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { if (node.Predicate == null || !AstUtil.ContainsSubselect(node.Predicate)) { return(base.VisitJoinAlgebraNode(node)); } node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); switch (node.Op) { case JoinAlgebraNode.JoinOperator.InnerJoin: { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Predicate = node.Predicate; filterAlgebraNode.Input = node; node.Predicate = null; SetLastAlgebraNode(node); _probingEnabledStack.Push(false); filterAlgebraNode.Predicate = VisitExpression(filterAlgebraNode.Predicate); _probingEnabledStack.Pop(); filterAlgebraNode.Input = GetAndResetLastNode(); return(filterAlgebraNode); } case JoinAlgebraNode.JoinOperator.LeftOuterJoin: { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Predicate = node.Predicate; filterAlgebraNode.Input = node.Right; node.Right = filterAlgebraNode; node.Predicate = null; SetLastAlgebraNode(filterAlgebraNode.Input); _probingEnabledStack.Push(false); filterAlgebraNode.Predicate = VisitExpression(filterAlgebraNode.Predicate); _probingEnabledStack.Pop(); filterAlgebraNode.Input = GetAndResetLastNode(); return(node); } case JoinAlgebraNode.JoinOperator.RightOuterJoin: { node.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin; AlgebraNode oldLeft = node.Left; node.Left = node.Right; node.Right = oldLeft; goto case JoinAlgebraNode.JoinOperator.LeftOuterJoin; } case JoinAlgebraNode.JoinOperator.FullOuterJoin: // TODO: Support subqueries in FULL OUTER JOIN. throw ExceptionBuilder.InternalError("FULL OUTER JOIN containing a subselect predicate in ON clause is not supported."); default: throw ExceptionBuilder.UnhandledCaseLabel(node.Op); } }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); node.OutputList = node.Input.OutputList; return node; }
public override ExpressionNode VisitAllAnySubselect(AllAnySubselect expression) { expression.Left = VisitExpression(expression.Left); ResultAlgebraNode algebrizedQuery = Algebrizer.Convert(expression.Query); ExpressionNode leftExpression = expression.Left; RowBufferEntryExpression rightExpression = new RowBufferEntryExpression(); rightExpression.RowBufferEntry = algebrizedQuery.OutputList[0]; ExpressionBuilder expressionBuilder = new ExpressionBuilder(); expressionBuilder.Push(leftExpression); expressionBuilder.Push(rightExpression); expressionBuilder.PushBinary(expression.Op); bool negated = (expression.Type == AllAnySubselect.AllAnyType.All); if (negated) { expressionBuilder.PushUnary(UnaryOperator.LogicalNot); expressionBuilder.Push(leftExpression); expressionBuilder.PushIsNull(); expressionBuilder.Push(rightExpression); expressionBuilder.PushIsNull(); expressionBuilder.PushNAry(LogicalOperator.Or); } ExpressionNode filterPredicate = expressionBuilder.Pop(); FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = algebrizedQuery; filterAlgebraNode.Predicate = filterPredicate; AlgebraNode input = GetAndResetLastNode(); if (!negated && !ProbingEnabled && input == null) { SetLastAlgebraNode(filterAlgebraNode); 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 = filterAlgebraNode; joinAlgebraNode.Op = negated ? JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin : JoinAlgebraNode.JoinOperator.LeftSemiJoin; SetLastAlgebraNode(joinAlgebraNode); return(CreateProbeColumnRef(probeColumn)); } }
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; }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { Visit(node.Input); _filters.Add(node.Predicate); return(node); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); node.OutputList = node.Input.OutputList; return(node); }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { _xmlWriter.WriteStartElement("filterAlgebraNode"); WriteAstNode("input", node.Input); WriteAstNode("predicate", node.Predicate); _xmlWriter.WriteEndElement(); return node; }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { Visit(node.Input); _filters.Add(node.Predicate); 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); } }
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 AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node) { if (node.Predicate == null || !AstUtil.ContainsSubselect(node.Predicate)) return base.VisitJoinAlgebraNode(node); node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); switch (node.Op) { case JoinAlgebraNode.JoinOperator.InnerJoin: { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Predicate = node.Predicate; filterAlgebraNode.Input = node; node.Predicate = null; SetLastAlgebraNode(node); _probingEnabledStack.Push(false); filterAlgebraNode.Predicate = VisitExpression(filterAlgebraNode.Predicate); _probingEnabledStack.Pop(); filterAlgebraNode.Input = GetAndResetLastNode(); return filterAlgebraNode; } case JoinAlgebraNode.JoinOperator.LeftOuterJoin: { FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Predicate = node.Predicate; filterAlgebraNode.Input = node.Right; node.Right = filterAlgebraNode; node.Predicate = null; SetLastAlgebraNode(filterAlgebraNode.Input); _probingEnabledStack.Push(false); filterAlgebraNode.Predicate = VisitExpression(filterAlgebraNode.Predicate); _probingEnabledStack.Pop(); filterAlgebraNode.Input = GetAndResetLastNode(); return node; } case JoinAlgebraNode.JoinOperator.RightOuterJoin: { node.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin; AlgebraNode oldLeft = node.Left; node.Left = node.Right; node.Right = oldLeft; goto case JoinAlgebraNode.JoinOperator.LeftOuterJoin; } case JoinAlgebraNode.JoinOperator.FullOuterJoin: // TODO: Support subqueries in FULL OUTER JOIN. throw ExceptionBuilder.InternalError("FULL OUTER JOIN containing a subselect predicate in ON clause is not supported."); default: throw ExceptionBuilder.UnhandledCaseLabel(node.Op); } }
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 VisitFilterAlgebraNode(FilterAlgebraNode node) { node.Input = VisitAlgebraNode(node.Input); ConstantExpression predicateAsConstant = node.Predicate as ConstantExpression; if (predicateAsConstant != null) { if (predicateAsConstant.AsBoolean) return node.Input; else return CreateNullScan(node.OutputList); } return NullScanIfInputIsNullScan(node); }
private AlgebraNode PushOverAggregate(FilterAlgebraNode node) { // TODO: It is not that easy. // For example this condition can be pushed 'GroupCol = Value' while this can't: 'GroupCol = Value OR Func(const) = const' // Formally, a predicate can be pushed over an aggregate if and only if all disjuncts of the predicate's CNF do reference // at least one grouping column. // Since this requires cloning of the predicate and heavy rewriting this is not done (yet). return base.VisitFilterAlgebraNode(node); /* // Predicates can be pushed over an aggregation if it does not contain any aggregate function. AggregateAlgebraNode inputNode = (AggregateAlgebraNode)node.Input; return PushOverValueDefininingUnary(inputNode.DefinedValues, node); */ }
private AlgebraNode PushOverComputeScalar(FilterAlgebraNode node) { // Predicates can be pushed over a compute scalar if it does not contain any row buffer entries // that are defined by the compute scalar node. ComputeScalarAlgebraNode inputNode = (ComputeScalarAlgebraNode) node.Input; return PushOverValueDefininingUnary(inputNode.DefinedValues, node); }
private AlgebraNode PushOverConcat(FilterAlgebraNode node) { ConcatAlgebraNode inputNode = (ConcatAlgebraNode) node.Input; for (int i = 0; i < inputNode.Inputs.Length; i++) { ExpressionNode predicate = (ExpressionNode)node.Predicate.Clone(); ConcatRowBufferEntryReplacer concatRowBufferEntryReplacer = new ConcatRowBufferEntryReplacer(inputNode.DefinedValues, i); predicate = concatRowBufferEntryReplacer.VisitExpression(predicate); FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode(); filterAlgebraNode.Input = inputNode.Inputs[i]; filterAlgebraNode.Predicate = predicate; inputNode.Inputs[i] = VisitAlgebraNode(filterAlgebraNode); } return inputNode; }
public override AlgebraNode VisitFilterAlgebraNode(FilterAlgebraNode node) { FilterIterator filterIterator = new FilterIterator(); filterIterator.RowBuffer = new object[node.OutputList.Length]; filterIterator.Input = ConvertAlgebraNode(node.Input); filterIterator.InputOutput = GetIteratorOutput(0, node.Input.OutputList, node.OutputList); BoundRowBufferEntrySet boundRowBufferEntrySet = new BoundRowBufferEntrySet(filterIterator.Input.RowBuffer, node.Input.OutputList); filterIterator.Predicate = CreateRuntimeExpression(node.Predicate, boundRowBufferEntrySet); SetLastIterator(node, filterIterator); 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; }
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) { ShowPlanElement inputElement = ConvertNode(node.Input); PropertyListBuilder propertyListBuilder = new PropertyListBuilder(); AddRowBufferEntries(propertyListBuilder, Resources.ShowPlanGroupOutputList, node.OutputList); AddStatistics(propertyListBuilder, node.StatisticsIterator); propertyListBuilder.Write(Resources.ShowPlanKeyPredicate, node.Predicate.GenerateSource()); IList<ShowPlanProperty> properties = propertyListBuilder.ToList(); ShowPlanElement element = new ShowPlanElement(ShowPlanOperator.Filter, properties, inputElement); _currentElement = element; return node; }