public override ExpressionNode VisitExistsSubselect(ExistsSubselect expression)
        {
            AlgebraNode       input           = GetAndResetLastNode();
            ResultAlgebraNode algebrizedQuery = Algebrizer.Convert(expression.Query);

            if (!expression.Negated && AstUtil.WillProduceAtLeastOneRow(algebrizedQuery))
            {
                if (input == null)
                {
                    SetLastAlgebraNode(CreateConstantScan());
                }
                else
                {
                    SetLastAlgebraNode(input);
                }

                return(LiteralExpression.FromBoolean(true));
            }


            if (!expression.Negated && !ProbingEnabled && input == null)
            {
                SetLastAlgebraNode(algebrizedQuery);
                return(LiteralExpression.FromBoolean(true));
            }
            else
            {
                if (input == null)
                {
                    input = CreateConstantScan();
                }

                RowBufferEntry probeColumn = CreateProbeColumn();

                JoinAlgebraNode joinAlgebraNode = new JoinAlgebraNode();
                joinAlgebraNode.PassthruPredicate = CurrentPassthruPredicate;
                joinAlgebraNode.ProbeBufferEntry  = probeColumn;
                joinAlgebraNode.Left  = input;
                joinAlgebraNode.Right = algebrizedQuery;
                joinAlgebraNode.Op    = expression.Negated ? JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin : JoinAlgebraNode.JoinOperator.LeftSemiJoin;
                SetLastAlgebraNode(joinAlgebraNode);

                return(CreateProbeColumnRef(probeColumn));
            }
        }
        public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node)
        {
            node.Left  = VisitAlgebraNode(node.Left);
            node.Right = VisitAlgebraNode(node.Right);

            bool leftIsNull  = node.Left is NullScanAlgebraNode;
            bool rightIsNull = node.Right is NullScanAlgebraNode;
            bool joinConditionAlwaysFalse = false;

            if (node.Predicate != null)
            {
                ExpressionNode     predicate           = node.Predicate;
                ConstantExpression predicateAsConstant = predicate as ConstantExpression;
                if (predicateAsConstant != null)
                {
                    if (predicateAsConstant.AsBoolean)
                    {
                        node.Predicate = null;
                    }
                    else
                    {
                        joinConditionAlwaysFalse = true;
                    }
                }
            }

            if (node.Op == JoinAlgebraNode.JoinOperator.RightOuterJoin ||
                node.Op == JoinAlgebraNode.JoinOperator.RightSemiJoin ||
                node.Op == JoinAlgebraNode.JoinOperator.RightAntiSemiJoin)
            {
                node.SwapSides();
            }

            switch (node.Op)
            {
            case JoinAlgebraNode.JoinOperator.InnerJoin:
                if (joinConditionAlwaysFalse || leftIsNull || rightIsNull)
                {
                    return(CreateNullScan(node.OutputList));
                }
                break;

            case JoinAlgebraNode.JoinOperator.FullOuterJoin:
                if (leftIsNull && rightIsNull)
                {
                    return(CreateNullScan(node.OutputList));
                }
                if (leftIsNull)
                {
                    return(PadRightWithNullsOnLeftSide(node, RowBufferCreationMode.KeepExisting));
                }
                if (rightIsNull)
                {
                    return(PadLeftWithNullsOnRightSide(node, RowBufferCreationMode.KeepExisting));
                }
                if (joinConditionAlwaysFalse)
                {
                    AlgebraNode left  = PadLeftWithNullsOnRightSide(node, RowBufferCreationMode.CreateNew);
                    AlgebraNode right = PadRightWithNullsOnLeftSide(node, RowBufferCreationMode.CreateNew);

                    ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode();
                    concatAlgebraNode.Inputs = new AlgebraNode[] { left, right };

                    List <RowBufferEntry>        outputList    = new List <RowBufferEntry>();
                    List <UnitedValueDefinition> definedValues = new List <UnitedValueDefinition>();
                    for (int i = 0; i < node.Left.OutputList.Length; i++)
                    {
                        int leftIndex  = i;
                        int rightIndex = node.Right.OutputList.Length + i;

                        UnitedValueDefinition definedValue = new UnitedValueDefinition();
                        definedValue.Target           = node.Left.OutputList[leftIndex];
                        definedValue.DependendEntries = new RowBufferEntry[] { left.OutputList[leftIndex], right.OutputList[rightIndex] };
                        definedValues.Add(definedValue);
                        outputList.Add(definedValue.Target);
                    }
                    for (int i = 0; i < node.Right.OutputList.Length; i++)
                    {
                        int leftIndex  = node.Left.OutputList.Length + i;
                        int rightIndex = i;

                        UnitedValueDefinition definedValue = new UnitedValueDefinition();
                        definedValue.Target           = node.Right.OutputList[rightIndex];
                        definedValue.DependendEntries = new RowBufferEntry[] { left.OutputList[leftIndex], right.OutputList[rightIndex] };
                        definedValues.Add(definedValue);
                        outputList.Add(definedValue.Target);
                    }

                    concatAlgebraNode.DefinedValues = definedValues.ToArray();
                    concatAlgebraNode.OutputList    = outputList.ToArray();
                    return(concatAlgebraNode);
                }
                break;

            case JoinAlgebraNode.JoinOperator.LeftOuterJoin:
                if (leftIsNull)
                {
                    return(CreateNullScan(node.OutputList));
                }
                if (rightIsNull || joinConditionAlwaysFalse)
                {
                    return(PadLeftWithNullsOnRightSide(node, RowBufferCreationMode.KeepExisting));
                }
                break;

            case JoinAlgebraNode.JoinOperator.LeftSemiJoin:
                if (leftIsNull || rightIsNull || joinConditionAlwaysFalse)
                {
                    return(CreateNullScan(node.OutputList));
                }
                if (node.Predicate == null && AstUtil.WillProduceAtLeastOneRow(node.Right))
                {
                    return(node.Left);
                }
                break;

            case JoinAlgebraNode.JoinOperator.LeftAntiSemiJoin:
                if (leftIsNull)
                {
                    return(CreateNullScan(node.OutputList));
                }
                if (rightIsNull || joinConditionAlwaysFalse)
                {
                    return(node.Left);
                }
                if (node.Predicate == null && AstUtil.WillProduceAtLeastOneRow(node.Right))
                {
                    return(CreateNullScan(node.OutputList));
                }
                break;
            }

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