/// <summary>
            /// Constructs a join propagator.
            /// </summary>
            /// <param name="left">Result of propagating changes in the left input to the join</param>
            /// <param name="right">Result of propagating changes in the right input to the join</param>
            /// <param name="node">Join operator in update mapping view over which to propagate changes</param>
            /// <param name="parent">Handler of propagation for the entire update mapping view</param>
            internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent)
            {
                EntityUtil.CheckArgumentNull(left, "left");
                EntityUtil.CheckArgumentNull(right, "right");
                EntityUtil.CheckArgumentNull(node, "node");
                EntityUtil.CheckArgumentNull(parent, "parent");

                m_left = left;
                m_right = right;
                m_joinExpression = node;
                m_parent = parent;

                Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " +
                    "caller must ensure only left outer and inner joins are requested");
                // Retrieve propagation rules for the join type of the expression.
                if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind)
                {
                    m_insertRules = s_innerJoinInsertRules;
                    m_deleteRules = s_innerJoinDeleteRules;
                }
                else
                {
                    m_insertRules = s_leftOuterJoinInsertRules;
                    m_deleteRules = s_leftOuterJoinDeleteRules;
                }

                // Figure out key selectors involved in the equi-join (if it isn't an equi-join, we don't support it)
                JoinConditionVisitor.GetKeySelectors(node.JoinCondition, out m_leftKeySelectors, out m_rightKeySelectors);

                // Find the key selector expressions in the left and right placeholders
                m_leftPlaceholderKey = ExtractKey(m_left.Placeholder, m_leftKeySelectors, m_parent);
                m_rightPlaceholderKey = ExtractKey(m_right.Placeholder, m_rightKeySelectors, m_parent);
            }
Exemple #2
0
        // <summary>
        // Propagates changes across a join expression node by implementing progation rules w.r.t. inputs
        // from the left- and right- hand sides of the join. The work is actually performed
        // by the <see cref="JoinPropagator" />.
        // </summary>
        // <param name="node"> A join expression node. </param>
        // <returns> Results propagated to the given join expression node. </returns>
        public override ChangeNode Visit(DbJoinExpression node)
        {
            Check.NotNull(node, "node");

            if (DbExpressionKind.InnerJoin != node.ExpressionKind &&
                DbExpressionKind.LeftOuterJoin != node.ExpressionKind)
            {
                throw new NotSupportedException(Strings.Update_UnsupportedJoinType(node.ExpressionKind));
            }

            // There are precisely two inputs to the join which we treat as the left and right children.
            var leftExpr  = node.Left.Expression;
            var rightExpr = node.Right.Expression;

            // Get the results of propagating changes to the left and right inputs to the join.
            var left  = Visit(leftExpr);
            var right = Visit(rightExpr);

            // Construct a new join propagator, passing in the left and right results, the actual
            // join expression, and this parent propagator.
            var evaluator = new JoinPropagator(left, right, node, this);

            // Execute propagation.
            var result = evaluator.Propagate();

            return(result);
        }
Exemple #3
0
        public override LegacyCommandTrees.DbExpression Visit(DbJoinExpression expression)
        {
            Debug.Assert(expression != null, "expression != null");

            switch (expression.ExpressionKind)
            {
            case DbExpressionKind.InnerJoin:
                return
                    (expression.Left.Expression.Accept(this)
                     .BindAs(expression.Left.VariableName)
                     .InnerJoin(
                         expression.Right.Expression.Accept(this).BindAs(expression.Right.VariableName),
                         expression.JoinCondition.Accept(this)));

            case DbExpressionKind.LeftOuterJoin:
                return
                    (expression.Left.Expression.Accept(this)
                     .BindAs(expression.Left.VariableName)
                     .LeftOuterJoin(
                         expression.Right.Expression.Accept(this).BindAs(expression.Right.VariableName),
                         expression.JoinCondition.Accept(this)));

            case DbExpressionKind.FullOuterJoin:
                return
                    (expression.Left.Expression.Accept(this)
                     .BindAs(expression.Left.VariableName)
                     .FullOuterJoin(
                         expression.Right.Expression.Accept(this).BindAs(expression.Right.VariableName),
                         expression.JoinCondition.Accept(this)));
            }

            Debug.Fail("Unknown comparison operator.");

            throw new NotSupportedException();
        }
Exemple #4
0
            /// <summary>
            /// Constructs a join propagator.
            /// </summary>
            /// <param name="left">Result of propagating changes in the left input to the join</param>
            /// <param name="right">Result of propagating changes in the right input to the join</param>
            /// <param name="node">Join operator in update mapping view over which to propagate changes</param>
            /// <param name="parent">Handler of propagation for the entire update mapping view</param>
            internal JoinPropagator(ChangeNode left, ChangeNode right, DbJoinExpression node, Propagator parent)
            {
                EntityUtil.CheckArgumentNull(left, "left");
                EntityUtil.CheckArgumentNull(right, "right");
                EntityUtil.CheckArgumentNull(node, "node");
                EntityUtil.CheckArgumentNull(parent, "parent");

                m_left           = left;
                m_right          = right;
                m_joinExpression = node;
                m_parent         = parent;

                Debug.Assert(DbExpressionKind.LeftOuterJoin == node.ExpressionKind || DbExpressionKind.InnerJoin == node.ExpressionKind, "(Update/JoinPropagagtor/JoinEvaluator) " +
                             "caller must ensure only left outer and inner joins are requested");
                // Retrieve propagation rules for the join type of the expression.
                if (DbExpressionKind.InnerJoin == m_joinExpression.ExpressionKind)
                {
                    m_insertRules = s_innerJoinInsertRules;
                    m_deleteRules = s_innerJoinDeleteRules;
                }
                else
                {
                    m_insertRules = s_leftOuterJoinInsertRules;
                    m_deleteRules = s_leftOuterJoinDeleteRules;
                }

                // Figure out key selectors involved in the equi-join (if it isn't an equi-join, we don't support it)
                JoinConditionVisitor.GetKeySelectors(node.JoinCondition, out m_leftKeySelectors, out m_rightKeySelectors);

                // Find the key selector expressions in the left and right placeholders
                m_leftPlaceholderKey  = ExtractKey(m_left.Placeholder, m_leftKeySelectors, m_parent);
                m_rightPlaceholderKey = ExtractKey(m_right.Placeholder, m_rightKeySelectors, m_parent);
            }
Exemple #5
0
        public override ISqlFragment Visit(DbJoinExpression e)
        {
            #region Map join type to a string
            string joinString;
            switch (e.ExpressionKind)
            {
            case DbExpressionKind.FullOuterJoin:
                joinString = "FULL OUTER JOIN";
                break;

            case DbExpressionKind.InnerJoin:
                joinString = "INNER JOIN";
                break;

            case DbExpressionKind.LeftOuterJoin:
                joinString = "LEFT OUTER JOIN";
                break;

            default:
                Debug.Assert(false);
                joinString = null;
                break;
            }
            #endregion

            var inputs = new List <DbExpressionBinding> {
                e.Left, e.Right
            };
            return(VisitJoinExpression(inputs, e.ExpressionKind, joinString, e.JoinCondition));
        }
Exemple #6
0
        /// <summary>
        /// Walks the structure
        /// </summary>
        /// <param name="expression">The DbJoinExpression that is being visited.</param>
        /// <returns></returns>
        public override bool Visit(DbJoinExpression expression)
        {
            bool leftNeedsRewrite      = VisitExpressionBinding(expression.Left);
            bool rightNeedsRewrite     = VisitExpressionBinding(expression.Right);
            bool conditionNeedsRewrite = VisitExpression(expression.JoinCondition);

            return(leftNeedsRewrite || rightNeedsRewrite || conditionNeedsRewrite);
        }
 public override void Visit(DbJoinExpression e)
 {
     Begin(e);
     Dump(e.Left, "Left");
     Dump(e.Right, "Right");
     Dump(e.JoinCondition, "JoinCondition");
     End(e);
 }
Exemple #8
0
 public override VfpExpression Visit(DbJoinExpression expression)
 {
     return(new VfpJoinExpression((VfpExpressionKind)expression.ExpressionKind,
                                  expression.ResultType,
                                  CreateDbExpressionBinding(expression.Left),
                                  CreateDbExpressionBinding(expression.Right),
                                  expression.JoinCondition.Accept(this)));
 }
Exemple #9
0
        public override bool Visit(DbJoinExpression expression)
        {
            bool flag1 = VisitExpressionBinding(expression.Left);
            bool flag2 = VisitExpressionBinding(expression.Right);
            bool flag3 = VisitExpression(expression.JoinCondition);

            return(flag1 || flag2 || flag3);
        }
Exemple #10
0
 public override void Visit(DbJoinExpression expression)
 {
     EntityUtils.CheckArgumentNull <DbJoinExpression>(expression, nameof(expression));
     this.VisitExpressionBindingPre(expression.Left);
     this.VisitExpressionBindingPre(expression.Right);
     this.VisitExpression(expression.JoinCondition);
     this.VisitExpressionBindingPost(expression.Left);
     this.VisitExpressionBindingPost(expression.Right);
 }
Exemple #11
0
 public override void Visit(DbJoinExpression expression)
 {
     Write(expression);
     _depth++;
     Write("JoinCondition", expression.JoinCondition);
     Write("Left", expression.Left);
     Write("Right", expression.Right);
     _depth--;
 }
Exemple #12
0
 public override void Visit(DbJoinExpression e)
 {
     Check.NotNull <DbJoinExpression>(e, nameof(e));
     this.Begin((DbExpression)e);
     this.Dump(e.Left, "Left");
     this.Dump(e.Right, "Right");
     this.Dump(e.JoinCondition, "JoinCondition");
     this.End((DbExpression)e);
 }
        public override Expression Visit(DbJoinExpression expression)
        {
            if (expression.ExpressionKind == DbExpressionKind.FullOuterJoin)
            {
                throw new NotSupportedException("Full outer join is not yet supported");
            }

            Expression left = this.Visit(expression.Left.Expression);
            Expression right = this.Visit(expression.Right.Expression);

            Type leftType = TypeHelper.GetElementType(left.Type);
            Type rightType = TypeHelper.GetElementType(right.Type);

            ParameterExpression leftParam =
                Expression.Parameter(leftType, expression.Left.VariableName);

            ParameterExpression rightParam = 
                Expression.Parameter(rightType, expression.Right.VariableName);

            using (this.CreateVariable(leftParam, leftParam.Name))
            using (this.CreateVariable(rightParam, rightParam.Name))
            {
                LambdaExpression joinCondition =
                    Expression.Lambda(
                        this.Visit(expression.JoinCondition),
                        rightParam);

                // The Where expression represents the join condition
                // The NMemory query compiler will optimize this into a Join expression

                Expression innerExpression =
                    this.queryMethodExpressionBuilder.Where(right, joinCondition);
                
                if (expression.ExpressionKind == DbExpressionKind.LeftOuterJoin)
                {
                    innerExpression =
                        queryMethodExpressionBuilder.DefaultIfEmpty(innerExpression);
                }

                // Collection expression for the SelectMany
                LambdaExpression collectionSelector =
                    Expression.Lambda(
                        Expression.Convert(
                            innerExpression,
                            typeof(IEnumerable<>).MakeGenericType(rightType)),
                    leftParam);

                Expression result = this.CreateCrossJoin(
                    left,
                    collectionSelector,
                    leftParam.Name,
                    rightParam.Name);

                return result;
            }
        }
        public override Expression Visit(DbJoinExpression expression)
        {
            if (expression.ExpressionKind == DbExpressionKind.FullOuterJoin)
            {
                throw new NotSupportedException("Full outer join is not yet supported");
            }

            Expression left  = this.Visit(expression.Left.Expression);
            Expression right = this.Visit(expression.Right.Expression);

            Type leftType  = TypeHelper.GetElementType(left.Type);
            Type rightType = TypeHelper.GetElementType(right.Type);

            ParameterExpression leftParam =
                Expression.Parameter(leftType, expression.Left.VariableName);

            ParameterExpression rightParam =
                Expression.Parameter(rightType, expression.Right.VariableName);

            using (this.CreateVariable(leftParam, leftParam.Name))
                using (this.CreateVariable(rightParam, rightParam.Name))
                {
                    LambdaExpression joinCondition =
                        Expression.Lambda(
                            this.Visit(expression.JoinCondition),
                            rightParam);

                    // The Where expression represents the join condition
                    // The NMemory query compiler will optimize this into a Join expression

                    Expression innerExpression =
                        this.queryMethodExpressionBuilder.Where(right, joinCondition);

                    if (expression.ExpressionKind == DbExpressionKind.LeftOuterJoin)
                    {
                        innerExpression =
                            queryMethodExpressionBuilder.DefaultIfEmpty(innerExpression);
                    }

                    // Collection expression for the SelectMany
                    LambdaExpression collectionSelector =
                        Expression.Lambda(
                            Expression.Convert(
                                innerExpression,
                                typeof(IEnumerable <>).MakeGenericType(rightType)),
                            leftParam);

                    Expression result = this.CreateCrossJoin(
                        left,
                        collectionSelector,
                        leftParam.Name,
                        rightParam.Name);

                    return(result);
                }
        }
Exemple #15
0
 public override void Visit(DbJoinExpression e)
 {
     VisitExprKind(e.ExpressionKind);
     _key.Append('(');
     VisitBinding(e.Left);
     VisitBinding(e.Right);
     _key.Append('(');
     e.JoinCondition.Accept(this);
     _key.Append("))");
 }
Exemple #16
0
            public override TreeNode Visit(DbJoinExpression e)
            {
                Check.NotNull <DbJoinExpression>(e, nameof(e));
                TreeNode treeNode = ExpressionPrinter.PrinterVisitor.NodeFromExpression((DbExpression)e);

                treeNode.Children.Add(this.VisitBinding("Left", e.Left));
                treeNode.Children.Add(this.VisitBinding("Right", e.Right));
                treeNode.Children.Add(this.Visit("JoinCondition", e.JoinCondition));
                return(treeNode);
            }
Exemple #17
0
        /// <summary>
        ///     Walks the structure
        /// </summary>
        /// <param name="expression"> The DbJoinExpression that is being visited. </param>
        /// <returns> </returns>
        public override bool Visit(DbJoinExpression expression)
        {
            Check.NotNull(expression, "expression");

            var leftNeedsRewrite      = VisitExpressionBinding(expression.Left);
            var rightNeedsRewrite     = VisitExpressionBinding(expression.Right);
            var conditionNeedsRewrite = VisitExpression(expression.JoinCondition);

            return(leftNeedsRewrite || rightNeedsRewrite || conditionNeedsRewrite);
        }
            public override TreeNode Visit(DbJoinExpression e)
            {
                TreeNode retInfo = NodeFromExpression(e);

                retInfo.Children.Add(this.VisitBinding("Left", e.Left));
                retInfo.Children.Add(this.VisitBinding("Right", e.Right));
                retInfo.Children.Add(this.Visit("JoinCondition", e.JoinCondition));

                return(retInfo);
            }
Exemple #19
0
 public override void Visit(DbJoinExpression e)
 {
     Check.NotNull <DbJoinExpression>(e, nameof(e));
     this.VisitExprKind(e.ExpressionKind);
     this._key.Append('(');
     this.VisitBinding(e.Left);
     this.VisitBinding(e.Right);
     this._key.Append('(');
     e.JoinCondition.Accept((DbExpressionVisitor)this);
     this._key.Append("))");
 }
Exemple #20
0
        /// <summary>
        /// Implements the visitor pattern for <see cref="T:System.Data.Common.CommandTrees.DbJoinExpression"/>.
        /// </summary>
        /// <param name="expression">The <see cref="T:System.Data.Common.CommandTrees.DbJoinExpression"/> that is visited.</param>
        public override void Visit(DbJoinExpression expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            expression.Left.Expression.Accept(this);
            expression.Right.Expression.Accept(this);
            expression.JoinCondition.Accept(this);
        }
Exemple #21
0
            public override TreeNode Visit(DbJoinExpression e)
            {
                Check.NotNull(e, "e");

                var retInfo = NodeFromExpression(e);

                retInfo.Children.Add(VisitBinding("Left", e.Left));
                retInfo.Children.Add(VisitBinding("Right", e.Right));
                retInfo.Children.Add(Visit("JoinCondition", e.JoinCondition));

                return(retInfo);
            }
 public override void Visit(DbJoinExpression expression)
 {
     if (expression == null)
     {
         throw new ArgumentException("expression");
     }
     VisitExpressionBindingPre(expression.Left);
     VisitExpressionBindingPre(expression.Right);
     VisitExpression(expression.JoinCondition);
     VisitExpressionBindingPost(expression.Left);
     VisitExpressionBindingPost(expression.Right);
 }
        protected override Expression VisitJoin(DbJoinExpression join)
        {
            if (join.JoinType == JoinType.CrossJoin)
            {
                this.VisitJoinLeft(join.Left);
                this.Write(", ");
                this.VisitJoinRight(join.Right);

                return(join);
            }

            return(base.VisitJoin(join));
        }
Exemple #24
0
            public override DbExpression Visit(DbJoinExpression expression)
            {
                var visitor = new TemporalTableVisitor();

                visitor.ProcessExpression(expression.JoinCondition);

                if (visitor.IsTemporalExpression)
                {
                    return(DbExpressionBuilder.InnerJoin(expression.Left, expression.Right, visitor.Expression));
                }

                return(base.Visit(expression));
            }
        /// <summary>
        ///     Visitor pattern method for <see cref="DbJoinExpression" />.
        /// </summary>
        /// <param name="expression"> The DbJoinExpression that is being visited. </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="expression" />
        ///     is null
        /// </exception>
        public override void Visit(DbJoinExpression expression)
        {
            // #433613: PreSharp warning 56506: Parameter 'expression' to this public method must be validated: A null-dereference can occur here.
            Check.NotNull(expression, "expression");

            VisitExpressionBindingPre(expression.Left);
            VisitExpressionBindingPre(expression.Right);

            VisitExpression(expression.JoinCondition);

            VisitExpressionBindingPost(expression.Left);
            VisitExpressionBindingPost(expression.Right);
        }
Exemple #26
0
        public override bool Visit(DbJoinExpression expression)
        {
            Check.NotNull <DbJoinExpression>(expression, nameof(expression));
            bool flag1 = this.VisitExpressionBinding(expression.Left);
            bool flag2 = this.VisitExpressionBinding(expression.Right);
            bool flag3 = this.VisitExpression(expression.JoinCondition);

            if (!flag1 && !flag2)
            {
                return(flag3);
            }
            return(true);
        }
Exemple #27
0
        protected override Expression VisitJoin(DbJoinExpression join)
        {
            this.VisitJoinLeft(join.Left);
            this.WriteLine(Indentation.Same);
            switch (join.Join)
            {
            case DbJoinType.CrossJoin:
                this.Write("CROSS JOIN ");
                break;

            case DbJoinType.InnerJoin:
                this.Write("INNER JOIN ");
                break;

            case DbJoinType.CrossApply:
                this.Write("CROSS APPLY ");
                break;

            case DbJoinType.OuterApply:
                this.Write("OUTER APPLY ");
                break;

            case DbJoinType.LeftOuter:
            case DbJoinType.SingletonLeftOuter:
                this.Write("LEFT OUTER JOIN ");
                break;
            }
            this.VisitJoinRight(join.Right);
            if (join.Condition != null)
            {
                this.WriteLine(Indentation.Inner);
                this.Write("ON ");
                this.VisitPredicate(join.Condition);
                this.Indent(Indentation.Outer);
            }
            return(join);
        }
		public override void Visit(DbJoinExpression expression)
		{
			throw new NotSupportedException("Visit(\"JoinExpression\") is not supported.");
		}
Exemple #29
0
 public override SqlFragment Visit(DbJoinExpression expression)
 {
     throw new NotImplementedException();
 }
 public override DbExpression Visit(DbJoinExpression expression)
 {
     System.Diagnostics.Debug.Print("Visit(DbJoinExpression): {0}", expression);
     return base.Visit(expression);
 }
        /// <summary>
        ///     Visitor pattern method for <see cref="DbJoinExpression" />.
        /// </summary>
        /// <param name="expression"> The DbJoinExpression that is being visited. </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="expression" />
        ///     is null
        /// </exception>
        public override void Visit(DbJoinExpression expression)
        {
            // #433613: PreSharp warning 56506: Parameter 'expression' to this public method must be validated: A null-dereference can occur here.
            Check.NotNull(expression, "expression");

            VisitExpressionBindingPre(expression.Left);
            VisitExpressionBindingPre(expression.Right);

            VisitExpression(expression.JoinCondition);

            VisitExpressionBindingPost(expression.Left);
            VisitExpressionBindingPost(expression.Right);
        }
        /// <summary>
        ///     Visitor pattern method for <see cref="DbJoinExpression" />.
        /// </summary>
        /// <param name="expression"> The DbJoinExpression that is being visited. </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="expression" />
        ///     is null
        /// </exception>
        public override void Visit(DbJoinExpression expression)
        {
            Check.NotNull(expression, "expression");

            VisitExpressionBindingPre(expression.Left);
            VisitExpressionBindingPre(expression.Right);

            VisitExpression(expression.JoinCondition);

            VisitExpressionBindingPost(expression.Left);
            VisitExpressionBindingPost(expression.Right);
        }
Exemple #33
0
 public override void Visit(DbJoinExpression expression)
 {
     throw new NotSupportedException("Visit(\"DbJoinExpression\") is not supported.");
 }
Exemple #34
0
 public override object Visit(DbJoinExpression expression)
 {
     this.Visit(expression.Left.Expression);
     this.Visit(expression.Right.Expression);
     return(null);
 }
 public override SqlFragment Visit(DbJoinExpression expression)
 {
     return(HandleJoinExpression(expression.Left, expression.Right,
                                 expression.ExpressionKind, expression.JoinCondition));
 }
 public override void Visit(DbJoinExpression e)
 {
     VisitExprKind(e.ExpressionKind);
     _key.Append('(');
     VisitBinding(e.Left);
     VisitBinding(e.Right);
     _key.Append('(');
     e.JoinCondition.Accept(this);
     _key.Append("))");
 }
        /// <summary>
        /// Implements the visitor pattern for <see cref="T:System.Data.Common.CommandTrees.DbJoinExpression"/>.
        /// </summary>
        /// <param name="expression">The <see cref="T:System.Data.Common.CommandTrees.DbJoinExpression"/> that is visited.</param>
        public override void Visit(DbJoinExpression expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            expression.Left.Expression.Accept(this);
            expression.Right.Expression.Accept(this);
            expression.JoinCondition.Accept(this);
        }
 public override void Visit(DbJoinExpression e)
 {
     Begin(e);
     Dump(e.Left, "Left");
     Dump(e.Right, "Right");
     Dump(e.JoinCondition, "JoinCondition");
     End(e);
 }
 public override void Visit(DbJoinExpression expression) { }
 public override SqlFragment Visit(DbJoinExpression expression)
 {
     return HandleJoinExpression(expression.Left, expression.Right, 
         expression.ExpressionKind, expression.JoinCondition);
 }
 /// <summary>
 ///     Visitor pattern method for DbJoinExpression.
 /// </summary>
 /// <param name="expression"> The DbJoinExpression that is being visited. </param>
 public abstract void Visit(DbJoinExpression expression);
 public override void Visit(DbJoinExpression expression)
 {
   if (expression == null) throw new ArgumentException("expression");
   VisitExpressionBindingPre(expression.Left);
   VisitExpressionBindingPre(expression.Right);
   VisitExpression(expression.JoinCondition);
   VisitExpressionBindingPost(expression.Left);
   VisitExpressionBindingPost(expression.Right);
 }
 public override void Visit(DbJoinExpression expression)
 {
     Contract.Requires(expression != null);
 }
Exemple #44
0
 public override DbExpressionEntitySetInfo Visit(DbJoinExpression expression)
 {
     return(null);
 }
        /// <summary>
        /// Visitor pattern method for <see cref="DbJoinExpression"/>.
        /// </summary>
        /// <param name="expression">The DbJoinExpression that is being visited.</param>
        /// <exception cref="ArgumentNullException"><paramref name="expression"/> is null</exception>
        public override void Visit(DbJoinExpression expression)
        {
            VisitExpressionBindingPre(expression.Left);
            VisitExpressionBindingPre(expression.Right);

            VisitExpression(expression.JoinCondition);

            VisitExpressionBindingPost(expression.Left);
            VisitExpressionBindingPost(expression.Right);
        }