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 QueryNode VisitBinaryQuery(BinaryQuery query) { switch (query.Op) { case BinaryQueryOperator.Intersect: case BinaryQueryOperator.Except: { ResultAlgebraNode left = ((ResultAlgebraNode)ConvertAstNode(query.Left)); ResultAlgebraNode right = ((ResultAlgebraNode)ConvertAstNode(query.Right)); // Create distinct sort SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Distinct = true; sortAlgebraNode.Input = left; sortAlgebraNode.SortEntries = left.OutputList; sortAlgebraNode.SortOrders = CreateAscendingSortOrders(sortAlgebraNode.SortEntries.Length); // Insert left (anti) semi join to (except) intersect left and right. ExpressionBuilder expressionBuilder = new ExpressionBuilder(); for (int i = 0; i < left.OutputList.Length; i++) { RowBufferEntryExpression leftExpr = new RowBufferEntryExpression(); leftExpr.RowBufferEntry = left.OutputList[i]; RowBufferEntryExpression rightExpr = new RowBufferEntryExpression(); rightExpr.RowBufferEntry = right.OutputList[i]; expressionBuilder.Push(leftExpr); expressionBuilder.Push(rightExpr); expressionBuilder.PushBinary(BinaryOperator.Equal); expressionBuilder.Push(leftExpr); expressionBuilder.PushIsNull(); expressionBuilder.Push(rightExpr); expressionBuilder.PushIsNull(); expressionBuilder.PushBinary(BinaryOperator.LogicalAnd); expressionBuilder.PushBinary(BinaryOperator.LogicalOr); } expressionBuilder.PushNAry(LogicalOperator.And); ExpressionNode joinCondition = expressionBuilder.Pop(); JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode(); if (query.Op == BinaryQueryOperator.Intersect) { joinAlgebraNode.Op = JoinAlgebraNode.JoinOperator.LeftSemiJoin; } else { joinAlgebraNode.Op = JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin; } joinAlgebraNode.Left = sortAlgebraNode; joinAlgebraNode.Right = right; joinAlgebraNode.Predicate = joinCondition; SetLastAlgebraNode(joinAlgebraNode); ResultAlgebraNode resultAlgebraNode = new ResultAlgebraNode(); resultAlgebraNode.Input = GetLastAlgebraNode(); resultAlgebraNode.OutputList = left.OutputList; resultAlgebraNode.ColumnNames = left.ColumnNames; SetLastAlgebraNode(resultAlgebraNode); break; } case BinaryQueryOperator.Union: case BinaryQueryOperator.UnionAll: { // Build a flat list with all inputs. List <QueryNode> inputList = AstUtil.FlattenBinaryQuery(query); AlgebraNode[] inputs = new AlgebraNode[inputList.Count]; for (int i = 0; i < inputs.Length; i++) { inputs[i] = ConvertAstNode(inputList[i]); } int outputColumnCount = inputs[0].OutputList.Length; UnitedValueDefinition[] definedValues = new UnitedValueDefinition[outputColumnCount]; List <RowBufferEntry> definedValueEntries = new List <RowBufferEntry>(); for (int i = 0; i < outputColumnCount; i++) { RowBufferEntry rowBufferEntry = new RowBufferEntry(inputs[0].OutputList[i].DataType); definedValueEntries.Add(rowBufferEntry); UnitedValueDefinition definedValue = new UnitedValueDefinition(); definedValue.Target = rowBufferEntry; List <RowBufferEntry> dependencies = new List <RowBufferEntry>(); foreach (ResultAlgebraNode node in inputs) { dependencies.Add(node.OutputList[i]); } definedValue.DependendEntries = dependencies.ToArray(); definedValues[i] = definedValue; } ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode(); concatAlgebraNode.Inputs = inputs; concatAlgebraNode.DefinedValues = definedValues; SetLastAlgebraNode(concatAlgebraNode); if (query.Op == BinaryQueryOperator.Union) { SortAlgebraNode sortAlgebraNode = new SortAlgebraNode(); sortAlgebraNode.Distinct = true; sortAlgebraNode.Input = GetLastAlgebraNode(); sortAlgebraNode.SortEntries = definedValueEntries.ToArray(); sortAlgebraNode.SortOrders = CreateAscendingSortOrders(sortAlgebraNode.SortEntries.Length); SetLastAlgebraNode(sortAlgebraNode); } ResultAlgebraNode unionResultAlgebraNode = new ResultAlgebraNode(); unionResultAlgebraNode.Input = GetLastAlgebraNode(); unionResultAlgebraNode.ColumnNames = ((ResultAlgebraNode)inputs[0]).ColumnNames; unionResultAlgebraNode.OutputList = definedValueEntries.ToArray(); SetLastAlgebraNode(unionResultAlgebraNode); break; } } return(query); }
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) { 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 static ResultAlgebraNode CreateAssertedSubquery(ResultAlgebraNode inputNode) { if (AstUtil.WillProduceAtMostOneRow(inputNode)) { return(inputNode); } RowBufferEntry inputEntry = inputNode.OutputList[0]; AggregatedValueDefinition countDefinedValue = new AggregatedValueDefinition(); countDefinedValue.Aggregate = new CountAggregateBinding("COUNT"); countDefinedValue.Aggregator = countDefinedValue.Aggregate.CreateAggregator(typeof(int)); countDefinedValue.Argument = LiteralExpression.FromInt32(0); RowBufferEntry countDefinedValueEntry = new RowBufferEntry(countDefinedValue.Aggregator.ReturnType); countDefinedValue.Target = countDefinedValueEntry; RowBufferEntryExpression anyAggregateArgument = new RowBufferEntryExpression(); anyAggregateArgument.RowBufferEntry = inputEntry; AggregatedValueDefinition anyDefinedValue = new AggregatedValueDefinition(); anyDefinedValue.Aggregate = new FirstAggregateBinding("ANY"); anyDefinedValue.Aggregator = anyDefinedValue.Aggregate.CreateAggregator(inputEntry.DataType); anyDefinedValue.Argument = anyAggregateArgument; RowBufferEntry anyDefinedValueEntry = new RowBufferEntry(inputEntry.DataType); anyDefinedValue.Target = anyDefinedValueEntry; AggregateAlgebraNode aggregateAlgebraNode = new AggregateAlgebraNode(); aggregateAlgebraNode.Input = inputNode.Input; aggregateAlgebraNode.DefinedValues = new AggregatedValueDefinition[] { countDefinedValue, anyDefinedValue }; // CASE WHEN SubqueryCount > 1 THEN 0 ELSE NULL END ExpressionBuilder expressionBuilder = new ExpressionBuilder(); expressionBuilder.Push(new RowBufferEntryExpression(countDefinedValueEntry)); expressionBuilder.Push(LiteralExpression.FromInt32(1)); expressionBuilder.PushBinary(BinaryOperator.Greater); ExpressionNode whenExpression = expressionBuilder.Pop(); ExpressionNode thenExpression = LiteralExpression.FromInt32(0); CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[] { whenExpression }; caseExpression.ThenExpressions = new ExpressionNode[] { thenExpression }; expressionBuilder.Push(caseExpression); ExpressionNode predicate = expressionBuilder.Pop(); AssertAlgebraNode assertAlgebraNode = new AssertAlgebraNode(); assertAlgebraNode.Input = aggregateAlgebraNode; assertAlgebraNode.Predicate = predicate; assertAlgebraNode.AssertionType = AssertionType.MaxOneRow; ResultAlgebraNode resultAlgebraNode = new ResultAlgebraNode(); resultAlgebraNode.Input = assertAlgebraNode; resultAlgebraNode.OutputList = new RowBufferEntry[] { anyDefinedValueEntry }; resultAlgebraNode.ColumnNames = inputNode.ColumnNames; return(resultAlgebraNode); }
public override QueryNode VisitSelectQuery(SelectQuery query) { PushQueryScope(query.QueryScope); // Validate all embedded AST entries that need to check a query context. _queryNestingLevel++; QueryNode result = base.VisitSelectQuery(query); _queryNestingLevel--; // Validate DISTINCT if (query.IsDistinct) { // Ensure that all column sources are datatypes that are comparable. foreach (SelectColumn columnSource in query.SelectColumns) { if (!CheckIfTypeIsComparable(columnSource.Expression.ExpressionType)) { _errorReporter.InvalidDataTypeInSelectDistinct(columnSource.Expression.ExpressionType); } } } // Validate TOP if (query.TopClause != null) { if (query.TopClause.WithTies && query.OrderByColumns == null) { _errorReporter.TopWithTiesRequiresOrderBy(); } } // Ensure that all ORDER BY datatypes are comparable. if (query.OrderByColumns != null) { ValidateOrderByClause(query.OrderByColumns); } // Ensure that if both DISTINCT and ORDER BY are presents all expressions in ORDER BY are also part in SELECT. if (query.IsDistinct && query.OrderByColumns != null) { bool allColumnsAreInInput = GetAllColumnsAreInInput(query.SelectColumns, query.OrderByColumns); if (!allColumnsAreInInput) { _errorReporter.OrderByItemsMustBeInSelectListIfDistinctSpecified(); } } // Validate GROUP BY and aggregation-only queries. if (query.GroupByColumns == null) { if (query.IsAggregated || query.HavingClause != null) { // No grouping applied but at least one aggregation function present. That // means we have an aggregation-only query. // // Check that all expressions in SELECT are either aggregated or do not // reference any column. foreach (SelectColumn columnSource in query.SelectColumns) { foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(null, columnSource.Expression)) { if (referencedColumn.Scope == query.QueryScope) { // The column is not an outer reference so this is an error. _errorReporter.SelectExpressionNotAggregatedAndNoGroupBy(referencedColumn); } } } // Check that all expressions in HAVING are either aggregated or do not // reference any column. if (query.HavingClause != null) { foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(null, query.HavingClause)) { if (referencedColumn.Scope == query.QueryScope) { // The column is not an outer reference so this is an error. _errorReporter.HavingExpressionNotAggregatedOrGrouped(referencedColumn); } } } // Check that all expressions in ORDER BY are either aggregated or do not // reference any column. if (query.OrderByColumns != null) { foreach (OrderByColumn orderByColumn in query.OrderByColumns) { foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(null, orderByColumn.Expression)) { if (referencedColumn.Scope == query.QueryScope) { // The column is not an outer reference so this is an error. _errorReporter.OrderByExpressionNotAggregatedAndNoGroupBy(referencedColumn); } } } } } } else { // Grouped query: // // 1. All expression in GROUP BY must have a datatype that is comparable. // // 2. All expressions in GROUP BY must not be aggregated // // 3. All expressions in SELECT, ORDER BY, and HAVING must be aggregated, grouped or must not reference // columns. // Check that all GROUP BY expressions are not aggregated. foreach (ExpressionNode groupExpression in query.GroupByColumns) { if (!CheckIfTypeIsComparable(groupExpression.ExpressionType)) { _errorReporter.InvalidDataTypeInGroupBy(groupExpression.ExpressionType); } MetaInfo metaInfo = AstUtil.GetMetaInfo(groupExpression); if (metaInfo.ColumnDependencies.Length == 0) { _errorReporter.GroupByItemDoesNotReferenceAnyColumns(); } } // Check that all expressions in SELECT are either part of the GROUP BY or are referencing only those // columns that are part of the GROUP BY. foreach (SelectColumn columnSource in query.SelectColumns) { foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(query.GroupByColumns, columnSource.Expression)) { if (referencedColumn.Scope == query.QueryScope) { // The column is not an outer reference so this is an error. _errorReporter.SelectExpressionNotAggregatedOrGrouped(referencedColumn); } } } // Check that all expressions in HAVING are either part of the GROUP BY or are referencing only those // columns that are part of the GROUP BY. if (query.HavingClause != null) { foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(query.GroupByColumns, query.HavingClause)) { if (referencedColumn.Scope == query.QueryScope) { // The column is not an outer reference so this is an error. _errorReporter.HavingExpressionNotAggregatedOrGrouped(referencedColumn); } } } // Check that all expressions in the ORDER BY clause are either part of the GROUP BY or are // referencing only those columns that are part of the GROUP BY. if (query.OrderByColumns != null) { foreach (OrderByColumn orderByColumn in query.OrderByColumns) { foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(query.GroupByColumns, orderByColumn.Expression)) { if (referencedColumn.Scope == query.QueryScope) { // The column is not an outer reference so this is an error. _errorReporter.OrderByExpressionNotAggregatedOrGrouped(referencedColumn); } } } } } PopQueryScope(); return(result); }
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) { node.Left = VisitAlgebraNode(node.Left); node.Right = VisitAlgebraNode(node.Right); if (node.Predicate != null && (node.OuterReferences == null || node.OuterReferences.Length == 0) && ( node.Op == JoinAlgebraNode.JoinOperator.InnerJoin || node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin || node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin || node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin) ) { RowBufferEntry[] leftDefinedEntries = AstUtil.GetDefinedValueEntries(node.Left); RowBufferEntry[] rightDefinedEntries = AstUtil.GetDefinedValueEntries(node.Right); EqualPredicatesExtractor equalPredicatesExtractor = new EqualPredicatesExtractor(leftDefinedEntries, rightDefinedEntries); ExpressionNode probeResidual = equalPredicatesExtractor.VisitExpression(node.Predicate); BinaryExpression[] equalPredicates = equalPredicatesExtractor.GetEqualPredicates(); if (equalPredicates.Length > 0) { BinaryExpression equalPredicate = equalPredicates[0]; ExpressionBuilder expressionBuilder = new ExpressionBuilder(); expressionBuilder.Push(probeResidual); if (equalPredicates.Length > 1) { for (int i = 1; i < equalPredicates.Length; i++) { expressionBuilder.Push(equalPredicates[i]); } expressionBuilder.PushNAry(LogicalOperator.And); } probeResidual = expressionBuilder.Pop(); if (probeResidual is ConstantExpression) { probeResidual = null; } AlgebraNode leftInput = node.Left; AlgebraNode rightInput = node.Right; if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin) { node.Op = JoinAlgebraNode.JoinOperator.RightOuterJoin; leftInput = node.Right; rightInput = node.Left; ExpressionNode oldLeft = equalPredicate.Left; equalPredicate.Left = equalPredicate.Right; equalPredicate.Right = oldLeft; } RowBufferEntry leftEntry; RowBufferEntryExpression leftAsRowBufferEntryExpression = equalPredicate.Left as RowBufferEntryExpression; if (leftAsRowBufferEntryExpression != null) { leftEntry = leftAsRowBufferEntryExpression.RowBufferEntry; } else { leftEntry = new RowBufferEntry(equalPredicate.Left.ExpressionType); ComputedValueDefinition definedValue = new ComputedValueDefinition(); definedValue.Target = leftEntry; definedValue.Expression = equalPredicate.Left; ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = leftInput; computeScalarAlgebraNode.DefinedValues = new ComputedValueDefinition[] { definedValue }; leftInput = computeScalarAlgebraNode; } RowBufferEntry rightEntry; RowBufferEntryExpression rightAsRowBufferEntryExpression = equalPredicate.Right as RowBufferEntryExpression; if (rightAsRowBufferEntryExpression != null) { rightEntry = rightAsRowBufferEntryExpression.RowBufferEntry; } else { rightEntry = new RowBufferEntry(equalPredicate.Right.ExpressionType); ComputedValueDefinition definedValue = new ComputedValueDefinition(); definedValue.Target = rightEntry; definedValue.Expression = equalPredicate.Right; ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = rightInput; computeScalarAlgebraNode.DefinedValues = new ComputedValueDefinition[] { definedValue }; rightInput = computeScalarAlgebraNode; } HashMatchAlgebraNode hashMatchAlgebraNode = new HashMatchAlgebraNode(); hashMatchAlgebraNode.Op = node.Op; hashMatchAlgebraNode.Left = leftInput; hashMatchAlgebraNode.Right = rightInput; hashMatchAlgebraNode.BuildKeyEntry = leftEntry; hashMatchAlgebraNode.ProbeEntry = rightEntry; hashMatchAlgebraNode.ProbeResidual = probeResidual; return(hashMatchAlgebraNode); } } return(node); }
public override ExpressionNode VisitUnaryExpression(UnaryExpression expression) { // First visit arguments base.VisitUnaryExpression(expression); if (expression.Op == UnaryOperator.LogicalNot) { // Replace "NOT NOT expr" by "expr" UnaryExpression unOp = expression.Operand as UnaryExpression; if (unOp != null) { if (unOp.Op == UnaryOperator.LogicalNot) { return(VisitExpression(unOp.Operand)); } } // Replace "NOT expr IS NULL" and "NOT expr IS NOT NULL" by // "expr IS NOT NULL" and "expr IS NULL" resp. IsNullExpression isNull = expression.Operand as IsNullExpression; if (isNull != null) { isNull.Negated = !isNull.Negated; return(VisitExpression(isNull)); } // Apply negation on EXISTS ExistsSubselect existsSubselect = expression.Operand as ExistsSubselect; if (existsSubselect != null) { existsSubselect.Negated = !existsSubselect.Negated; return(existsSubselect); } // Apply negation on ALL/ANY subquery AllAnySubselect allAnySubselect = expression.Operand as AllAnySubselect; if (allAnySubselect != null) { allAnySubselect.Op = AstUtil.NegateBinaryOp(allAnySubselect.Op); allAnySubselect.Type = (allAnySubselect.Type == AllAnySubselect.AllAnyType.All) ? AllAnySubselect.AllAnyType.Any : AllAnySubselect.AllAnyType.All; return(allAnySubselect); } // Apply De Morgan's law BinaryExpression binOp = expression.Operand as BinaryExpression; if (binOp != null) { BinaryOperator negatedOp = AstUtil.NegateBinaryOp(binOp.Op); if (negatedOp != null) { ExpressionNode newLeft; ExpressionNode newRight; if (binOp.Op == BinaryOperator.LogicalAnd || binOp.Op == BinaryOperator.LogicalOr) { newLeft = new UnaryExpression(expression.Op, binOp.Left); newRight = new UnaryExpression(expression.Op, binOp.Right); } else { newLeft = binOp.Left; newRight = binOp.Right; } binOp.Op = negatedOp; binOp.Left = newLeft; binOp.Right = newRight; return(VisitExpression(binOp)); } } } return(expression); }