internal override SqlExpression VisitMethodCall(SqlMethodCall mc)
			{
				if(mc.Arguments.Count == 2 && mc.Method.Name == "op_Equality")
				{
					var r = mc.Arguments[1];
					if(r.NodeType == SqlNodeType.Value)
					{
						var v = (SqlValue)r;
						v.SetSqlType(mc.Arguments[0].SqlType);
					}
				}
				return base.VisitMethodCall(mc);
			}
		private static MethodSupport GetSqlMethodsMethodSupport(SqlMethodCall mc)
		{
			if(mc.Method.IsStatic && mc.Method.DeclaringType == typeof(SqlMethods))
			{
				if(mc.Method.Name.StartsWith("DateDiff", StringComparison.Ordinal) && mc.Arguments.Count == 2)
				{
					foreach(string datePart in dateParts)
					{
						if(mc.Method.Name == "DateDiff" + datePart)
						{
							if(mc.Arguments.Count == 2)
							{
								return MethodSupport.Method;
							}
							else
							{
								return MethodSupport.MethodGroup;
							}
						}
					}
				}
				else if(mc.Method.Name == "Like")
				{
					if(mc.Arguments.Count == 2)
					{
						return MethodSupport.Method;
					}
					else if(mc.Arguments.Count == 3)
					{
						return MethodSupport.Method;
					}
					return MethodSupport.MethodGroup;
				}
				else if(mc.Method.Name == "RawLength")
				{
					return MethodSupport.Method;
				}
			}
			return MethodSupport.None;
		}
Beispiel #3
0
 internal virtual SqlExpression VisitMethodCall(SqlMethodCall mc) {
     mc.Object = this.VisitExpression(mc.Object);
     for (int i = 0, n = mc.Arguments.Count; i < n; i++) {
         mc.Arguments[i] = this.VisitExpression(mc.Arguments[i]);
     }
     return mc;
 }
		private SqlExpression ExpandTogether(List<SqlExpression> exprs)
		{
			switch(exprs[0].NodeType)
			{
				case SqlNodeType.MethodCall:
				{
					SqlMethodCall[] mcs = new SqlMethodCall[exprs.Count];
					for(int i = 0; i < mcs.Length; ++i)
					{
						mcs[i] = (SqlMethodCall)exprs[i];
					}

					List<SqlExpression> expandedArgs = new List<SqlExpression>();

					for(int i = 0; i < mcs[0].Arguments.Count; ++i)
					{
						List<SqlExpression> args = new List<SqlExpression>();
						for(int j = 0; j < mcs.Length; ++j)
						{
							args.Add(mcs[j].Arguments[i]);
						}
						SqlExpression expanded = this.ExpandTogether(args);
						expandedArgs.Add(expanded);
					}
					return factory.MethodCall(mcs[0].Method, mcs[0].Object, expandedArgs.ToArray(), mcs[0].SourceExpression);
				}
				case SqlNodeType.ClientCase:
				{
					// Are they all the same?
					SqlClientCase[] scs = new SqlClientCase[exprs.Count];
					scs[0] = (SqlClientCase)exprs[0];
					for(int i = 1; i < scs.Length; ++i)
					{
						scs[i] = (SqlClientCase)exprs[i];
					}

					// Expand expressions together.
					List<SqlExpression> expressions = new List<SqlExpression>();
					for(int i = 0; i < scs.Length; ++i)
					{
						expressions.Add(scs[i].Expression);
					}
					SqlExpression expression = this.ExpandTogether(expressions);

					// Expand individual expressions together.
					List<SqlClientWhen> whens = new List<SqlClientWhen>();
					for(int i = 0; i < scs[0].Whens.Count; ++i)
					{
						List<SqlExpression> scos = new List<SqlExpression>();
						for(int j = 0; j < scs.Length; ++j)
						{
							SqlClientWhen when = scs[j].Whens[i];
							scos.Add(when.Value);
						}
						whens.Add(new SqlClientWhen(scs[0].Whens[i].Match, this.ExpandTogether(scos)));
					}

					return new SqlClientCase(scs[0].ClrType, expression, whens, scs[0].SourceExpression);
				}
				case SqlNodeType.TypeCase:
				{
					// Are they all the same?
					SqlTypeCase[] tcs = new SqlTypeCase[exprs.Count];
					tcs[0] = (SqlTypeCase)exprs[0];
					for(int i = 1; i < tcs.Length; ++i)
					{
						tcs[i] = (SqlTypeCase)exprs[i];
					}

					// Expand discriminators together.
					List<SqlExpression> discriminators = new List<SqlExpression>();
					for(int i = 0; i < tcs.Length; ++i)
					{
						discriminators.Add(tcs[i].Discriminator);
					}
					SqlExpression discriminator = this.ExpandTogether(discriminators);
					// Write expanded discriminators back in.
					for(int i = 0; i < tcs.Length; ++i)
					{
						tcs[i].Discriminator = discriminators[i];
					}
					// Expand individual type bindings together.
					List<SqlTypeCaseWhen> whens = new List<SqlTypeCaseWhen>();
					for(int i = 0; i < tcs[0].Whens.Count; ++i)
					{
						List<SqlExpression> scos = new List<SqlExpression>();
						for(int j = 0; j < tcs.Length; ++j)
						{
							SqlTypeCaseWhen when = tcs[j].Whens[i];
							scos.Add(when.TypeBinding);
						}
						SqlExpression expanded = this.ExpandTogether(scos);
						whens.Add(new SqlTypeCaseWhen(tcs[0].Whens[i].Match, expanded));
					}

					return factory.TypeCase(tcs[0].ClrType, tcs[0].RowType, discriminator, whens, tcs[0].SourceExpression);
				}
				case SqlNodeType.New:
				{
					// first verify all are similar client objects...
					SqlNew[] cobs = new SqlNew[exprs.Count];
					cobs[0] = (SqlNew)exprs[0];
					for(int i = 1, n = exprs.Count; i < n; i++)
					{
						if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.New)
							throw Error.UnionIncompatibleConstruction();
						cobs[i] = (SqlNew)exprs[1];
						if(cobs[i].Members.Count != cobs[0].Members.Count)
							throw Error.UnionDifferentMembers();
						for(int m = 0, mn = cobs[0].Members.Count; m < mn; m++)
						{
							if(cobs[i].Members[m].Member != cobs[0].Members[m].Member)
							{
								throw Error.UnionDifferentMemberOrder();
							}
						}
					}
					SqlMemberAssign[] bindings = new SqlMemberAssign[cobs[0].Members.Count];
					for(int m = 0, mn = bindings.Length; m < mn; m++)
					{
						List<SqlExpression> mexprs = new List<SqlExpression>();
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							mexprs.Add(cobs[i].Members[m].Expression);
						}
						bindings[m] = new SqlMemberAssign(cobs[0].Members[m].Member, this.ExpandTogether(mexprs));
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							cobs[i].Members[m].Expression = mexprs[i];
						}
					}
					SqlExpression[] arguments = new SqlExpression[cobs[0].Args.Count];
					for(int m = 0, mn = arguments.Length; m < mn; ++m)
					{
						List<SqlExpression> mexprs = new List<SqlExpression>();
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							mexprs.Add(cobs[i].Args[m]);
						}
						arguments[m] = ExpandTogether(mexprs);
					}
					return factory.New(cobs[0].MetaType, cobs[0].Constructor, arguments, cobs[0].ArgMembers, bindings, exprs[0].SourceExpression);
				}
				case SqlNodeType.Link:
				{
					SqlLink[] links = new SqlLink[exprs.Count];
					links[0] = (SqlLink)exprs[0];
					for(int i = 1, n = exprs.Count; i < n; i++)
					{
						if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.Link)
							throw Error.UnionIncompatibleConstruction();
						links[i] = (SqlLink)exprs[i];
						if(links[i].KeyExpressions.Count != links[0].KeyExpressions.Count ||
						   links[i].Member != links[0].Member ||
						   (links[i].Expansion != null) != (links[0].Expansion != null))
							throw Error.UnionIncompatibleConstruction();
					}
					SqlExpression[] kexprs = new SqlExpression[links[0].KeyExpressions.Count];
					List<SqlExpression> lexprs = new List<SqlExpression>();
					for(int k = 0, nk = links[0].KeyExpressions.Count; k < nk; k++)
					{
						lexprs.Clear();
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							lexprs.Add(links[i].KeyExpressions[k]);
						}
						kexprs[k] = this.ExpandTogether(lexprs);
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							links[i].KeyExpressions[k] = lexprs[i];
						}
					}
					SqlExpression expansion = null;
					if(links[0].Expansion != null)
					{
						lexprs.Clear();
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							lexprs.Add(links[i].Expansion);
						}
						expansion = this.ExpandTogether(lexprs);
						for(int i = 0, n = exprs.Count; i < n; i++)
						{
							links[i].Expansion = lexprs[i];
						}
					}
					return new SqlLink(links[0].Id, links[0].RowType, links[0].ClrType, links[0].SqlType, links[0].Expression, links[0].Member, kexprs, expansion, links[0].SourceExpression);
				}
				case SqlNodeType.Value:
				{
					/*
							* ExprSet of all literals of the same value reduce to just a single literal.
							*/
					SqlValue val0 = (SqlValue)exprs[0];
					for(int i = 1; i < exprs.Count; ++i)
					{
						SqlValue val = (SqlValue)exprs[i];
						if(!Equals(val.Value, val0.Value))
							return this.ExpandIntoExprSet(exprs);
					}
					return val0;
				}
				case SqlNodeType.OptionalValue:
				{
					if(exprs[0].SqlType.CanBeColumn)
					{
						goto default;
					}
					List<SqlExpression> hvals = new List<SqlExpression>(exprs.Count);
					List<SqlExpression> vals = new List<SqlExpression>(exprs.Count);
					for(int i = 0, n = exprs.Count; i < n; i++)
					{
						if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.OptionalValue)
						{
							throw Error.UnionIncompatibleConstruction();
						}
						SqlOptionalValue sov = (SqlOptionalValue)exprs[i];
						hvals.Add(sov.HasValue);
						vals.Add(sov.Value);
					}
					return new SqlOptionalValue(this.ExpandTogether(hvals), this.ExpandTogether(vals));
				}
				case SqlNodeType.OuterJoinedValue:
				{
					if(exprs[0].SqlType.CanBeColumn)
					{
						goto default;
					}
					List<SqlExpression> values = new List<SqlExpression>(exprs.Count);
					for(int i = 0, n = exprs.Count; i < n; i++)
					{
						if(exprs[i] == null || exprs[i].NodeType != SqlNodeType.OuterJoinedValue)
						{
							throw Error.UnionIncompatibleConstruction();
						}
						SqlUnary su = (SqlUnary)exprs[i];
						values.Add(su.Operand);
					}
					return factory.Unary(SqlNodeType.OuterJoinedValue, this.ExpandTogether(values));
				}
				case SqlNodeType.DiscriminatedType:
				{
					SqlDiscriminatedType sdt0 = (SqlDiscriminatedType)exprs[0];
					List<SqlExpression> foos = new List<SqlExpression>(exprs.Count);
					foos.Add(sdt0.Discriminator);
					for(int i = 1, n = exprs.Count; i < n; i++)
					{
						SqlDiscriminatedType sdtN = (SqlDiscriminatedType)exprs[i];
						if(sdtN.TargetType != sdt0.TargetType)
						{
							throw Error.UnionIncompatibleConstruction();
						}
						foos.Add(sdtN.Discriminator);
					}
					return factory.DiscriminatedType(this.ExpandTogether(foos), ((SqlDiscriminatedType)exprs[0]).TargetType);
				}
				case SqlNodeType.ClientQuery:
				case SqlNodeType.Multiset:
				case SqlNodeType.Element:
				case SqlNodeType.Grouping:
					throw Error.UnionWithHierarchy();
				default:
					return this.ExpandIntoExprSet(exprs);
			}
		}
		internal override SqlExpression VisitMethodCall(SqlMethodCall mc)
		{
			if(!_isDebugMode)
			{
				throw Error.InvalidFormatNode("MethodCall");
			}
			if(mc.Method.IsStatic)
			{
				_commandStringBuilder.Append(mc.Method.DeclaringType);
			}
			else
			{
				this.Visit(mc.Object);
			}
			_commandStringBuilder.Append(".");
			_commandStringBuilder.Append(mc.Method.Name);
			_commandStringBuilder.Append("(");
			for(int i = 0, n = mc.Arguments.Count; i < n; i++)
			{
				if(i > 0) _commandStringBuilder.Append(", ");
				this.Visit(mc.Arguments[i]);
			}
			_commandStringBuilder.Append(")");
			return mc;
		}
Beispiel #6
0
		internal override SqlExpression VisitMethodCall(SqlMethodCall mc)
		{
			mc.Object = this.VisitExpression(mc.Object);
			Reflection.ParameterInfo[] pis = mc.Method.GetParameters();
			for(int i = 0, n = mc.Arguments.Count; i < n; i++)
			{
				mc.Arguments[i] = this.VisitNamedExpression(mc.Arguments[i], pis[i].Name);
			}
			return mc;
		}
			internal override SqlExpression VisitMethodCall(SqlMethodCall mc)
			{
				mc.Object = this.VisitExpression(mc.Object);
				for(int i = 0, n = mc.Arguments.Count; i < n; i++)
				{
					mc.Arguments[i] = this.VisitExpression(mc.Arguments[i]);
				}
				if(mc.Method.IsStatic)
				{
					if(mc.Method.Name == "Equals" && mc.Arguments.Count == 2)
					{
						return sql.Binary(SqlNodeType.EQ2V, mc.Arguments[0], mc.Arguments[1], mc.Method);
					}
					if(mc.Method.DeclaringType == typeof(string) && mc.Method.Name == "Concat")
					{
						SqlClientArray arr = mc.Arguments[0] as SqlClientArray;
						List<SqlExpression> exprs = null;
						if(arr != null)
						{
							exprs = arr.Expressions;
						}
						else
						{
							exprs = mc.Arguments;
						}
						if(exprs.Count == 0)
						{
							return sql.ValueFromObject("", false, mc.SourceExpression);
						}
						SqlExpression sum;
						if(exprs[0].SqlType.IsString || exprs[0].SqlType.IsChar)
						{
							sum = exprs[0];
						}
						else
						{
							sum = sql.ConvertTo(typeof(string), exprs[0]);
						}
						for(int i = 1; i < exprs.Count; i++)
						{
							if(exprs[i].SqlType.IsString || exprs[i].SqlType.IsChar)
							{
								sum = sql.Concat(sum, exprs[i]);
							}
							else
							{
								sum = sql.Concat(sum, sql.ConvertTo(typeof(string), exprs[i]));
							}
						}
						return sum;
					}
					if(IsVbIIF(mc))
					{
						return TranslateVbIIF(mc);
					}
					switch(mc.Method.Name)
					{
						case "op_Equality":
							return sql.Binary(SqlNodeType.EQ, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_Inequality":
							return sql.Binary(SqlNodeType.NE, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_LessThan":
							return sql.Binary(SqlNodeType.LT, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_LessThanOrEqual":
							return sql.Binary(SqlNodeType.LE, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_GreaterThan":
							return sql.Binary(SqlNodeType.GT, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_GreaterThanOrEqual":
							return sql.Binary(SqlNodeType.GE, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_Multiply":
							return sql.Binary(SqlNodeType.Mul, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_Division":
							return sql.Binary(SqlNodeType.Div, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_Subtraction":
							return sql.Binary(SqlNodeType.Sub, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_Addition":
							return sql.Binary(SqlNodeType.Add, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_Modulus":
							return sql.Binary(SqlNodeType.Mod, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_BitwiseAnd":
							return sql.Binary(SqlNodeType.BitAnd, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_BitwiseOr":
							return sql.Binary(SqlNodeType.BitOr, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_ExclusiveOr":
							return sql.Binary(SqlNodeType.BitXor, mc.Arguments[0], mc.Arguments[1], mc.Method, mc.ClrType);
						case "op_UnaryNegation":
							return sql.Unary(SqlNodeType.Negate, mc.Arguments[0], mc.Method, mc.SourceExpression);
						case "op_OnesComplement":
							return sql.Unary(SqlNodeType.BitNot, mc.Arguments[0], mc.Method, mc.SourceExpression);
						case "op_False":
							return sql.Unary(SqlNodeType.Not, mc.Arguments[0], mc.Method, mc.SourceExpression);
					}
				}
				else
				{
					if(mc.Method.Name == "Equals" && mc.Arguments.Count == 1)
					{
						return sql.Binary(SqlNodeType.EQ, mc.Object, mc.Arguments[0]);
					}
					if(mc.Method.Name == "GetType" && mc.Arguments.Count == 0)
					{
						MetaType mt = TypeSource.GetSourceMetaType(mc.Object, this.model);
						if(mt.HasInheritance)
						{
							Type discriminatorType = mt.Discriminator.Type;
							SqlDiscriminatorOf discriminatorOf = new SqlDiscriminatorOf(mc.Object, discriminatorType, this.sql.TypeProvider.From(discriminatorType), mc.SourceExpression);
							return this.VisitExpression(sql.DiscriminatedType(discriminatorOf, mt));
						}
						return this.VisitExpression(sql.StaticType(mt, mc.SourceExpression));
					}
				}
				return mc;
			}
		private static bool IsVbIIF(SqlMethodCall mc)
		{
			return mc.Method.IsStatic && (mc.Method.DeclaringType!=null) &&
				   mc.Method.DeclaringType.FullName == "Microsoft.VisualBasic.Interaction" && mc.Method.Name == "IIf";
		}
		private static MethodSupport GetDecimalMethodSupport(SqlMethodCall mc)
		{
			if(mc.Method.IsStatic)
			{
				if(mc.Arguments.Count == 2)
				{
					switch(mc.Method.Name)
					{
						case "Multiply":
						case "Divide":
						case "Subtract":
						case "Add":
						case "Remainder":
						case "Round":
							return MethodSupport.Method;
					}
				}
				else if(mc.Arguments.Count == 1)
				{
					switch(mc.Method.Name)
					{
						case "Negate":
						case "Floor":
						case "Truncate":
						case "Round":
							return MethodSupport.Method;
						default:
							if(mc.Method.Name.StartsWith("To", StringComparison.Ordinal))
							{
								return MethodSupport.Method;
							}
							break;
					}
				}
			}
			return MethodSupport.None;
		}
		private static MethodSupport GetConvertMethodSupport(SqlMethodCall mc)
		{
			if(mc.Method.IsStatic && mc.Method.DeclaringType == typeof(Convert) && mc.Arguments.Count == 1)
			{
				switch(mc.Method.Name)
				{
					case "ToBoolean":
					case "ToDecimal":
					case "ToByte":
					case "ToChar":
					case "ToDouble":
					case "ToInt16":
					case "ToInt32":
					case "ToInt64":
					case "ToSingle":
					case "ToString":
						return MethodSupport.Method;
					case "ToDateTime":
						if(mc.Arguments[0].ClrType == typeof(string) || mc.Arguments[0].ClrType == typeof(DateTime))
						{
							return MethodSupport.Method;
						}
						else
						{
							return MethodSupport.MethodGroup;
						}
				}
			}
			return MethodSupport.None;
		}
		private static MethodSupport GetTimeSpanMethodSupport(SqlMethodCall mc)
		{
			if(!mc.Method.IsStatic && mc.Method.DeclaringType == typeof(TimeSpan))
			{
				switch(mc.Method.Name)
				{
					case "Add":
					case "Subtract":
					case "CompareTo":
					case "Duration":
					case "Negate":
						return MethodSupport.Method;
				}
			}
			return MethodSupport.None;
		}
		private static MethodSupport GetDateTimeOffsetMethodSupport(SqlMethodCall mc)
		{
			if(!mc.Method.IsStatic && mc.Method.DeclaringType == typeof(DateTimeOffset))
			{
				switch(mc.Method.Name)
				{
					case "CompareTo":
					case "AddTicks":
					case "AddMonths":
					case "AddYears":
					case "AddMilliseconds":
					case "AddSeconds":
					case "AddMinutes":
					case "AddHours":
					case "AddDays":
						return MethodSupport.Method;
					case "Add":
						if(mc.Arguments.Count == 1 && mc.Arguments[0].ClrType == typeof(TimeSpan))
						{
							return MethodSupport.Method;
						}
						else
						{
							return MethodSupport.MethodGroup;
						}
				}
			}
			return MethodSupport.None;
		}
			private SqlExpression TranslateVbLikeString(SqlMethodCall mc)
			{
				// these should be true per the method signature
				Debug.Assert(mc.Arguments.Count == 3);
				Debug.Assert(mc.Arguments[0].ClrType == typeof(string));
				Debug.Assert(mc.Arguments[1].ClrType == typeof(string));
				bool needsEscape = true;

				Expression source = mc.SourceExpression;
				SqlExpression pattern = mc.Arguments[1];
				if(pattern.NodeType == SqlNodeType.Value)
				{
					string unescapedText = (string)((SqlValue)pattern).Value;
					string patternText = SqlHelpers.TranslateVBLikePattern(unescapedText, '~');
					pattern = sql.ValueFromObject(patternText, typeof(string), true, source);
					needsEscape = unescapedText != patternText;
				}
				else if(pattern.NodeType == SqlNodeType.ClientParameter)
				{
					SqlClientParameter cp = (SqlClientParameter)pattern;
					pattern = new SqlClientParameter(
						cp.ClrType, cp.SqlType,
						Expression.Lambda(
							Expression.Call(typeof(SqlHelpers), "TranslateVBLikePattern", Type.EmptyTypes, cp.Accessor.Body, Expression.Constant('~')),
							cp.Accessor.Parameters[0]
							),
						cp.SourceExpression
						);
				}
				else
				{
					throw Error.NonConstantExpressionsNotSupportedFor("LIKE");
				}
				SqlExpression escape = needsEscape ? sql.ValueFromObject("~", false, mc.SourceExpression) : null;
				return sql.Like(mc.Arguments[0], pattern, escape, source);
			}
			private SqlExpression TranslateVbCompareString(SqlMethodCall mc)
			{
				if(mc.Arguments.Count >= 2)
				{
					return CreateComparison(mc.Arguments[0], mc.Arguments[1], mc.SourceExpression);
				}
				throw GetMethodSupportException(mc);
			}
			private SqlExpression TranslateVbConversionMethod(SqlMethodCall mc)
			{
				Expression source = mc.SourceExpression;
				if(mc.Arguments.Count == 1)
				{
					SqlExpression expr = mc.Arguments[0];
					Type targetType = null;
					switch(mc.Method.Name)
					{
						case "ToBoolean":
							targetType = typeof(bool);
							break;
						case "ToSByte":
							targetType = typeof(sbyte);
							break;
						case "ToByte":
							targetType = typeof(byte);
							break;
						case "ToChar":
							targetType = typeof(char);
							break;
						case "ToCharArrayRankOne":
							targetType = typeof(char[]);
							break;
						case "ToDate":
							targetType = typeof(DateTime);
							break;
						case "ToDecimal":
							targetType = typeof(decimal);
							break;
						case "ToDouble":
							targetType = typeof(double);
							break;
						case "ToInteger":
							targetType = typeof(Int32);
							break;
						case "ToUInteger":
							targetType = typeof(UInt32);
							break;
						case "ToLong":
							targetType = typeof(Int64);
							break;
						case "ToULong":
							targetType = typeof(UInt64);
							break;
						case "ToShort":
							targetType = typeof(Int16);
							break;
						case "ToUShort":
							targetType = typeof(UInt16);
							break;
						case "ToSingle":
							targetType = typeof(float);
							break;
						case "ToString":
							targetType = typeof(string);
							break;
					}
					if(targetType != null)
					{
						if((targetType == typeof(int) || targetType == typeof(Single)) && expr.ClrType == typeof(bool))
						{
							List<SqlExpression> matchesList = new List<SqlExpression>();
							List<SqlExpression> valuesList = new List<SqlExpression>();

							matchesList.Add(sql.ValueFromObject(true, false, source));
							valuesList.Add(sql.ValueFromObject(-1, false, source));
							matchesList.Add(sql.ValueFromObject(false, false, source));
							valuesList.Add(sql.ValueFromObject(0, false, source));

							return sql.Case(targetType, expr, matchesList, valuesList, source);
						}
						else if(mc.ClrType != mc.Arguments[0].ClrType)
						{
							// do the conversions that would be done for a cast "(<targetType>) expression"
							return sql.ConvertTo(targetType, expr);
						}
						else
						{
							return mc.Arguments[0];
						}
					}
				}
				throw GetMethodSupportException(mc);
			}
		private static bool IsVbCompareString(SqlMethodCall call)
		{
			return call.Method.IsStatic && (call.Method.DeclaringType!=null) &&
				call.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" &&
				call.Method.Name == "CompareString";
		}
		private static bool IsSupportedVbHelperMethod(SqlMethodCall mc)
		{
			return IsVbIIF(mc);
		}
		private static MethodSupport GetStringMethodSupport(SqlMethodCall mc)
		{
			if(mc.Method.DeclaringType == typeof(string))
			{
				if(mc.Method.IsStatic)
				{
					if(mc.Method.Name == "Concat")
					{
						return MethodSupport.Method;
					}
				}
				else
				{
					switch(mc.Method.Name)
					{
						case "Contains":
						case "StartsWith":
						case "EndsWith":
							if(mc.Arguments.Count == 1)
							{
								return MethodSupport.Method;
							}
							return MethodSupport.MethodGroup;
						case "IndexOf":
						case "LastIndexOf":
							if(mc.Arguments.Count == 1
								|| mc.Arguments.Count == 2
								|| mc.Arguments.Count == 3)
							{
								return MethodSupport.Method;
							}
							return MethodSupport.MethodGroup;
						case "Insert":
							if(mc.Arguments.Count == 2)
							{
								return MethodSupport.Method;
							}
							return MethodSupport.MethodGroup;
						case "PadLeft":
						case "PadRight":
						case "Remove":
						case "Substring":
							if(mc.Arguments.Count == 1
							   || mc.Arguments.Count == 2)
							{
								return MethodSupport.Method;
							}
							return MethodSupport.MethodGroup;
						case "Replace":
							return MethodSupport.Method;
						case "Trim":
						case "ToLower":
						case "ToUpper":
							if(mc.Arguments.Count == 0)
							{
								return MethodSupport.Method;
							}
							return MethodSupport.MethodGroup;
						case "get_Chars":
						case "CompareTo":
							if(mc.Arguments.Count == 1)
							{
								return MethodSupport.Method;
							}
							return MethodSupport.MethodGroup;
					}
				}
			}
			return MethodSupport.None;
		}
		private static bool IsSupportedMethod(SqlMethodCall mc)
		{
			if(mc.Method.IsStatic)
			{
				switch(mc.Method.Name)
				{
					case "op_Equality":
					case "op_Inequality":
					case "op_LessThan":
					case "op_LessThanOrEqual":
					case "op_GreaterThan":
					case "op_GreaterThanOrEqual":
					case "op_Multiply":
					case "op_Division":
					case "op_Subtraction":
					case "op_Addition":
					case "op_Modulus":
					case "op_BitwiseAnd":
					case "op_BitwiseOr":
					case "op_ExclusiveOr":
					case "op_UnaryNegation":
					case "op_OnesComplement":
					case "op_False":
						return true;
					case "Equals":
						return mc.Arguments.Count == 2;
					case "Concat":
						return mc.Method.DeclaringType == typeof(string);
				}
			}
			else
			{
				return mc.Method.Name == "Equals" && mc.Arguments.Count == 1 ||
					   mc.Method.Name == "GetType" && mc.Arguments.Count == 0;
			}
			return false;
		}
		private static MethodSupport GetMathMethodSupport(SqlMethodCall mc)
		{
			if(mc.Method.IsStatic && mc.Method.DeclaringType == typeof(Math))
			{
				switch(mc.Method.Name)
				{
					case "Abs":
					case "Acos":
					case "Asin":
					case "Atan":
					case "Ceiling":
					case "Cos":
					case "Cosh":
					case "Exp":
					case "Floor":
					case "Log10":
						if(mc.Arguments.Count == 1)
						{
							return MethodSupport.Method;
						}
						return MethodSupport.MethodGroup;
					case "Log":
						if(mc.Arguments.Count == 1 || mc.Arguments.Count == 2)
						{
							return MethodSupport.Method;
						};
						return MethodSupport.MethodGroup;
					case "Max":
					case "Min":
					case "Pow":
					case "Atan2":
					case "BigMul":
						if(mc.Arguments.Count == 2)
						{
							return MethodSupport.Method;
						}
						return MethodSupport.MethodGroup;
					case "Round":
						if(mc.Arguments[mc.Arguments.Count - 1].ClrType == typeof(MidpointRounding)
							&& (mc.Arguments.Count == 2 || mc.Arguments.Count == 3))
						{
							return MethodSupport.Method;
						}
						return MethodSupport.MethodGroup;
					case "Sign":
					case "Sin":
					case "Sinh":
					case "Sqrt":
					case "Tan":
					case "Tanh":
					case "Truncate":
						if(mc.Arguments.Count == 1)
						{
							return MethodSupport.Method;
						}
						return MethodSupport.MethodGroup;
				}
			}
			return MethodSupport.None;
		}
		internal override SqlExpression VisitMethodCall(SqlMethodCall mc) {
			mc.Object = this.FetchExpression(mc.Object);
			for (int i = 0, n = mc.Arguments.Count; i < n; i++) {
				mc.Arguments[i] = this.FetchExpression(mc.Arguments[i]);
			}
			return mc;
		}
		private static MethodSupport GetVbHelperMethodSupport(SqlMethodCall mc)
		{
			if(IsVbConversionMethod(mc) ||
				IsVbCompareString(mc) ||
				IsVbLike(mc))
			{
				return MethodSupport.Method;
			}
			return MethodSupport.None;
		}
		internal override SqlExpression VisitMethodCall(SqlMethodCall mc)
		{
			SqlExpression[] args = new SqlExpression[mc.Arguments.Count];
			for(int i = 0, n = mc.Arguments.Count; i < n; i++)
			{
				args[i] = this.VisitExpression(mc.Arguments[i]);
			}
			return new SqlMethodCall(mc.ClrType, mc.SqlType, mc.Method, this.VisitExpression(mc.Object), args, mc.SourceExpression);
		}
		private static bool IsVbLike(SqlMethodCall mc)
		{
			return mc.Method.IsStatic &&
				   (mc.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.LikeOperator" && mc.Method.Name == "LikeString")
				   || (mc.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" && mc.Method.Name == "LikeString");
		}
		private Type GenerateMethodCall(SqlMethodCall mc)
		{
			ParameterInfo[] pis = mc.Method.GetParameters();
			if(mc.Object != null)
			{
				Type actualType = this.GenerateExpressionForType(mc.Object, mc.Object.ClrType);
				if(actualType.IsValueType)
				{
					LocalBuilder loc = gen.DeclareLocal(actualType);
					gen.Emit(OpCodes.Stloc, loc);
					gen.Emit(OpCodes.Ldloca, loc);
				}
			}
			for(int i = 0, n = mc.Arguments.Count; i < n; i++)
			{
				ParameterInfo pi = pis[i];
				Type pType = pi.ParameterType;
				if(pType.IsByRef)
				{
					pType = pType.GetElementType();
					this.GenerateExpressionForType(mc.Arguments[i], pType);
					LocalBuilder loc = gen.DeclareLocal(pType);
					gen.Emit(OpCodes.Stloc, loc);
					gen.Emit(OpCodes.Ldloca, loc);
				}
				else
				{
					this.GenerateExpressionForType(mc.Arguments[i], pType);
				}
			}
			OpCode callOpCode = GetMethodCallOpCode(mc.Method);
			if(mc.Object != null && TypeSystem.IsNullableType(mc.Object.ClrType) && callOpCode == OpCodes.Callvirt)
			{
				gen.Emit(OpCodes.Constrained, mc.Object.ClrType);
			}
			gen.Emit(callOpCode, mc.Method);

			return mc.Method.ReturnType;
		}
		private static bool IsVbConversionMethod(SqlMethodCall mc)
		{
			if(mc.Method.IsStatic &&
				mc.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Conversions")
			{
				switch(mc.Method.Name)
				{
					case "ToBoolean":
					case "ToSByte":
					case "ToByte":
					case "ToChar":
					case "ToCharArrayRankOne":
					case "ToDate":
					case "ToDecimal":
					case "ToDouble":
					case "ToInteger":
					case "ToUInteger":
					case "ToLong":
					case "ToULong":
					case "ToShort":
					case "ToUShort":
					case "ToSingle":
					case "ToString":
						return true;
				}
			}
			return false;
		}
			private SqlExpression TranslateVbIIF(SqlMethodCall mc)
			{
				//Check to see if the types can be implicitly converted from one to another.
				if(mc.Arguments[1].ClrType == mc.Arguments[2].ClrType)
				{
					List<SqlWhen> whens = new List<SqlWhen>(1);
					whens.Add(new SqlWhen(mc.Arguments[0], mc.Arguments[1]));
					SqlExpression @else = mc.Arguments[2];
					while(@else.NodeType == SqlNodeType.SearchedCase)
					{
						SqlSearchedCase sc = (SqlSearchedCase)@else;
						whens.AddRange(sc.Whens);
						@else = sc.Else;
					}
					return sql.SearchedCase(whens.ToArray(), @else, mc.SourceExpression);
				}
				throw Error.IifReturnTypesMustBeEqual(mc.Arguments[1].ClrType.Name, mc.Arguments[2].ClrType.Name);
			}
		private static bool IsCompareMethod(SqlMethodCall call)
		{
			return call.Method.IsStatic && call.Method.Name == "Compare" && call.Arguments.Count > 1 && call.Method.ReturnType == typeof(int);
		}
		internal override SqlExpression VisitMethodCall(SqlMethodCall mc)
		{
			// eventually we may support this type of stuff given the SQL CLR, but for now it is illegal
			throw Error.MethodHasNoSupportConversionToSql(mc.Method.Name);
		}
		private static MethodSupport GetNullableMethodSupport(SqlMethodCall mc)
		{
			if(mc.Method.Name == "GetValueOrDefault" && TypeSystem.IsNullableType(mc.Object.ClrType))
			{
				return MethodSupport.Method;
			}
			return MethodSupport.None;
		}