Beispiel #1
0
        private AlgebraNode PushOverJoin(ComputeScalarAlgebraNode node)
        {
            JoinAlgebraNode joinAlgebraNode = (JoinAlgebraNode)node.Input;

            RowBufferEntry[] leftDefinedValues  = AstUtil.GetDefinedValueEntries(joinAlgebraNode.Left);
            RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(joinAlgebraNode.Right);

            List <ComputedValueDefinition> remainingValueDefinitions   = new List <ComputedValueDefinition>();
            List <ComputedValueDefinition> leftPushedValueDefinitions  = new List <ComputedValueDefinition>();
            List <ComputedValueDefinition> rightPushedValueDefinitions = new List <ComputedValueDefinition>();

            bool canPushToLeftSide = joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin &&
                                     joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin;

            bool canPushToRightSide = joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin &&
                                      joinAlgebraNode.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin;

            foreach (ComputedValueDefinition valueDefinition in node.DefinedValues)
            {
                RowBufferEntry[] referencedValues      = AstUtil.GetRowBufferEntryReferences(valueDefinition.Expression);
                bool             referencesProbeColumn = ArrayHelpers.Contains(referencedValues, joinAlgebraNode.ProbeBufferEntry);

                if (!referencesProbeColumn && canPushToLeftSide && AstUtil.DoesNotReference(referencedValues, rightDefinedValues))
                {
                    leftPushedValueDefinitions.Add(valueDefinition);
                }
                else if (!referencesProbeColumn && canPushToRightSide && AstUtil.DoesNotReference(referencedValues, leftDefinedValues))
                {
                    rightPushedValueDefinitions.Add(valueDefinition);
                }
                else
                {
                    remainingValueDefinitions.Add(valueDefinition);
                }
            }

            if (leftPushedValueDefinitions.Count > 0)
            {
                ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode();
                computeScalarAlgebraNode.DefinedValues = leftPushedValueDefinitions.ToArray();
                computeScalarAlgebraNode.Input         = joinAlgebraNode.Left;
                joinAlgebraNode.Left = VisitAlgebraNode(computeScalarAlgebraNode);
            }

            if (rightPushedValueDefinitions.Count > 0)
            {
                ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode();
                computeScalarAlgebraNode.DefinedValues = rightPushedValueDefinitions.ToArray();
                computeScalarAlgebraNode.Input         = joinAlgebraNode.Right;
                joinAlgebraNode.Right = VisitAlgebraNode(computeScalarAlgebraNode);
            }

            if (remainingValueDefinitions.Count == 0)
            {
                return(joinAlgebraNode);
            }

            node.DefinedValues = remainingValueDefinitions.ToArray();
            return(node);
        }
 private void AddNeededRowBufferEntryReferences(ExpressionNode expression)
 {
     RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression);
     foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
     {
         AddNeededRowBufferEntry(rowBufferEntry);
     }
 }
Beispiel #3
0
        private static bool AndPartHasOuterReference(ExpressionNode andPart, RowBufferEntry[] definedValues)
        {
            RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart);
            foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
            {
                if (!ArrayHelpers.Contains(definedValues, rowBufferEntry))
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #4
0
        private static ExpressionNode[] GetAndPartsApplicableToJoin(IDictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns, JoinOrder joinOrder, int joinIndex, ICollection <ExpressionNode> andParts, bool removeApplicableAndParts)
        {
            List <RowBufferEntry> columnsInJoin = new List <RowBufferEntry>();

            for (int i = 0; i <= joinIndex; i++)
            {
                foreach (ColumnRefBinding columnRefBinding in joinOrder.Joins[i].TableRefBinding.ColumnRefs)
                {
                    columnsInJoin.Add(columnRefBinding.ValueDefinition.Target);
                }
            }

            List <ExpressionNode> applicableAndParts = new List <ExpressionNode>();

            foreach (ExpressionNode andPart in andParts)
            {
                RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart);

                bool allDependenciesInJoin = true;
                foreach (RowBufferEntry entry in rowBufferEntries)
                {
                    if (!columnsInJoin.Contains(entry))
                    {
                        // Row buffer entry not available in the join the current position.
                        // It could be an outer reference. Check if the row buffer entry
                        // is in the set of introduced row buffer entries.

                        if (introducedColumns.ContainsKey(entry))
                        {
                            allDependenciesInJoin = false;
                            break;
                        }
                    }
                }

                if (allDependenciesInJoin)
                {
                    applicableAndParts.Add(andPart);
                }
            }

            if (removeApplicableAndParts)
            {
                foreach (ExpressionNode andPart in applicableAndParts)
                {
                    andParts.Remove(andPart);
                }
            }

            return(applicableAndParts.ToArray());
        }
Beispiel #5
0
 private bool CheckIfNodeHasDependenciesToOuterReferences(AlgebraNode node)
 {
     foreach (RowBufferEntry rowBufferEntryReference in AstUtil.GetRowBufferEntryReferences(node))
     {
         foreach (RowBufferEntry[] outerReferences in _outerReferences)
         {
             if (ArrayHelpers.Contains(outerReferences, rowBufferEntryReference))
             {
                 return(true);
             }
         }
     }
     return(false);
 }
Beispiel #6
0
            public override ExpressionNode VisitBinaryExpression(BinaryExpression expression)
            {
                if (expression.Op == BinaryOperator.LogicalAnd)
                {
                    return(base.VisitBinaryExpression(expression));
                }
                else if (expression.Op == BinaryOperator.Equal)
                {
                    RowBufferEntry[] leftRowBufferEntries  = AstUtil.GetRowBufferEntryReferences(expression.Left);
                    RowBufferEntry[] rightRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Right);

                    if (leftRowBufferEntries.Length == 1 && rightRowBufferEntries.Length == 1)
                    {
                        RowBufferEntry leftRowBufferEntry  = leftRowBufferEntries[0];
                        RowBufferEntry rightRowBufferEntry = rightRowBufferEntries[0];

                        if (leftRowBufferEntry != rightRowBufferEntry)
                        {
                            // Both expressions depend on extactly one row buffer entry but
                            // they are not refering to the same row buffer entry.

                            bool leftDependsOnLeft   = ArrayHelpers.Contains(_leftDefinedEntries, leftRowBufferEntry);
                            bool rightDependsOnRight = ArrayHelpers.Contains(_rightDefinedEntries, rightRowBufferEntry);

                            bool leftDependsOnRight = ArrayHelpers.Contains(_rightDefinedEntries, leftRowBufferEntry);
                            bool rightDependsOnLeft = ArrayHelpers.Contains(_leftDefinedEntries, rightRowBufferEntry);

                            if (leftDependsOnRight && rightDependsOnLeft)
                            {
                                ExpressionNode oldLeft = expression.Left;
                                expression.Left     = expression.Right;
                                expression.Right    = oldLeft;
                                leftDependsOnLeft   = true;
                                rightDependsOnRight = true;
                            }

                            if (leftDependsOnLeft && rightDependsOnRight)
                            {
                                _equalPredicates.Add(expression);
                                return(LiteralExpression.FromBoolean(true));
                            }
                        }
                    }
                }

                return(expression);
            }
Beispiel #7
0
        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);
        }
Beispiel #8
0
            public override ExpressionNode VisitBinaryExpression(BinaryExpression expression)
            {
                if (expression.Op == BinaryOperator.LogicalAnd)
                {
                    return(base.VisitBinaryExpression(expression));
                }
                else if (expression.Op == BinaryOperator.Equal)
                {
                    RowBufferEntry[] leftRowBufferEntries  = AstUtil.GetRowBufferEntryReferences(expression.Left);
                    RowBufferEntry[] rightRowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression.Right);

                    if (leftRowBufferEntries.Length == 1 && rightRowBufferEntries.Length == 1)
                    {
                        RowBufferEntry leftRowBufferEntry  = leftRowBufferEntries[0];
                        RowBufferEntry rightRowBufferEntry = rightRowBufferEntries[0];
                        bool           leftIsOuter         = IsOuterReference(leftRowBufferEntry);
                        bool           rightIsOuter        = IsOuterReference(rightRowBufferEntry);

                        if (leftRowBufferEntry != rightRowBufferEntry && leftIsOuter ^ rightIsOuter)
                        {
                            // Both expressions depend on extactly one row buffer entry but
                            // they are not refering to the same row buffer entry and
                            // only one is an outer reference.

                            SpoolExpression spoolExpression = new SpoolExpression();
                            if (leftIsOuter)
                            {
                                spoolExpression.IndexExpression = expression.Right;
                                spoolExpression.ProbeExpression = expression.Left;
                            }
                            else
                            {
                                spoolExpression.IndexExpression = expression.Left;
                                spoolExpression.ProbeExpression = expression.Right;
                            }

                            _spoolExpressions.Add(spoolExpression);
                            return(LiteralExpression.FromBoolean(true));
                        }
                    }
                }

                return(expression);
            }
Beispiel #9
0
        private static TableRefBinding[] GetTableReferences(IDictionary <RowBufferEntry, ColumnRefBinding> rowBufferColumnDictionary, ExpressionNode expression)
        {
            List <TableRefBinding> result = new List <TableRefBinding>();

            RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(expression);
            foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
            {
                ColumnRefBinding columnRefBinding;
                if (rowBufferColumnDictionary.TryGetValue(rowBufferEntry, out columnRefBinding))
                {
                    if (!result.Contains(columnRefBinding.TableRefBinding))
                    {
                        result.Add(columnRefBinding.TableRefBinding);
                    }
                }
            }

            return(result.ToArray());
        }
Beispiel #10
0
        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));
        }
Beispiel #11
0
        private static ExpressionNode ExtractConditionsApplicableToTable(IDictionary <RowBufferEntry, ColumnValueDefinition> introducedColumns, IList <ExpressionNode> conditionList, TableRefBinding tableRefBinding)
        {
            List <ExpressionNode> applicableConditionList = new List <ExpressionNode>();

            for (int i = conditionList.Count - 1; i >= 0; i--)
            {
                ExpressionNode   condition        = conditionList[i];
                RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(condition);

                bool dependentOnOtherTable = false;
                foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
                {
                    ColumnValueDefinition columnValueDefinition;
                    if (introducedColumns.TryGetValue(rowBufferEntry, out columnValueDefinition))
                    {
                        if (columnValueDefinition.ColumnRefBinding.TableRefBinding != tableRefBinding)
                        {
                            dependentOnOtherTable = true;
                            break;
                        }
                    }
                }

                if (!dependentOnOtherTable)
                {
                    conditionList.RemoveAt(i);
                    applicableConditionList.Add(condition);
                }
            }

            if (applicableConditionList.Count == 0)
            {
                return(null);
            }

            ExpressionNode[] applicableConditions = applicableConditionList.ToArray();
            return(AstUtil.CombineConditions(LogicalOperator.And, applicableConditions));
        }
Beispiel #12
0
        public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node)
        {
            // Get declared tables of left and right

            RowBufferEntry[] leftDefinedValues  = AstUtil.GetDefinedValueEntries(node.Left);
            RowBufferEntry[] rightDefinedValues = AstUtil.GetDefinedValueEntries(node.Right);

            // Replace outer joins by left-/right-/inner joins

            if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin ||
                node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin)
            {
                if (IsAnyNullRejected(leftDefinedValues))
                {
                    if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin)
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
                    }
                    else
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin;
                    }
                }
            }

            if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin ||
                node.Op == JoinAlgebraNode.JoinOperator.FullOuterJoin)
            {
                if (IsAnyNullRejected(rightDefinedValues))
                {
                    if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin)
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
                    }
                    else
                    {
                        node.Op = JoinAlgebraNode.JoinOperator.RightOuterJoin;
                    }
                }
            }

            // After converting an outer join to an inner one we can
            // sometimes eliminate the whole join.

            if (node.Op == JoinAlgebraNode.JoinOperator.InnerJoin)
            {
                // TODO: There is a problem. If the constant scan defines values this does not work. Acutally,
                //       this is currently no problem as the only way to create such a plan is using derived
                //       tables and in this phase the child will be a ResultNode.

                if (node.Left is ConstantScanAlgebraNode)
                {
                    return(VisitAlgebraNode(WrapWithFilter(node.Right, node.Predicate)));
                }

                if (node.Right is ConstantScanAlgebraNode)
                {
                    return(VisitAlgebraNode(WrapWithFilter(node.Left, node.Predicate)));
                }
            }

            // Analyze AND-parts of Condition

            if (node.Predicate == null)
            {
                // TODO: This does not work as the children are not yet rearranged.
                if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin ||
                    node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin)
                {
                    bool hasOuterReferences = AstUtil.GetOuterReferences(node).Length == 0;
                    if (!hasOuterReferences)
                    {
                        if (node.Op == JoinAlgebraNode.JoinOperator.LeftOuterJoin && AstUtil.WillProduceAtLeastOneRow(node.Right) ||
                            node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin && AstUtil.WillProduceAtLeastOneRow(node.Left))
                        {
                            node.Op = JoinAlgebraNode.JoinOperator.InnerJoin;
                            return(VisitAlgebraNode(node));
                        }
                    }
                }
            }
            else
            {
                foreach (ExpressionNode andPart in AstUtil.SplitCondition(LogicalOperator.And, node.Predicate))
                {
                    if (node.Op != JoinAlgebraNode.JoinOperator.FullOuterJoin)
                    {
                        // Check if we can derive from this AND-part that a table it depends on
                        // is null-rejected.

                        RowBufferEntry[] rowBufferEntries = AstUtil.GetRowBufferEntryReferences(andPart);
                        foreach (RowBufferEntry rowBufferEntry in rowBufferEntries)
                        {
                            if (AstUtil.ExpressionYieldsNullOrFalseIfRowBufferEntryNull(andPart, rowBufferEntry))
                            {
                                if (ArrayHelpers.Contains(leftDefinedValues, rowBufferEntry) &&
                                    node.Op != JoinAlgebraNode.JoinOperator.LeftOuterJoin)
                                {
                                    AddNullRejectedTable(rowBufferEntry);
                                }
                                else if (ArrayHelpers.Contains(rightDefinedValues, rowBufferEntry) &&
                                         node.Op != JoinAlgebraNode.JoinOperator.RightOuterJoin)
                                {
                                    AddNullRejectedTable(rowBufferEntry);
                                }
                            }
                        }
                    }
                }
            }

            // Visit children

            node.Left  = VisitAlgebraNode(node.Left);
            node.Right = VisitAlgebraNode(node.Right);

            return(node);
        }
Beispiel #13
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);
        }