public override AstNode Visit(AstNode node)
        {
            if (!(node is ExpressionNode))
            {
                // Non-expressions are visited as usual.
                return(base.Visit(node));
            }

            // First, we only visit expressions that contain a subquery.
            //
            // For correct handling of ProbeColumn we to decect whether probing
            // is required or not. Probing is only needed if the existance subquery
            // appears in an expression that is not a logical AND or logical OR (or
            // an existence subquery itself).

            if (AstUtil.ContainsSubselect(node))
            {
                BinaryExpression binaryExpression = node as BinaryExpression;
                bool             isLogicalLink    = binaryExpression != null &&
                                                    (binaryExpression.Op == BinaryOperator.LogicalAnd ||
                                                     binaryExpression.Op == BinaryOperator.LogicalOr);

                bool isExistenceSubquery = node.NodeType == AstNodeType.AllAnySubselect ||
                                           node.NodeType == AstNodeType.ExistsSubselect;

                bool requiresProbing = !isLogicalLink && !isExistenceSubquery;

                if (requiresProbing)
                {
                    _probingEnabledStack.Push(true);
                }

                AstNode resultExpression = base.Visit(node);

                if (requiresProbing)
                {
                    _probingEnabledStack.Pop();
                }

                return(resultExpression);
            }

            // Don't visit expressions that do not contain suqueries.
            return(node);
        }
        public override AlgebraNode VisitJoinAlgebraNode(JoinAlgebraNode node)
        {
            if (node.Predicate == null || !AstUtil.ContainsSubselect(node.Predicate))
            {
                return(base.VisitJoinAlgebraNode(node));
            }

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

            switch (node.Op)
            {
            case JoinAlgebraNode.JoinOperator.InnerJoin:
            {
                FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode();
                filterAlgebraNode.Predicate = node.Predicate;
                filterAlgebraNode.Input     = node;
                node.Predicate = null;

                SetLastAlgebraNode(node);
                _probingEnabledStack.Push(false);
                filterAlgebraNode.Predicate = VisitExpression(filterAlgebraNode.Predicate);
                _probingEnabledStack.Pop();
                filterAlgebraNode.Input = GetAndResetLastNode();

                return(filterAlgebraNode);
            }

            case JoinAlgebraNode.JoinOperator.LeftOuterJoin:
            {
                FilterAlgebraNode filterAlgebraNode = new FilterAlgebraNode();
                filterAlgebraNode.Predicate = node.Predicate;
                filterAlgebraNode.Input     = node.Right;

                node.Right     = filterAlgebraNode;
                node.Predicate = null;

                SetLastAlgebraNode(filterAlgebraNode.Input);
                _probingEnabledStack.Push(false);
                filterAlgebraNode.Predicate = VisitExpression(filterAlgebraNode.Predicate);
                _probingEnabledStack.Pop();
                filterAlgebraNode.Input = GetAndResetLastNode();

                return(node);
            }

            case JoinAlgebraNode.JoinOperator.RightOuterJoin:
            {
                node.Op = JoinAlgebraNode.JoinOperator.LeftOuterJoin;
                AlgebraNode oldLeft = node.Left;
                node.Left  = node.Right;
                node.Right = oldLeft;
                goto case JoinAlgebraNode.JoinOperator.LeftOuterJoin;
            }

            case JoinAlgebraNode.JoinOperator.FullOuterJoin:
                // TODO: Support subqueries in FULL OUTER JOIN.
                throw ExceptionBuilder.InternalError("FULL OUTER JOIN containing a subselect predicate in ON clause is not supported.");

            default:
                throw ExceptionBuilder.UnhandledCaseLabel(node.Op);
            }
        }
        public override 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));
            }
        }