예제 #1
0
        /// <summary>
        /// For CASE statements which represent boolean values:
        ///
        ///  CASE XXX
        ///    WHEN AAA THEN true        ===>        (XXX==AAA) || (XXX==BBB)
        ///    WHEN BBB THEN true
        ///    ELSE false
        ///    etc.
        ///  END
        ///
        /// Also,
        ///
        ///  CASE XXX
        ///    WHEN AAA THEN false        ===>        (XXX!=AAA) && (XXX!=BBB)
        ///    WHEN BBB THEN false
        ///    ELSE true
        ///    etc.
        ///  END
        ///
        /// The reduce to a conjunction or disjunction of equality or inequality.
        /// The possibility of NULL in XXX is taken into account.
        /// </summary>
        private SqlExpression TryToWriteAsSimpleBooleanExpression(Type caseType, SqlExpression discriminator, List <SqlWhen> newWhens, bool allValuesLiteral)
        {
            SqlExpression rewrite = null;

            if (caseType == typeof(bool) && allValuesLiteral)
            {
                bool?holdsNull = SqlExpressionNullability.CanBeNull(discriminator);
                // The discriminator can't hold a NULL.
                // In this case, we don't need the special fallback that CASE-ELSE gives.
                // We can just construct a boolean operation.
                bool?whenValue = null;
                for (int i = 0; i < newWhens.Count; ++i)
                {
                    SqlValue lit   = (SqlValue)newWhens[i].Value; // Must be SqlValue because of allValuesLiteral.
                    bool     value = (bool)lit.Value;             // Must be bool because of caseType==typeof(bool).
                    if (newWhens[i].Match != null)
                    {                                             // Skip the ELSE
                        if (value)
                        {
                            rewrite = _sql.OrAccumulate(rewrite, _sql.Binary(SqlNodeType.EQ, discriminator, newWhens[i].Match));
                        }
                        else
                        {
                            rewrite = _sql.AndAccumulate(rewrite, _sql.Binary(SqlNodeType.NE, discriminator, newWhens[i].Match));
                        }
                    }
                    else
                    {
                        whenValue = value;
                    }
                }
                // If it could possibly hold null values.
                if (holdsNull != false && whenValue != null)
                {
                    if (whenValue == true)
                    {
                        rewrite = _sql.OrAccumulate(rewrite, _sql.Unary(SqlNodeType.IsNull, discriminator, discriminator.SourceExpression));
                    }
                    else
                    {
                        rewrite = _sql.AndAccumulate(rewrite, _sql.Unary(SqlNodeType.IsNotNull, discriminator, discriminator.SourceExpression));
                    }
                }
            }
            return(rewrite);
        }
예제 #2
0
 internal override SqlExpression VisitBinaryOperator(SqlBinary bo)
 {
     base.VisitBinaryOperator(bo);
     if (bo.NodeType.IsComparisonOperator() &&
         bo.Left.ClrType != typeof(bool) && bo.Right.ClrType != typeof(bool))
     {
         // Strip unnecessary CONVERT calls.
         if (bo.Left.NodeType == SqlNodeType.Convert)
         {
             var conv = (SqlUnary)bo.Left;
             if (CanDbConvert(conv.Operand.ClrType, bo.Right.ClrType) &&
                 conv.Operand.SqlType.ComparePrecedenceTo(bo.Right.SqlType) != 1)
             {
                 return(VisitBinaryOperator(new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, conv.Operand, bo.Right)));
             }
         }
         if (bo.Right.NodeType == SqlNodeType.Convert)
         {
             var conv = (SqlUnary)bo.Right;
             if (CanDbConvert(conv.Operand.ClrType, bo.Left.ClrType) &&
                 conv.Operand.SqlType.ComparePrecedenceTo(bo.Left.SqlType) != 1)
             {
                 return(VisitBinaryOperator(new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, bo.Left, conv.Operand)));
             }
         }
     }
     if (bo.Right != null && bo.NodeType != SqlNodeType.Concat)
     {
         SqlExpression left  = bo.Left;
         SqlExpression right = bo.Right;
         this.CoerceBinaryArgs(ref left, ref right);
         if (bo.Left != left || bo.Right != right)
         {
             bo = sql.Binary(bo.NodeType, left, right);
         }
         bo.SetSqlType(typeProvider.PredictTypeForBinary(bo.NodeType, left.SqlType, right.SqlType));
     }
     if (bo.NodeType.IsComparisonOperator())
     {
         // When comparing a unicode value against a non-unicode column,
         // we want retype the parameter as non-unicode.
         Func <SqlExpression, SqlExpression, bool> needsRetype =
             (expr, val) => (val.NodeType == SqlNodeType.Value || val.NodeType == SqlNodeType.ClientParameter) &&
             !(expr.NodeType == SqlNodeType.Value || expr.NodeType == SqlNodeType.ClientParameter) &&
             val.SqlType.IsUnicodeType && !expr.SqlType.IsUnicodeType;
         SqlSimpleTypeExpression valueToRetype = null;
         if (needsRetype(bo.Left, bo.Right))
         {
             valueToRetype = (SqlSimpleTypeExpression)bo.Right;
         }
         else if (needsRetype(bo.Right, bo.Left))
         {
             valueToRetype = (SqlSimpleTypeExpression)bo.Left;
         }
         if (valueToRetype != null)
         {
             valueToRetype.SetSqlType(valueToRetype.SqlType.GetNonUnicodeEquivalent());
         }
     }
     return(bo);
 }
예제 #3
0
            private SqlBinary MakeCompareTo(SqlExpression left, SqlExpression right, SqlNodeType op, int iValue)
            {
                if (iValue == 0)
                {
                    return(sql.Binary(op, left, right));
                }
                if (op == SqlNodeType.EQ || op == SqlNodeType.EQ2V)
                {
                    switch (iValue)
                    {
                    case -1:
                        return(sql.Binary(SqlNodeType.LT, left, right));

                    case 1:
                        return(sql.Binary(SqlNodeType.GT, left, right));
                    }
                }
                return(null);
            }