PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/referencesource/System.Data.Linq/SqlClient/Common/SqlFactory.cs

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