/// <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)); }
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); }
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); }
/// <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)); }
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))); } }
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; } }