Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
        }