1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Linq.Expressions; 6 using System.Data.Linq; 7 8 namespace System.Data.Linq.SqlClient { 9 using System.Data.Linq.Mapping; 10 using System.Data.Linq.Provider; 11 using System.Diagnostics.CodeAnalysis; 12 using System.Diagnostics; 13 14 /// <summary> 15 /// Factory class produces SqlNodes. Smarts about type system mappings should go 16 /// here and not in the individual SqlNodes. 17 /// </summary> 18 internal class SqlFactory { 19 private TypeSystemProvider typeProvider; 20 private MetaModel model; 21 22 internal TypeSystemProvider TypeProvider { 23 get { return typeProvider; } 24 } 25 SqlFactory(TypeSystemProvider typeProvider, MetaModel model)26 internal SqlFactory(TypeSystemProvider typeProvider, MetaModel model) { 27 this.typeProvider = typeProvider; 28 this.model = model; 29 } 30 31 #region Expression Operators 32 ConvertTo(Type clrType, ProviderType sqlType, SqlExpression expr)33 internal SqlExpression ConvertTo(Type clrType, ProviderType sqlType, SqlExpression expr) { 34 return UnaryConvert(clrType, sqlType, expr, expr.SourceExpression); 35 } 36 ConvertTo(Type clrType, SqlExpression expr)37 internal SqlExpression ConvertTo(Type clrType, SqlExpression expr) { 38 // 39 // In SQL Server 2008, the new TIME data type cannot be converted to BIGINT, or FLOAT, 40 // or a bunch of other SQL types. 41 // 42 if (clrType.IsGenericType && clrType.GetGenericTypeDefinition() == typeof(Nullable<>)) 43 clrType = clrType.GetGenericArguments()[0]; 44 45 bool isClrTimeSpanType = clrType == typeof(TimeSpan); 46 47 if (IsSqlTimeType(expr)) 48 { 49 if (isClrTimeSpanType) { 50 // no conversion necessary 51 return expr; 52 } else { 53 expr = ConvertToDateTime(expr); 54 } 55 } 56 57 return UnaryConvert(clrType, typeProvider.From(clrType), expr, expr.SourceExpression); 58 } 59 ConvertToBigint(SqlExpression expr)60 internal SqlExpression ConvertToBigint(SqlExpression expr) { 61 return ConvertTo(typeof(long), expr); 62 } 63 ConvertToInt(SqlExpression expr)64 internal SqlExpression ConvertToInt(SqlExpression expr) { 65 return ConvertTo(typeof(int), expr); 66 } 67 ConvertToDouble(SqlExpression expr)68 internal SqlExpression ConvertToDouble(SqlExpression expr) { 69 return ConvertTo(typeof(double), expr); 70 } 71 72 // If the argument expression has SqlDbType Time, inject a conversion to Double, else return 73 // the expression unchanged. 74 // ConvertTimeToDouble(SqlExpression exp)75 internal SqlExpression ConvertTimeToDouble(SqlExpression exp) { 76 return IsSqlTimeType(exp) ? ConvertToDouble(exp) : exp; 77 } 78 ConvertToBool(SqlExpression expr)79 internal SqlExpression ConvertToBool(SqlExpression expr) { 80 return ConvertTo(typeof(bool), expr); 81 } 82 ConvertToDateTime(SqlExpression expr)83 internal SqlExpression ConvertToDateTime(SqlExpression expr) { 84 return UnaryConvert(typeof(DateTime), typeProvider.From(typeof(DateTime)), expr, expr.SourceExpression); 85 } 86 AndAccumulate(SqlExpression left, SqlExpression right)87 internal SqlExpression AndAccumulate(SqlExpression left, SqlExpression right) { 88 if (left == null) { 89 return right; 90 } 91 else if (right == null) { 92 return left; 93 } 94 else { 95 return Binary(SqlNodeType.And, left, right); 96 } 97 } 98 OrAccumulate(SqlExpression left, SqlExpression right)99 internal SqlExpression OrAccumulate(SqlExpression left, SqlExpression right) { 100 if (left == null) { 101 return right; 102 } 103 else if (right == null) { 104 return left; 105 } 106 else { 107 return Binary(SqlNodeType.Or, left, right); 108 } 109 } 110 Concat(params SqlExpression[] expressions)111 internal SqlExpression Concat(params SqlExpression[] expressions) { 112 SqlExpression result = expressions[expressions.Length - 1]; 113 for (int i = expressions.Length - 2; i >= 0; i--) { 114 result = Binary(SqlNodeType.Concat, expressions[i], result); 115 } 116 return result; 117 } 118 Add(params SqlExpression[] expressions)119 internal SqlExpression Add(params SqlExpression[] expressions) { 120 SqlExpression sum = expressions[expressions.Length - 1]; 121 for (int i = expressions.Length - 2; i >= 0; i--) { 122 sum = Binary(SqlNodeType.Add, expressions[i], sum); 123 } 124 return sum; 125 } 126 Subtract(SqlExpression first, SqlExpression second)127 internal SqlExpression Subtract(SqlExpression first, SqlExpression second) { 128 return Binary(SqlNodeType.Sub, first, second); 129 } 130 Multiply(params SqlExpression[] expressions)131 internal SqlExpression Multiply(params SqlExpression[] expressions) { 132 SqlExpression result = expressions[expressions.Length - 1]; 133 for (int i = expressions.Length - 2; i >= 0; i--) { 134 result = Binary(SqlNodeType.Mul, expressions[i], result); 135 } 136 return result; 137 } 138 Divide(SqlExpression first, SqlExpression second)139 internal SqlExpression Divide(SqlExpression first, SqlExpression second) { 140 return Binary(SqlNodeType.Div, first, second); 141 } 142 Add(SqlExpression expr, int second)143 internal SqlExpression Add(SqlExpression expr, int second) { 144 return Binary(SqlNodeType.Add, expr, ValueFromObject(second, false, expr.SourceExpression)); 145 } 146 Subtract(SqlExpression expr, int second)147 internal SqlExpression Subtract(SqlExpression expr, int second) { 148 return Binary(SqlNodeType.Sub, expr, ValueFromObject(second, false, expr.SourceExpression)); 149 } 150 Multiply(SqlExpression expr, long second)151 internal SqlExpression Multiply(SqlExpression expr, long second) { 152 return Binary(SqlNodeType.Mul, expr, ValueFromObject(second, false, expr.SourceExpression)); 153 } 154 Divide(SqlExpression expr, long second)155 internal SqlExpression Divide(SqlExpression expr, long second) { 156 return Binary(SqlNodeType.Div, expr, ValueFromObject(second, false, expr.SourceExpression)); 157 } 158 Mod(SqlExpression expr, long second)159 internal SqlExpression Mod(SqlExpression expr, long second) { 160 return Binary(SqlNodeType.Mod, expr, ValueFromObject(second, false, expr.SourceExpression)); 161 } 162 163 /// <summary> 164 /// Non-internal string length. This should only be used when translating an explicit call by the 165 /// user to String.Length. 166 /// </summary> LEN(SqlExpression expr)167 internal SqlExpression LEN(SqlExpression expr) { 168 return FunctionCall(typeof(int), "LEN", new SqlExpression[] { expr }, expr.SourceExpression); 169 } 170 171 /// <summary> 172 /// This represents the SQL DATALENGTH function, which is the raw number of bytes in the argument. In the 173 /// case of string types it will count trailing spaces, but doesn't understand unicode. 174 /// </summary> DATALENGTH(SqlExpression expr)175 internal SqlExpression DATALENGTH(SqlExpression expr) { 176 return FunctionCall(typeof(int), "DATALENGTH", new SqlExpression[] { expr }, expr.SourceExpression); 177 } 178 179 /// <summary> 180 /// A unary function that uses DATALENGTH, dividing by two if the string is unicode. This is the internal 181 /// form of String.Length that should always be used. 182 /// </summary> CLRLENGTH(SqlExpression expr)183 internal SqlExpression CLRLENGTH(SqlExpression expr) { 184 return Unary(SqlNodeType.ClrLength, expr); 185 } 186 DATEPART(string partName, SqlExpression expr)187 internal SqlExpression DATEPART(string partName, SqlExpression expr) { 188 return FunctionCall( 189 typeof(int), 190 "DATEPART", 191 new SqlExpression[] { 192 new SqlVariable(typeof(void), null, partName, expr.SourceExpression), 193 expr 194 }, 195 expr.SourceExpression 196 ); 197 } 198 DATEADD(string partName, SqlExpression value, SqlExpression expr)199 internal SqlExpression DATEADD(string partName, SqlExpression value, SqlExpression expr) { 200 return DATEADD(partName, value, expr, expr.SourceExpression, false); 201 } 202 DATEADD(string partName, SqlExpression value, SqlExpression expr, Expression sourceExpression, bool asNullable)203 internal SqlExpression DATEADD(string partName, SqlExpression value, SqlExpression expr, Expression sourceExpression, bool asNullable) { 204 Type returnType = asNullable ? typeof(DateTime?) : typeof(DateTime); 205 206 return FunctionCall( 207 returnType, 208 "DATEADD", 209 new SqlExpression[] { 210 new SqlVariable(typeof(void), null, partName, sourceExpression), 211 value, 212 expr }, 213 sourceExpression 214 ); 215 } 216 DATETIMEOFFSETADD(string partName, SqlExpression value, SqlExpression expr)217 internal SqlExpression DATETIMEOFFSETADD(string partName, SqlExpression value, SqlExpression expr) { 218 return DATETIMEOFFSETADD(partName, value, expr, expr.SourceExpression, false); 219 } 220 DATETIMEOFFSETADD(string partName, SqlExpression value, SqlExpression expr, Expression sourceExpression, bool asNullable)221 internal SqlExpression DATETIMEOFFSETADD(string partName, SqlExpression value, SqlExpression expr, Expression sourceExpression, bool asNullable) { 222 Type returnType = asNullable ? typeof(DateTimeOffset?) : typeof(DateTimeOffset); 223 224 return FunctionCall( 225 returnType, 226 "DATEADD", 227 new SqlExpression[] { 228 new SqlVariable(typeof(void), null, partName, sourceExpression), 229 value, 230 expr }, 231 sourceExpression 232 ); 233 } 234 235 #endregion 236 AddTimeSpan(SqlExpression dateTime, SqlExpression timeSpan)237 internal SqlExpression AddTimeSpan(SqlExpression dateTime, SqlExpression timeSpan) { 238 return AddTimeSpan(dateTime, timeSpan, false); 239 } 240 AddTimeSpan(SqlExpression dateTime, SqlExpression timeSpan, bool asNullable)241 internal SqlExpression AddTimeSpan(SqlExpression dateTime, SqlExpression timeSpan, bool asNullable) { 242 Debug.Assert(IsSqlHighPrecisionDateTimeType(timeSpan)); 243 244 SqlExpression ns = DATEPART("NANOSECOND", timeSpan); 245 SqlExpression ms = DATEPART("MILLISECOND", timeSpan); 246 SqlExpression ss = DATEPART("SECOND", timeSpan); 247 SqlExpression mi = DATEPART("MINUTE", timeSpan); 248 SqlExpression hh = DATEPART("HOUR", timeSpan); 249 250 SqlExpression result = dateTime; 251 if (IsSqlHighPrecisionDateTimeType(dateTime)) { 252 result = DATEADD("NANOSECOND", ns, result, dateTime.SourceExpression, asNullable); 253 } else { 254 result = DATEADD("MILLISECOND", ms, result, dateTime.SourceExpression, asNullable); 255 } 256 result = DATEADD("SECOND", ss, result, dateTime.SourceExpression, asNullable); 257 result = DATEADD("MINUTE", mi, result, dateTime.SourceExpression, asNullable); 258 result = DATEADD("HOUR", hh, result, dateTime.SourceExpression, asNullable); 259 260 if (IsSqlDateTimeOffsetType(dateTime)) 261 return ConvertTo(typeof(DateTimeOffset), result); 262 263 return result; 264 } 265 IsSqlDateTimeType(SqlExpression exp)266 internal static bool IsSqlDateTimeType(SqlExpression exp) { 267 SqlDbType sqlDbType = ((SqlTypeSystem.SqlType)(exp.SqlType)).SqlDbType; 268 return (sqlDbType == SqlDbType.DateTime || sqlDbType == SqlDbType.SmallDateTime); 269 } 270 IsSqlDateType(SqlExpression exp)271 internal static bool IsSqlDateType(SqlExpression exp) { 272 return (((SqlTypeSystem.SqlType)(exp.SqlType)).SqlDbType == SqlDbType.Date); 273 } 274 IsSqlTimeType(SqlExpression exp)275 internal static bool IsSqlTimeType(SqlExpression exp) { 276 return (((SqlTypeSystem.SqlType)(exp.SqlType)).SqlDbType == SqlDbType.Time); 277 } 278 IsSqlDateTimeOffsetType(SqlExpression exp)279 internal static bool IsSqlDateTimeOffsetType(SqlExpression exp) { 280 return (((SqlTypeSystem.SqlType)(exp.SqlType)).SqlDbType == SqlDbType.DateTimeOffset); 281 } 282 IsSqlHighPrecisionDateTimeType(SqlExpression exp)283 internal static bool IsSqlHighPrecisionDateTimeType(SqlExpression exp) { 284 SqlDbType sqlDbType = ((SqlTypeSystem.SqlType)(exp.SqlType)).SqlDbType; 285 return (sqlDbType == SqlDbType.Time || sqlDbType == SqlDbType.DateTime2 || sqlDbType == SqlDbType.DateTimeOffset); 286 } 287 Value(Type clrType, ProviderType sqlType, object value, bool isClientSpecified, Expression sourceExpression)288 internal SqlExpression Value(Type clrType, ProviderType sqlType, object value, bool isClientSpecified, Expression sourceExpression) { 289 if (typeof(Type).IsAssignableFrom(clrType) && value != null) { 290 MetaType typeOf = this.model.GetMetaType((Type)value); 291 return StaticType(typeOf, sourceExpression); 292 } 293 return new SqlValue(clrType, sqlType, value, isClientSpecified, sourceExpression); 294 } 295 296 /// <summary> 297 /// Return a node representing typeof(typeOf) 298 /// </summary> StaticType(MetaType typeOf, Expression sourceExpression)299 internal SqlExpression StaticType(MetaType typeOf, Expression sourceExpression) { 300 if (typeOf==null) 301 throw Error.ArgumentNull("typeOf"); 302 if(typeOf.InheritanceCode==null) { 303 // If no inheritance is involved, then there's no discriminator to 304 // make a discriminated type. In this case, just make a literal type. 305 return new SqlValue(typeof(Type), this.typeProvider.From(typeof(Type)), typeOf.Type, false, sourceExpression); 306 } 307 Type type = typeOf.InheritanceCode.GetType(); 308 SqlValue match = new SqlValue(type, this.typeProvider.From(type), typeOf.InheritanceCode, true, sourceExpression); 309 return this.DiscriminatedType(match, typeOf); 310 } 311 DiscriminatedType(SqlExpression discriminator, MetaType targetType)312 internal SqlExpression DiscriminatedType(SqlExpression discriminator, MetaType targetType) { 313 return new SqlDiscriminatedType(typeProvider.From(typeof(Type)), discriminator, targetType, discriminator.SourceExpression); 314 } 315 Table(MetaTable table, MetaType rowType, Expression sourceExpression)316 internal SqlTable Table(MetaTable table, MetaType rowType, Expression sourceExpression) { 317 return new SqlTable(table, rowType, this.typeProvider.GetApplicationType((int)ConverterSpecialTypes.Row), sourceExpression); 318 } 319 Unary(SqlNodeType nodeType, SqlExpression expression)320 internal SqlUnary Unary(SqlNodeType nodeType, SqlExpression expression) { 321 return Unary(nodeType, expression, expression.SourceExpression); 322 } 323 RowNumber(List<SqlOrderExpression> orderBy, Expression sourceExpression)324 internal SqlRowNumber RowNumber(List<SqlOrderExpression> orderBy, Expression sourceExpression) { 325 return new SqlRowNumber(typeof(long), typeProvider.From(typeof(long)), orderBy, sourceExpression); 326 } 327 Unary(SqlNodeType nodeType, SqlExpression expression, Expression sourceExpression)328 internal SqlUnary Unary(SqlNodeType nodeType, SqlExpression expression, Expression sourceExpression) { 329 return Unary(nodeType, expression, null, sourceExpression); 330 } 331 Unary(SqlNodeType nodeType, SqlExpression expression, MethodInfo method, Expression sourceExpression)332 internal SqlUnary Unary(SqlNodeType nodeType, SqlExpression expression, MethodInfo method, Expression sourceExpression) { 333 Type clrType = null; 334 ProviderType sqlType = null; 335 336 if (nodeType == SqlNodeType.Count) { 337 clrType = typeof(int); 338 sqlType = typeProvider.From(typeof(int)); 339 } 340 else if (nodeType == SqlNodeType.LongCount) { 341 clrType = typeof(long); 342 sqlType = typeProvider.From(typeof(long)); 343 } 344 else if (nodeType == SqlNodeType.ClrLength) { 345 clrType = typeof(int); 346 sqlType = typeProvider.From(typeof(int)); 347 } 348 else { 349 if (nodeType.IsPredicateUnaryOperator()) { 350 // DevDiv 201730 - Do not ignore nullability of bool type 351 clrType = expression.ClrType.Equals(typeof(bool?)) ? typeof(bool?) : typeof(bool); 352 } 353 else { 354 clrType = expression.ClrType; 355 } 356 sqlType = typeProvider.PredictTypeForUnary(nodeType, expression.SqlType); 357 } 358 359 return new SqlUnary(nodeType, clrType, sqlType, expression, method, sourceExpression); 360 } 361 362 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] UnaryConvert(Type targetClrType, ProviderType targetSqlType, SqlExpression expression, Expression sourceExpression)363 internal SqlUnary UnaryConvert(Type targetClrType, ProviderType targetSqlType, SqlExpression expression, Expression sourceExpression) { 364 System.Diagnostics.Debug.Assert(!targetSqlType.IsRuntimeOnlyType, "Attempted coversion to a runtime type: from = " + expression.SqlType.ToQueryString() + "; to = " + targetSqlType.ToQueryString() + "; source = " + sourceExpression.ToString()); 365 return new SqlUnary(SqlNodeType.Convert, targetClrType, targetSqlType, expression, null, sourceExpression); 366 } 367 368 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] UnaryValueOf(SqlExpression expression, Expression sourceExpression)369 internal SqlUnary UnaryValueOf(SqlExpression expression, Expression sourceExpression) { 370 Type valueType = TypeSystem.GetNonNullableType(expression.ClrType); 371 return new SqlUnary(SqlNodeType.ValueOf, valueType, expression.SqlType, expression, null, sourceExpression); 372 } 373 Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right)374 internal SqlBinary Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right) { 375 return Binary(nodeType, left, right, null, null); 376 } 377 Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right, MethodInfo method)378 internal SqlBinary Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right, MethodInfo method) { 379 return Binary(nodeType, left, right, method, null); 380 } 381 Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right, Type clrType)382 internal SqlBinary Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right, Type clrType) { 383 return Binary(nodeType, left, right, null, clrType); 384 } 385 Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right, MethodInfo method, Type clrType)386 internal SqlBinary Binary(SqlNodeType nodeType, SqlExpression left, SqlExpression right, MethodInfo method, Type clrType) { 387 ProviderType sqlType = null; 388 if (nodeType.IsPredicateBinaryOperator()) { 389 if (clrType == null) { 390 clrType = typeof(bool); 391 } 392 sqlType = typeProvider.From(clrType); 393 } 394 else { 395 ProviderType resultType = this.typeProvider.PredictTypeForBinary(nodeType, left.SqlType, right.SqlType); 396 if (resultType == right.SqlType) { 397 if (clrType == null) { 398 clrType = right.ClrType; 399 } 400 sqlType = right.SqlType; 401 } 402 else if (resultType == left.SqlType) { 403 if (clrType == null) { 404 clrType = left.ClrType; 405 } 406 sqlType = left.SqlType; 407 } 408 else { 409 sqlType = resultType; 410 if (clrType == null) { 411 clrType = resultType.GetClosestRuntimeType(); 412 } 413 } 414 } 415 return new SqlBinary(nodeType, clrType, sqlType, left, right, method); 416 } 417 Between(SqlExpression expr, SqlExpression start, SqlExpression end, Expression source)418 internal SqlBetween Between(SqlExpression expr, SqlExpression start, SqlExpression end, Expression source) { 419 return new SqlBetween(typeof(bool), typeProvider.From(typeof(bool)), expr, start, end, source); 420 } 421 In(SqlExpression expr, IEnumerable<SqlExpression> values, Expression source)422 internal SqlIn In(SqlExpression expr, IEnumerable<SqlExpression> values, Expression source) { 423 return new SqlIn(typeof(bool), typeProvider.From(typeof(bool)), expr, values, source); 424 } 425 Like(SqlExpression expr, SqlExpression pattern, SqlExpression escape, Expression source)426 internal SqlLike Like(SqlExpression expr, SqlExpression pattern, SqlExpression escape, Expression source) { 427 SqlLike like = new SqlLike(typeof(bool), typeProvider.From(typeof(bool)), expr, pattern, escape, source); 428 return like; 429 } 430 431 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] SearchedCase(SqlWhen[] whens, SqlExpression @else, Expression sourceExpression)432 internal SqlSearchedCase SearchedCase(SqlWhen[] whens, SqlExpression @else, Expression sourceExpression) { 433 return new SqlSearchedCase(whens[0].Value.ClrType, whens, @else, sourceExpression); 434 } 435 436 /// <summary> 437 /// Construct either a SqlClientCase or a SqlSimpleCase depending on whether the individual cases 438 /// are client-aided or not. 439 /// </summary> 440 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] Case(Type clrType, SqlExpression discriminator, List<SqlExpression> matches, List<SqlExpression> values, Expression sourceExpression)441 internal SqlExpression Case(Type clrType, SqlExpression discriminator, List<SqlExpression> matches, List<SqlExpression> values, Expression sourceExpression) { 442 if (values.Count == 0) { 443 throw Error.EmptyCaseNotSupported(); 444 } 445 bool anyClient = false; 446 foreach (SqlExpression value in values) { 447 anyClient |= value.IsClientAidedExpression(); 448 } 449 if (anyClient) { 450 List<SqlClientWhen> whens = new List<SqlClientWhen>(); 451 for (int i = 0, c = matches.Count; i < c; ++i) { 452 whens.Add(new SqlClientWhen(matches[i], values[i])); 453 } 454 return new SqlClientCase(clrType, discriminator, whens, sourceExpression); 455 } 456 else { 457 List<SqlWhen> whens = new List<SqlWhen>(); 458 for (int i = 0, c = matches.Count; i < c; ++i) { 459 whens.Add(new SqlWhen(matches[i], values[i])); 460 } 461 return new SqlSimpleCase(clrType, discriminator, whens, sourceExpression); 462 } 463 } 464 Parameter(object value, Expression source)465 internal SqlExpression Parameter(object value, Expression source) { 466 System.Diagnostics.Debug.Assert(value != null); 467 Type type = value.GetType(); 468 return Value(type, this.typeProvider.From(value), value, true, source); 469 } 470 ValueFromObject(object value, Expression sourceExpression)471 internal SqlExpression ValueFromObject(object value, Expression sourceExpression) { 472 return ValueFromObject(value, false, sourceExpression); 473 } 474 ValueFromObject(object value, bool isClientSpecified, Expression sourceExpression)475 internal SqlExpression ValueFromObject(object value, bool isClientSpecified, Expression sourceExpression) { 476 if (value == null) { 477 System.Diagnostics.Debug.Assert(false); 478 throw Error.ArgumentNull("value"); 479 } 480 Type clrType = value.GetType(); 481 return ValueFromObject(value, clrType, isClientSpecified, sourceExpression); 482 } 483 484 // Override allowing the CLR type of the value to be specified explicitly. ValueFromObject(object value, Type clrType, bool isClientSpecified, Expression sourceExpression)485 internal SqlExpression ValueFromObject(object value, Type clrType, bool isClientSpecified, Expression sourceExpression) { 486 if (clrType == null) { 487 throw Error.ArgumentNull("clrType"); 488 } 489 ProviderType sqlType = (value == null) ? this.typeProvider.From(clrType) : this.typeProvider.From(value); 490 return Value(clrType, sqlType, value, isClientSpecified, sourceExpression); 491 } 492 TypedLiteralNull(Type type, Expression sourceExpression)493 public SqlExpression TypedLiteralNull(Type type, Expression sourceExpression) { 494 return ValueFromObject(null, type, false, sourceExpression); 495 } 496 Member(SqlExpression expr, MetaDataMember member)497 internal SqlMember Member(SqlExpression expr, MetaDataMember member) { 498 return new SqlMember(member.Type, this.Default(member), expr, member.Member); 499 } 500 Member(SqlExpression expr, MemberInfo member)501 internal SqlMember Member(SqlExpression expr, MemberInfo member) { 502 Type clrType = TypeSystem.GetMemberType(member); 503 MetaType metaType = this.model.GetMetaType(member.DeclaringType); 504 MetaDataMember metaDataMember = metaType.GetDataMember(member); 505 if (metaType != null && metaDataMember != null) { 506 return new SqlMember(clrType, this.Default(metaDataMember), expr, member); 507 } else { 508 return new SqlMember(clrType, this.Default(clrType), expr, member); 509 } 510 } 511 TypeCase(Type clrType, MetaType rowType, SqlExpression discriminator, IEnumerable<SqlTypeCaseWhen> whens, Expression sourceExpression)512 internal SqlExpression TypeCase(Type clrType, MetaType rowType, SqlExpression discriminator, IEnumerable<SqlTypeCaseWhen> whens, Expression sourceExpression) { 513 return new SqlTypeCase(clrType, typeProvider.From(clrType), rowType, discriminator, whens, sourceExpression); 514 } 515 New(MetaType type, ConstructorInfo cons, IEnumerable<SqlExpression> args, IEnumerable<MemberInfo> argMembers, IEnumerable<SqlMemberAssign> bindings, Expression sourceExpression)516 internal SqlNew New(MetaType type, ConstructorInfo cons, IEnumerable<SqlExpression> args, IEnumerable<MemberInfo> argMembers, IEnumerable<SqlMemberAssign> bindings, Expression sourceExpression) { 517 SqlNew tb = new SqlNew(type, typeProvider.From(type.Type), cons, args, argMembers, bindings, sourceExpression); 518 return tb; 519 } 520 MethodCall(MethodInfo method, SqlExpression obj, SqlExpression[] args, Expression sourceExpression)521 internal SqlMethodCall MethodCall(MethodInfo method, SqlExpression obj, SqlExpression[] args, Expression sourceExpression) { 522 return new SqlMethodCall(method.ReturnType, this.Default(method.ReturnType), method, obj, args, sourceExpression); 523 } 524 MethodCall(Type returnType, MethodInfo method, SqlExpression obj, SqlExpression[] args, Expression sourceExpression)525 internal SqlMethodCall MethodCall(Type returnType, MethodInfo method, SqlExpression obj, SqlExpression[] args, Expression sourceExpression) { 526 return new SqlMethodCall(returnType, this.Default(returnType), method, obj, args, sourceExpression); 527 } 528 529 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] ExprSet(SqlExpression[] exprs, Expression sourceExpression)530 internal SqlExprSet ExprSet(SqlExpression[] exprs, Expression sourceExpression) { 531 return new SqlExprSet(exprs[0].ClrType, exprs, sourceExpression); 532 } 533 SubSelect(SqlNodeType nt, SqlSelect select)534 internal SqlSubSelect SubSelect(SqlNodeType nt, SqlSelect select) { 535 return this.SubSelect(nt, select, null); 536 } SubSelect(SqlNodeType nt, SqlSelect select, Type clrType)537 internal SqlSubSelect SubSelect(SqlNodeType nt, SqlSelect select, Type clrType) { 538 ProviderType sqlType = null; 539 switch (nt) { 540 case SqlNodeType.ScalarSubSelect: 541 case SqlNodeType.Element: 542 clrType = select.Selection.ClrType; 543 sqlType = select.Selection.SqlType; 544 break; 545 case SqlNodeType.Multiset: 546 if (clrType == null) { 547 clrType = typeof(List<>).MakeGenericType(select.Selection.ClrType); 548 } 549 sqlType = typeProvider.GetApplicationType((int)ConverterSpecialTypes.Table); 550 break; 551 case SqlNodeType.Exists: 552 clrType = typeof(bool); 553 sqlType = typeProvider.From(typeof(bool)); 554 break; 555 } 556 return new SqlSubSelect(nt, clrType, sqlType, select); 557 } 558 559 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] DoNotVisitExpression(SqlExpression expr)560 internal SqlDoNotVisitExpression DoNotVisitExpression(SqlExpression expr) { 561 return new SqlDoNotVisitExpression(expr); 562 } 563 FunctionCall(Type clrType, string name, IEnumerable<SqlExpression> args, Expression source)564 internal SqlFunctionCall FunctionCall(Type clrType, string name, IEnumerable<SqlExpression> args, Expression source) { 565 return new SqlFunctionCall(clrType, Default(clrType), name, args, source); 566 } 567 568 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] FunctionCall(Type clrType, ProviderType sqlType, string name, IEnumerable<SqlExpression> args, Expression source)569 internal SqlFunctionCall FunctionCall(Type clrType, ProviderType sqlType, string name, IEnumerable<SqlExpression> args, Expression source) { 570 return new SqlFunctionCall(clrType, sqlType, name, args, source); 571 } 572 TableValuedFunctionCall(MetaType rowType, Type clrType, string name, IEnumerable<SqlExpression> args, Expression source)573 internal SqlTableValuedFunctionCall TableValuedFunctionCall(MetaType rowType, Type clrType, string name, IEnumerable<SqlExpression> args, Expression source) { 574 return new SqlTableValuedFunctionCall(rowType, clrType, Default(clrType), name, args, source); 575 } 576 Default(Type clrType)577 internal ProviderType Default(Type clrType) { 578 return typeProvider.From(clrType); 579 } 580 Default(MetaDataMember member)581 internal ProviderType Default(MetaDataMember member) { 582 if(member == null) 583 throw Error.ArgumentNull("member"); 584 585 if (member.DbType != null) { 586 return this.typeProvider.Parse(member.DbType); 587 } 588 else { 589 return this.typeProvider.From(member.Type); 590 } 591 } 592 MakeJoin(SqlJoinType joinType, SqlSource location, SqlAlias alias, SqlExpression condition, Expression source)593 internal SqlJoin MakeJoin(SqlJoinType joinType, SqlSource location, SqlAlias alias, SqlExpression condition, Expression source) { 594 // if the new item is on the right side of some outer join then fixup the projection to reflect that it can possibly be null 595 if (joinType == SqlJoinType.LeftOuter) { 596 SqlSelect sel = alias.Node as SqlSelect; 597 if (sel != null && sel.Selection != null && sel.Selection.NodeType != SqlNodeType.OptionalValue) { 598 // replace selection w/ optional + outer-joined-value 599 sel.Selection = new SqlOptionalValue( 600 new SqlColumn( 601 "test", 602 this.Unary(SqlNodeType.OuterJoinedValue, 603 this.Value(typeof(int?), this.typeProvider.From(typeof(int)), 1, false, source)) 604 ), 605 sel.Selection 606 ); 607 } 608 } 609 return new SqlJoin(joinType, location, alias, condition, source); 610 } 611 } 612 } 613