/// <summary>
        /// Creates an Equal comparison of a nullable property (db column) to a nullable parameter (lambda param)
        /// that adds the necessary "is null" checks to support a filter like "e.TenantId = tenantId".
        /// Results in sql: (e.TenantID is null and @tenantID is null) or (e.TenantID is not null and e.TenantID = @tenantID)
        /// which will support parmeter values that are "null" or a specific value and will correctly filter on columns that
        /// are "null" or a specific value.
        /// </summary>
        /// <param name="propExpression"></param>
        /// <param name="paramExpression"></param>
        /// <returns></returns>
        private DbExpression CreateEqualComparisonOfNullablePropToNullableParam(DbExpression propExpression, DbExpression paramExpression)
        {
            var condition1 = propExpression.IsNull().And(paramExpression.IsNull());
            var condition2 = propExpression.IsNull().Not().And(propExpression.Equal(paramExpression));

            return(condition1.Or(condition2));
        }
Exemple #2
0
        private static DbExpression GeneratePredicate(
            ConditionPropertyMapping condition,
            DbExpression row)
        {
            DbExpression columnRef = FunctionImportMappingComposable.GenerateColumnRef(row, condition.Column);

            if (!condition.IsNull.HasValue)
            {
                return((DbExpression)columnRef.Equal((DbExpression)columnRef.ResultType.Constant(condition.Value)));
            }
            if (!condition.IsNull.Value)
            {
                return((DbExpression)columnRef.IsNull().Not());
            }
            return((DbExpression)columnRef.IsNull());
        }
            internal static CqtExpression StripNull(LinqExpression sourceExpression,
                                                    DbExpression inputExpression, DbExpression outputExpression, bool useDatabaseNullSemantics)
            {
                if (sourceExpression.IsNullConstant())
                {
                    return(DbExpressionBuilder.Constant(string.Empty));
                }

                if (sourceExpression.NodeType == ExpressionType.Constant)
                {
                    return(outputExpression);
                }

                if (useDatabaseNullSemantics)
                {
                    return(outputExpression);
                }

                // converts evaluated null values to empty string, nullable primitive properties etc.
                var castNullToEmptyString = DbExpressionBuilder.Case(
                    new[] { inputExpression.IsNull() },
                    new[] { DbExpressionBuilder.Constant(string.Empty) },
                    outputExpression);

                return(castNullToEmptyString);
            }
Exemple #4
0
        internal DbExpression AsCqt(DbExpression row)
        {
            DbExpression left = this.m_slotValue.AsCqt(row, this.m_outputMember);

            if (this.m_enforceNotNull)
            {
                left = (DbExpression)left.And((DbExpression)left.IsNull().Not());
            }
            return(left);
        }
Exemple #5
0
        /// <summary>
        /// Generates CQT representation of the slot.
        /// </summary>
        internal DbExpression AsCqt(DbExpression row)
        {
            DbExpression cqt = m_slotValue.AsCqt(row, m_outputMember);

            if (m_enforceNotNull)
            {
                cqt = cqt.And(cqt.IsNull().Not());
            }
            return(cqt);
        }
        // Effects: given a "clause" in the form of a property/value pair, produces an equality expression. If the
        // value is null, creates an IsNull expression
        // Requires: all arguments are set
        private DbExpression GenerateEqualityExpression(DbExpressionBinding target, EdmProperty property, PropagatorResult value)
        {
            Debug.Assert(null != target && null != property && null != value);

            DbExpression propertyExpression = GeneratePropertyExpression(target, property);
            DbExpression valueExpression    = GenerateValueExpression(property, value);

            if (valueExpression.ExpressionKind == DbExpressionKind.Null)
            {
                return(propertyExpression.IsNull());
            }
            return(propertyExpression.Equal(valueExpression));
        }
Exemple #7
0
        private DbExpression GeneratePredicate(StorageConditionPropertyMapping condition, DbExpression row)
        {
            Debug.Assert(condition.EdmProperty == null, "C-side conditions are not supported in function mappings.");
            DbExpression columnRef = GenerateColumnRef(row, condition.ColumnProperty);

            if (condition.IsNull.HasValue)
            {
                return(condition.IsNull.Value ? (DbExpression)columnRef.IsNull() : (DbExpression)columnRef.IsNull().Not());
            }
            else
            {
                return(columnRef.Equal(columnRef.ResultType.Constant(condition.Value)));
            }
        }
Exemple #8
0
        private DbExpression GenerateEqualityExpression(
            DbExpressionBinding target,
            EdmProperty property,
            PropagatorResult value)
        {
            DbExpression propertyExpression = UpdateCompiler.GeneratePropertyExpression(target, property);
            DbExpression valueExpression    = this.GenerateValueExpression(property, value);

            if (valueExpression.ExpressionKind == DbExpressionKind.Null)
            {
                return((DbExpression)propertyExpression.IsNull());
            }
            return((DbExpression)propertyExpression.Equal(valueExpression));
        }
        private DbExpression RewriteRow(DbExpression expression, RowType rowType)
        {
            var lambdaExpression = expression as DbLambdaExpression;
            DbNewInstanceExpression newRow;

            if (lambdaExpression != null)
            {
                // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions
                // created by users, because user-created expressions cannot be used for querying in O-space.
                // If that were to change, pushing span beyond a LambdaExpression could cause variable name
                // collisions between the variable names used in the Lambda and the names generated by the
                // RelationshipNavigationVisitor.
                newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression;
            }
            else
            {
                newRow = expression as DbNewInstanceExpression;
            }

            Dictionary <int, DbExpression> unmodifiedColumns = null;
            Dictionary <int, DbExpression> spannedColumns    = null;

            for (var idx = 0; idx < rowType.Properties.Count; idx++)
            {
                // Retrieve the property that represents the current column
                var columnProp = rowType.Properties[idx];

                // Construct an expression that defines the current column.
                DbExpression columnExpr = null;
                if (newRow != null)
                {
                    // For a row-constructing NewInstance expression, the corresponding argument can simply be used
                    columnExpr = newRow.Arguments[idx];
                }
                else
                {
                    // For all other expressions the property corresponding to the column name must be retrieved
                    // from the row-typed expression
                    columnExpr = expression.Property(columnProp.Name);
                }

                var spannedColumn = Rewrite(columnExpr);
                if (!ReferenceEquals(spannedColumn, columnExpr))
                {
                    // If so, then update the dictionary of column index to span information
                    if (null == spannedColumns)
                    {
                        spannedColumns = new Dictionary <int, DbExpression>();
                    }

                    spannedColumns[idx] = spannedColumn;
                }
                else
                {
                    // Otherwise, update the dictionary of column index to unmodified expression
                    if (null == unmodifiedColumns)
                    {
                        unmodifiedColumns = new Dictionary <int, DbExpression>();
                    }

                    unmodifiedColumns[idx] = columnExpr;
                }
            }

            // A new expression need only be built if at least one column was spanned
            if (null == spannedColumns)
            {
                // No columns were spanned, indicate that the original expression should remain.
                return(expression);
            }
            else
            {
                // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns.
                var columnArguments = new List <DbExpression>(rowType.Properties.Count);
                var properties      = new List <EdmProperty>(rowType.Properties.Count);
                for (var idx = 0; idx < rowType.Properties.Count; idx++)
                {
                    var          columnProp = rowType.Properties[idx];
                    DbExpression columnDef  = null;
                    if (!spannedColumns.TryGetValue(idx, out columnDef))
                    {
                        columnDef = unmodifiedColumns[idx];
                    }
                    columnArguments.Add(columnDef);
                    properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType));
                }

                // Copy over any eLinq initializer metadata (if present, or null if not).
                // Note that this initializer metadata does not strictly match the new row type
                // that includes spanned columns, but will be correct once the object materializer
                // has interpreted the query results to produce the correct value for each column.
                var          rewrittenRow          = new RowType(properties, rowType.InitializerMetadata);
                var          rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow);
                DbExpression rewritten             = rewrittenRowTypeUsage.New(columnArguments);

                // SQLBUDT #554182: If we insert a new projection we should make sure to
                // not interfere with the nullability of the input.
                // In particular, if the input row is null and we construct a new row as a projection over its columns
                // we would get a row consisting of nulls, instead of a null row.
                // Thus, given an input X, we rewrite it as:  if (X is null) then NULL else rewritten.
                if (newRow == null)
                {
                    DbExpression condition      = expression.IsNull();
                    DbExpression nullExpression = rewrittenRowTypeUsage.Null();
                    rewritten = DbExpressionBuilder.Case(
                        new List <DbExpression>(new[] { condition }),
                        new List <DbExpression>(new[] { nullExpression }),
                        rewritten);
                }

                // Add an entry to the spanned row type => original row type map for the new row type.
                AddSpannedRowType(rewrittenRow, expression.ResultType);

                if (lambdaExpression != null &&
                    newRow != null)
                {
                    rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments);
                }

                return(rewritten);
            }
        }
 // Generate an equality expression where the values of the left and right operands are completely unknown 
 private DbExpression ImplementEqualityUnknownArguments(DbExpression left, DbExpression right, EqualsPattern pattern)
 {
     switch (pattern)
     {
         case EqualsPattern.Store: // left EQ right
             return left.Equal(right);
         case EqualsPattern.PositiveNullEqualityNonComposable: // for Joins
             return left.Equal(right).Or(left.IsNull().And(right.IsNull()));
         case EqualsPattern.PositiveNullEqualityComposable:
             {
                 var bothNotNull = left.Equal(right);
                 var bothNull = left.IsNull().And(right.IsNull());
                 if (!_funcletizer.RootContext.ContextOptions.UseCSharpNullComparisonBehavior)
                 {
                     return bothNotNull.Or(bothNull); // same as EqualsPattern.PositiveNullEqualityNonComposable
                 }
                 // add more logic to avoid undefined result for true clr semantics, ensuring composability
                 // (left EQ right AND NOT (left IS NULL OR right IS NULL)) OR (left IS NULL AND right IS NULL)
                 var anyOneIsNull = left.IsNull().Or(right.IsNull());
                 return (bothNotNull.And(anyOneIsNull.Not())).Or(bothNull);
             }
         default:
             Debug.Fail("unexpected pattern");
             return null;
     }
 }
 // Generate an equality expression with one unknown operator and 
 private DbExpression ImplementEqualityConstantAndUnknown(
     DbConstantExpression constant, DbExpression unknown, EqualsPattern pattern)
 {
     switch (pattern)
     {
         case EqualsPattern.Store:
         case EqualsPattern.PositiveNullEqualityNonComposable: // for Joins                    
             return constant.Equal(unknown); // either both are non-null, or one is null and the predicate result is undefined
         case EqualsPattern.PositiveNullEqualityComposable:
             if (!_funcletizer.RootContext.ContextOptions.UseCSharpNullComparisonBehavior)
             {
                 return constant.Equal(unknown); // same as EqualsPattern.PositiveNullEqualityNonComposable
             }
             return constant.Equal(unknown).And(unknown.IsNull().Not());
         // add more logic to avoid undefined result for true clr semantics
         default:
             Debug.Fail("unknown pattern");
             return null;
     }
 }
 // For comparisons, where the left and right side are nullable or not nullable, 
 // here are the (compositionally safe) null equality predicates:
 // -- x NOT NULL, y NULL
 // x = y AND  NOT (y IS NULL)
 // -- x NULL, y NULL
 // (x = y AND  (NOT (x IS NULL OR y IS NULL))) OR (x IS NULL AND y IS NULL)
 // -- x NOT NULL, y NOT NULL
 // x = y
 // -- x NULL, y NOT NULL
 // x = y AND  NOT (x IS NULL)
 private DbExpression ImplementEquality(DbExpression left, DbExpression right, EqualsPattern pattern)
 {
     switch (left.ExpressionKind)
     {
         case DbExpressionKind.Constant:
             switch (right.ExpressionKind)
             {
                 case DbExpressionKind.Constant: // constant EQ constant
                     return left.Equal(right);
                 case DbExpressionKind.Null: // null EQ constant --> false
                     return DbExpressionBuilder.False;
                 default:
                     return ImplementEqualityConstantAndUnknown((DbConstantExpression)left, right, pattern);
             }
         case DbExpressionKind.Null:
             switch (right.ExpressionKind)
             {
                 case DbExpressionKind.Constant: // null EQ constant --> false
                     return DbExpressionBuilder.False;
                 case DbExpressionKind.Null: // null EQ null --> true
                     return DbExpressionBuilder.True;
                 default: // null EQ right --> right IS NULL
                     return right.IsNull();
             }
         default: // unknown
             switch (right.ExpressionKind)
             {
                 case DbExpressionKind.Constant:
                     return ImplementEqualityConstantAndUnknown((DbConstantExpression)right, left, pattern);
                 case DbExpressionKind.Null: //  left EQ null --> left IS NULL
                     return left.IsNull();
                 default:
                     return ImplementEqualityUnknownArguments(left, right, pattern);
             }
     }
 }
 // <summary>
 // Creates an implementation of IsNull. Throws exception when operand type is not supported.
 // </summary>
 private static DbExpression CreateIsNullExpression(DbExpression operand, Type operandClrType)
 {
     VerifyTypeSupportedForComparison(operandClrType, operand.ResultType, null);
     return operand.IsNull();
 }
            internal static CqtExpression StripNull(LinqExpression sourceExpression, 
                DbExpression inputExpression, DbExpression outputExpression)
            {
                if (sourceExpression.IsNullConstant())
                {
                    return DbExpressionBuilder.Constant(string.Empty);
                }

                if (sourceExpression.NodeType == ExpressionType.Constant)
                {
                    return outputExpression;
                }

                // converts evaluated null values to empty string, nullable primitive properties etc.
                var castNullToEmptyString = DbExpressionBuilder.Case(
                    new[] { inputExpression.IsNull() },
                    new[] { DbExpressionBuilder.Constant(string.Empty) },
                    outputExpression);
                return castNullToEmptyString;
            }
        private DbExpression RewriteRow(DbExpression expression, RowType rowType)
        {
            DbLambdaExpression             lambdaExpression   = expression as DbLambdaExpression;
            DbNewInstanceExpression        instanceExpression = lambdaExpression == null ? expression as DbNewInstanceExpression : lambdaExpression.Lambda.Body as DbNewInstanceExpression;
            Dictionary <int, DbExpression> dictionary1        = (Dictionary <int, DbExpression>)null;
            Dictionary <int, DbExpression> dictionary2        = (Dictionary <int, DbExpression>)null;

            for (int index = 0; index < rowType.Properties.Count; ++index)
            {
                EdmProperty  property     = rowType.Properties[index];
                DbExpression expression1  = instanceExpression == null ? (DbExpression)expression.Property(property.Name) : instanceExpression.Arguments[index];
                DbExpression dbExpression = this.Rewrite(expression1);
                if (!object.ReferenceEquals((object)dbExpression, (object)expression1))
                {
                    if (dictionary2 == null)
                    {
                        dictionary2 = new Dictionary <int, DbExpression>();
                    }
                    dictionary2[index] = dbExpression;
                }
                else
                {
                    if (dictionary1 == null)
                    {
                        dictionary1 = new Dictionary <int, DbExpression>();
                    }
                    dictionary1[index] = expression1;
                }
            }
            if (dictionary2 == null)
            {
                return(expression);
            }
            List <DbExpression> dbExpressionList = new List <DbExpression>(rowType.Properties.Count);
            List <EdmProperty>  edmPropertyList  = new List <EdmProperty>(rowType.Properties.Count);

            for (int key = 0; key < rowType.Properties.Count; ++key)
            {
                EdmProperty  property     = rowType.Properties[key];
                DbExpression dbExpression = (DbExpression)null;
                if (!dictionary2.TryGetValue(key, out dbExpression))
                {
                    dbExpression = dictionary1[key];
                }
                dbExpressionList.Add(dbExpression);
                edmPropertyList.Add(new EdmProperty(property.Name, dbExpression.ResultType));
            }
            RowType      spannedType   = new RowType((IEnumerable <EdmProperty>)edmPropertyList, rowType.InitializerMetadata);
            TypeUsage    typeUsage     = TypeUsage.Create((EdmType)spannedType);
            DbExpression dbExpression1 = (DbExpression)typeUsage.New((IEnumerable <DbExpression>)dbExpressionList);

            if (instanceExpression == null)
            {
                dbExpression1 = (DbExpression)DbExpressionBuilder.Case((IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1]
                {
                    (DbExpression)expression.IsNull()
                }), (IEnumerable <DbExpression>) new List <DbExpression>((IEnumerable <DbExpression>) new DbExpression[1]
                {
                    (DbExpression)typeUsage.Null()
                }), dbExpression1);
            }
            this.AddSpannedRowType(spannedType, expression.ResultType);
            if (lambdaExpression != null && instanceExpression != null)
            {
                dbExpression1 = (DbExpression)DbLambda.Create(dbExpression1, (IEnumerable <DbVariableReferenceExpression>)lambdaExpression.Lambda.Variables).Invoke((IEnumerable <DbExpression>)lambdaExpression.Arguments);
            }
            return(dbExpression1);
        }
        private DbExpression RewriteRow(DbExpression expression, RowType rowType)
        {
            var lambdaExpression = expression as DbLambdaExpression;
            DbNewInstanceExpression newRow;

            if (lambdaExpression != null)
            {
                // NOTE: We rely on the fact that today span cannot be done over queries containing DbLambdaExpressions
                // created by users, because user-created expressions cannot be used for querying in O-space.
                // If that were to change, pushing span beyond a LambdaExpression could cause variable name 
                // collisions between the variable names used in the Lambda and the names generated by the
                // RelationshipNavigationVisitor.           
                newRow = lambdaExpression.Lambda.Body as DbNewInstanceExpression;
            }
            else
            {
                newRow = expression as DbNewInstanceExpression;
            }

            Dictionary<int, DbExpression> unmodifiedColumns = null;
            Dictionary<int, DbExpression> spannedColumns = null;
            for (var idx = 0; idx < rowType.Properties.Count; idx++)
            {
                // Retrieve the property that represents the current column
                var columnProp = rowType.Properties[idx];

                // Construct an expression that defines the current column.
                DbExpression columnExpr = null;
                if (newRow != null)
                {
                    // For a row-constructing NewInstance expression, the corresponding argument can simply be used
                    columnExpr = newRow.Arguments[idx];
                }
                else
                {
                    // For all other expressions the property corresponding to the column name must be retrieved
                    // from the row-typed expression
                    columnExpr = expression.Property(columnProp.Name);
                }

                var spannedColumn = Rewrite(columnExpr);
                if (!ReferenceEquals(spannedColumn, columnExpr))
                {
                    // If so, then update the dictionary of column index to span information
                    if (null == spannedColumns)
                    {
                        spannedColumns = new Dictionary<int, DbExpression>();
                    }

                    spannedColumns[idx] = spannedColumn;
                }
                else
                {
                    // Otherwise, update the dictionary of column index to unmodified expression
                    if (null == unmodifiedColumns)
                    {
                        unmodifiedColumns = new Dictionary<int, DbExpression>();
                    }

                    unmodifiedColumns[idx] = columnExpr;
                }
            }

            // A new expression need only be built if at least one column was spanned
            if (null == spannedColumns)
            {
                // No columns were spanned, indicate that the original expression should remain.
                return expression;
            }
            else
            {
                // At least one column was spanned, so build a new row constructor that defines the new row, including spanned columns.
                var columnArguments = new List<DbExpression>(rowType.Properties.Count);
                var properties = new List<EdmProperty>(rowType.Properties.Count);
                for (var idx = 0; idx < rowType.Properties.Count; idx++)
                {
                    var columnProp = rowType.Properties[idx];
                    DbExpression columnDef = null;
                    if (!spannedColumns.TryGetValue(idx, out columnDef))
                    {
                        columnDef = unmodifiedColumns[idx];
                    }
                    columnArguments.Add(columnDef);
                    properties.Add(new EdmProperty(columnProp.Name, columnDef.ResultType));
                }

                // Copy over any eLinq initializer metadata (if present, or null if not).
                // Note that this initializer metadata does not strictly match the new row type
                // that includes spanned columns, but will be correct once the object materializer
                // has interpreted the query results to produce the correct value for each colum.
                var rewrittenRow = new RowType(properties, rowType.InitializerMetadata);
                var rewrittenRowTypeUsage = TypeUsage.Create(rewrittenRow);
                DbExpression rewritten = rewrittenRowTypeUsage.New(columnArguments);

                // SQLBUDT #554182: If we insert a new projection we should should make sure to 
                // not interfere with the nullability of the input. 
                // In particular, if the input row is null and we construct a new row as a projection over its columns
                // we would get a row consisting of nulls, instead of a null row. 
                // Thus, given an input X, we rewritte it as:  if (X is null) then NULL else rewritten.
                if (newRow == null)
                {
                    DbExpression condition = expression.IsNull();
                    DbExpression nullExpression = rewrittenRowTypeUsage.Null();
                    rewritten = DbExpressionBuilder.Case(
                        new List<DbExpression>(new[] { condition }),
                        new List<DbExpression>(new[] { nullExpression }),
                        rewritten);
                }

                // Add an entry to the spanned row type => original row type map for the new row type.
                AddSpannedRowType(rewrittenRow, expression.ResultType);

                if (lambdaExpression != null
                    && newRow != null)
                {
                    rewritten = DbLambda.Create(rewritten, lambdaExpression.Lambda.Variables).Invoke(lambdaExpression.Arguments);
                }

                return rewritten;
            }
        }