private static bool IsSupportedDateTimeNew(SqlNew sox)
		{
			if(sox.ClrType == typeof(DateTime)
				&& sox.Args.Count >= 3
				&& sox.Args[0].ClrType == typeof(int)
				&& sox.Args[1].ClrType == typeof(int)
				&& sox.Args[2].ClrType == typeof(int))
			{
				if(sox.Args.Count == 3)
				{
					return true;
				}
				if(sox.Args.Count >= 6 &&
					sox.Args[3].ClrType == typeof(int) && sox.Args[4].ClrType == typeof(int) && sox.Args[5].ClrType == typeof(int))
				{
					if(sox.Args.Count == 6)
					{
						return true;
					}
					if((sox.Args.Count == 7) && (sox.Args[6].ClrType == typeof(int)))
					{
						return true;
					}
				}
			}
			return false;
		}
		private static bool IsSupportedNew(SqlNew snew)
		{
			if(snew.ClrType == typeof(string))
			{
				return IsSupportedStringNew(snew);
			}
			else if(snew.ClrType == typeof(TimeSpan))
			{
				return IsSupportedTimeSpanNew(snew);
			}
			else if(snew.ClrType == typeof(DateTime))
			{
				return IsSupportedDateTimeNew(snew);
			}
			return false;
		}
		internal override SqlExpression VisitNew(SqlNew sox)
		{
			if(!_isDebugMode)
			{
				throw Error.InvalidFormatNode("New");
			}
			_commandStringBuilder.Append("new ");
			_commandStringBuilder.Append(sox.ClrType.Name);
			_commandStringBuilder.Append("{ ");
			// Visit Args
			for(int i = 0, n = sox.Args.Count; i < n; i++)
			{
				SqlExpression argExpr = sox.Args[i];
				if(i > 0) _commandStringBuilder.Append(", ");
				_commandStringBuilder.Append(sox.ArgMembers[i].Name);
				_commandStringBuilder.Append(" = ");
				this.Visit(argExpr);
			}
			// Visit Members
			for(int i = 0, n = sox.Members.Count; i < n; i++)
			{
				SqlMemberAssign ma = sox.Members[i];
				if(i > 0) _commandStringBuilder.Append(", ");
				string ename = this.InferName(ma.Expression, null);
				if(ename != ma.Member.Name)
				{
					_commandStringBuilder.Append(ma.Member.Name);
					_commandStringBuilder.Append(" = ");
				}
				this.Visit(ma.Expression);
			}
			_commandStringBuilder.Append(" }");
			return sox;
		}
		internal override SqlExpression VisitNew(SqlNew sox)
		{
			SqlExpression[] args = new SqlExpression[sox.Args.Count];
			SqlMemberAssign[] bindings = new SqlMemberAssign[sox.Members.Count];
			for(int i = 0, n = args.Length; i < n; i++)
			{
				args[i] = this.VisitExpression(sox.Args[i]);
			}
			for(int i = 0, n = bindings.Length; i < n; i++)
			{
				bindings[i] = this.VisitMemberAssign(sox.Members[i]);
			}
			return new SqlNew(sox.MetaType, sox.SqlType, sox.Constructor, args, sox.ArgMembers, bindings, sox.SourceExpression);
		}
Beispiel #5
0
		internal override SqlExpression VisitNew(SqlNew sox)
		{
			if(sox.Constructor != null)
			{
				Reflection.ParameterInfo[] pis = sox.Constructor.GetParameters();
				for(int i = 0, n = sox.Args.Count; i < n; i++)
				{
					sox.Args[i] = this.VisitNamedExpression(sox.Args[i], pis[i].Name);
				}
			}
			else
			{
				for(int i = 0, n = sox.Args.Count; i < n; i++)
				{
					sox.Args[i] = this.VisitExpression(sox.Args[i]);
				}
			}
			foreach(SqlMemberAssign ma in sox.Members)
			{
				string n = ma.Member.Name;
				if(this.useMappedNames)
				{
					n = sox.MetaType.GetDataMember(ma.Member).MappedName;
				}
				ma.Expression = this.VisitNamedExpression(ma.Expression, n);
			}
			return sox;
		}
		internal override SqlExpression VisitNew(SqlNew sox)
		{
			// check the args for the PKs
			foreach(MemberInfo column in _identityMembers)
			{
				// assume we're invalid unless we find a matching argument which is
				// a bare column/columnRef to the PK
				bool isMatch = false;

				// find a matching arg
				foreach(SqlExpression expr in sox.Args)
				{
					isMatch = IsColumnMatch(column, expr);

					if(isMatch)
					{
						break;
					}
				}

				if(!isMatch)
				{
					foreach(SqlMemberAssign ma in sox.Members)
					{
						SqlExpression expr = ma.Expression;

						isMatch = IsColumnMatch(column, expr);

						if(isMatch)
						{
							break;
						}
					}
				}

				_isValid &= isMatch;
				if(!_isValid)
				{
					break;
				}
			}

			return sox;
		}
		internal override SqlExpression VisitNew(SqlNew sox) {
			for (int i = 0, n = sox.Args.Count; i < n; i++) {
				if (inGroupBy) {
					// we don't want to fetch expressions for group by,
					// since we want links to remain links so SqlFlattener
					// can deal with them properly
					sox.Args[i] = this.VisitExpression(sox.Args[i]);
				}
				else {
					sox.Args[i] = this.FetchExpression(sox.Args[i]);
				}
			}
			for (int i = 0, n = sox.Members.Count; i < n; i++) {
				SqlMemberAssign ma = sox.Members[i];
				MetaDataMember mm = sox.MetaType.GetDataMember(ma.Member);
				MetaType otherType = mm.DeclaringType.InheritanceRoot;
				if (mm.IsAssociation && ma.Expression != null && ma.Expression.NodeType != SqlNodeType.Link
					&& this.shape != null && this.shape.IsPreloaded(mm.Member) && mm.LoadMethod == null
					&& this.alreadyIncluded != null && !this.alreadyIncluded.Contains(otherType)) {
						// The expression is already fetched, add it to the alreadyIncluded set.
						this.alreadyIncluded.Add(otherType);
						ma.Expression = this.VisitExpression(ma.Expression);
						this.alreadyIncluded.Remove(otherType);
					}
				else if (mm.IsAssociation || mm.IsDeferred) {
					ma.Expression = this.VisitExpression(ma.Expression);
				}
				else {
					ma.Expression = this.FetchExpression(ma.Expression);
				}
			}
			return sox;
		}
		private static bool IsSupportedTimeSpanNew(SqlNew sox)
		{
			if(sox.Args.Count == 1)
			{
				return true;
			}
			else if(sox.Args.Count == 3)
			{
				return true;
			}
			else
			{
				if(sox.Args.Count == 4)
				{
					return true;
				}
				else if(sox.Args.Count == 5)
				{
					return true;
				}
			}
			return false;
		}
Beispiel #9
0
 internal virtual SqlExpression VisitNew(SqlNew sox) {
     for (int i = 0, n = sox.Args.Count; i < n; i++) {
         sox.Args[i] = this.VisitExpression(sox.Args[i]);
     }
     for (int i = 0, n = sox.Members.Count; i < n; i++) {
         sox.Members[i].Expression = this.VisitExpression(sox.Members[i].Expression);
     }
     return sox;
 }
			private SqlExpression TranslateNewDateTime(SqlNew sox)
			{
				Expression source = sox.SourceExpression;

				// DateTime(int year, int month, int day) 
				// --> CONVERT(DATETIME, CONVERT(nchar(2),@month) + '/' + CONVERT(nchar(2),@day) + '/' + CONVERT(nchar(4),@year),101)
				if(sox.ClrType == typeof(DateTime) && sox.Args.Count >= 3 &&
					sox.Args[0].ClrType == typeof(int) && sox.Args[1].ClrType == typeof(int) && sox.Args[2].ClrType == typeof(int))
				{
					SqlExpression char2 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(2, false, source) }, source);
					SqlExpression char4 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(4, false, source) }, source);
					SqlExpression year = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char4, sox.Args[0] }, source);
					SqlExpression month = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[1] }, source);
					SqlExpression day = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[2] }, source);
					SqlExpression datetime = new SqlVariable(typeof(void), null, "DATETIME", source);
					if(sox.Args.Count == 3)
					{
						SqlExpression date = sql.Concat(month, sql.ValueFromObject("/", false, source), day, sql.ValueFromObject("/", false, source), year);
						return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[3] { datetime, date, sql.ValueFromObject(101, false, source) }, source);
					}
					if(sox.Args.Count >= 6 &&
						sox.Args[3].ClrType == typeof(int) && sox.Args[4].ClrType == typeof(int) && sox.Args[5].ClrType == typeof(int))
					{
						// DateTime(year, month, day, hour, minute, second ) 
						// --> CONVERT(DATETIME, CONVERT(nchar(2),@month) + '-' + CONVERT(nchar(2),@day) + '-' + CONVERT(nchar(4),@year) +
						//                 ' ' + CONVERT(nchar(2),@hour) + ':' + CONVERT(nchar(2),@minute) + ':' + CONVERT(nchar(2),@second)  ,120)
						SqlExpression hour = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[3] }, source);
						SqlExpression minute = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[4] }, source);
						SqlExpression second = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[5] }, source);
						SqlExpression date = sql.Concat(year, sql.ValueFromObject("-", false, source), month, sql.ValueFromObject("-", false, source), day);
						SqlExpression time = sql.Concat(hour, sql.ValueFromObject(":", false, source), minute, sql.ValueFromObject(":", false, source), second);
						SqlExpression dateAndTime = sql.Concat(date, sql.ValueFromObject(' ', false, source), time);
						if(sox.Args.Count == 6)
						{
							return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[3] { datetime, dateAndTime, sql.ValueFromObject(120, false, source) }, source);
						}
						if((sox.Args.Count == 7) && (sox.Args[6].ClrType == typeof(int)))
						{
							// DateTime(year, month, day, hour, minute, second, millisecond ) 
							// add leading zeros to milliseconds by RIGHT(CONVERT(NCHAR(4),1000+@ms),3) 
							SqlExpression msRaw = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] {char4,
                                       sql.Add(sql.ValueFromObject(1000, false, source),sox.Args[6])}, source);
							SqlExpression ms;
							if(this.providerMode == SqlServerProviderMode.SqlCE)
							{
								//SqlCE doesn't have "RIGHT", so need to use "SUBSTRING"
								SqlExpression len = sql.FunctionCall(typeof(int), "LEN", new SqlExpression[1] { msRaw }, source);
								SqlExpression startIndex = sql.Binary(SqlNodeType.Sub, len, sql.ValueFromObject(2, false, source));
								ms = sql.FunctionCall(typeof(string), "SUBSTRING", new SqlExpression[3] { msRaw, startIndex, sql.ValueFromObject(3, false, source) }, source);
							}
							else
							{
								ms = sql.FunctionCall(typeof(string), "RIGHT", new SqlExpression[2] { msRaw, sql.ValueFromObject(3, false, source) }, source);
							}
							dateAndTime = sql.Concat(dateAndTime, sql.ValueFromObject('.', false, source), ms);
							return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[3] { datetime, dateAndTime, sql.ValueFromObject(121, false, source) }, source);
						}
					}
				}
				throw Error.UnsupportedDateTimeConstructorForm();
			}
			private SqlExpression TranslateNewString(SqlNew sox)
			{
				// string(char c, int i) 
				// --> REPLICATE(@c,@i)
				if(sox.ClrType == typeof(string) && sox.Args.Count == 2
					&& sox.Args[0].ClrType == typeof(char) && sox.Args[1].ClrType == typeof(int))
				{
					return sql.FunctionCall(typeof(string), "REPLICATE", new SqlExpression[] { sox.Args[0], sox.Args[1] }, sox.SourceExpression);
				}
				throw Error.UnsupportedStringConstructorForm();
			}
			// transform constructors if necessary
			internal override SqlExpression VisitNew(SqlNew sox)
			{
				sox = (SqlNew)base.VisitNew(sox);
				if(sox.ClrType == typeof(string))
				{
					return TranslateNewString(sox);
				}
				else if(sox.ClrType == typeof(TimeSpan))
				{
					return TranslateNewTimeSpan(sox);
				}
				else if(sox.ClrType == typeof(DateTime))
				{
					return TranslateNewDateTime(sox);
				}
				else if(sox.ClrType == typeof(DateTimeOffset))
				{
					return TranslateNewDateTimeOffset(sox);
				}
				return sox;
			}
		private static bool IsSupportedStringNew(SqlNew snew)
		{
			return snew.Args.Count == 2 && snew.Args[0].ClrType == typeof(char) && snew.Args[1].ClrType == typeof(int);
		}
		private Type GenerateNew(SqlNew sn)
		{
			LocalBuilder locInstance = gen.DeclareLocal(sn.ClrType);
			LocalBuilder locStoreInMember = null;
			Label labNewExit = gen.DefineLabel();
			Label labAlreadyCached = gen.DefineLabel();

			// read all arg values
			if(sn.Args.Count > 0)
			{
				ParameterInfo[] pis = sn.Constructor.GetParameters();
				for(int i = 0, n = sn.Args.Count; i < n; i++)
				{
					this.GenerateExpressionForType(sn.Args[i], pis[i].ParameterType);
				}
			}

			// construct the new instance
			if(sn.Constructor != null)
			{
				gen.Emit(OpCodes.Newobj, sn.Constructor);
				gen.Emit(OpCodes.Stloc, locInstance);
			}
			else if(sn.ClrType.IsValueType)
			{
				gen.Emit(OpCodes.Ldloca, locInstance);
				gen.Emit(OpCodes.Initobj, sn.ClrType);
			}
			else
			{
				ConstructorInfo ci = sn.ClrType.GetConstructor(System.Type.EmptyTypes);
				gen.Emit(OpCodes.Newobj, ci);
				gen.Emit(OpCodes.Stloc, locInstance);
			}

			// read/write key bindings if there are any
			foreach(SqlMemberAssign ma in sn.Members.OrderBy(m => sn.MetaType.GetDataMember(m.Member).Ordinal))
			{
				MetaDataMember mm = sn.MetaType.GetDataMember(ma.Member);
				if(mm.IsPrimaryKey)
				{
					this.GenerateMemberAssignment(mm, locInstance, ma.Expression, null);
				}
			}

			int iMeta = 0;

			if(sn.MetaType.IsEntity)
			{
				LocalBuilder locCached = gen.DeclareLocal(sn.ClrType);
				locStoreInMember = gen.DeclareLocal(typeof(bool));
				Label labExit = gen.DefineLabel();

				iMeta = this.AddGlobal(typeof(MetaType), sn.MetaType);
				Type orbType = typeof(ObjectMaterializer<>).MakeGenericType(this.compiler.DataReaderType);

				// this.InsertLookup(metaType, locInstance)
				gen.Emit(OpCodes.Ldarg_0);
				this.GenerateConstInt(iMeta);
				gen.Emit(OpCodes.Ldloc, locInstance);
				MethodInfo miInsertLookup = orbType.GetMethod(
															  "InsertLookup",
					BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
					null,
					new Type[] { typeof(int), typeof(object) },
					null
					);

				Diagnostics.Debug.Assert(miInsertLookup != null);
				gen.Emit(GetMethodCallOpCode(miInsertLookup), miInsertLookup);
				gen.Emit(OpCodes.Castclass, sn.ClrType);
				gen.Emit(OpCodes.Stloc, locCached);

				// if cached != instance then already cached
				gen.Emit(OpCodes.Ldloc, locCached);
				gen.Emit(OpCodes.Ldloc, locInstance);
				gen.Emit(OpCodes.Ceq);
				gen.Emit(OpCodes.Brfalse, labAlreadyCached);

				this.GenerateConstInt(1);
				gen.Emit(OpCodes.Stloc, locStoreInMember);
				gen.Emit(OpCodes.Br_S, labExit);

				gen.MarkLabel(labAlreadyCached);
				gen.Emit(OpCodes.Ldloc, locCached);
				gen.Emit(OpCodes.Stloc, locInstance);
				// signal to not store loaded values in instance...
				this.GenerateConstInt(0);
				gen.Emit(OpCodes.Stloc, locStoreInMember);

				gen.MarkLabel(labExit);
			}

			// read/write non-key bindings
			foreach(SqlMemberAssign ma in sn.Members.OrderBy(m => sn.MetaType.GetDataMember(m.Member).Ordinal))
			{
				MetaDataMember mm = sn.MetaType.GetDataMember(ma.Member);
				if(!mm.IsPrimaryKey)
				{
					this.GenerateMemberAssignment(mm, locInstance, ma.Expression, locStoreInMember);
				}
			}

			if(sn.MetaType.IsEntity)
			{
				// don't call SendEntityMaterialized if we already had the instance cached
				gen.Emit(OpCodes.Ldloc, locStoreInMember);
				this.GenerateConstInt(0);
				gen.Emit(OpCodes.Ceq);
				gen.Emit(OpCodes.Brtrue, labNewExit);

				// send entity materialized event
				gen.Emit(OpCodes.Ldarg_0);
				this.GenerateConstInt(iMeta);
				gen.Emit(OpCodes.Ldloc, locInstance);
				Type orbType = typeof(ObjectMaterializer<>).MakeGenericType(this.compiler.DataReaderType);
				MethodInfo miRaiseEvent = orbType.GetMethod(
														    "SendEntityMaterialized",
					BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
					null,
					new Type[] { typeof(int), typeof(object) },
					null
					);
				Diagnostics.Debug.Assert(miRaiseEvent != null);
				gen.Emit(GetMethodCallOpCode(miRaiseEvent), miRaiseEvent);
			}

			gen.MarkLabel(labNewExit);
			gen.Emit(OpCodes.Ldloc, locInstance);

			return sn.ClrType;
		}
			private SqlExpression TranslateNewDateTimeOffset(SqlNew sox)
			{
				Expression source = sox.SourceExpression;
				if(sox.ClrType == typeof(DateTimeOffset))
				{
					// DateTimeOffset(DateTime dateTime)
					// --> CONVERT(DATETIMEOFFSET, @dateTime)
					if(sox.Args.Count == 1 && sox.Args[0].ClrType == typeof(DateTime))
					{
						return sql.FunctionCall(typeof(DateTimeOffset), "TODATETIMEOFFSET",
												new SqlExpression[2] { sox.Args[0], sql.ValueFromObject(0, false, source) },
												source);
					}
					// DateTimeOffset(DateTime dateTime, TimeSpan timeSpan)
					// --> DATEADD(DATETIMEOFFSET, @dateTimePart)
					if(sox.Args.Count == 2 && sox.Args[0].ClrType == typeof(DateTime) && sox.Args[1].ClrType == typeof(TimeSpan))
					{
						return sql.FunctionCall(typeof(DateTimeOffset), "TODATETIMEOFFSET",
												new SqlExpression[2] 
                                                { 
                                                    sox.Args[0], 
                                                    sql.ConvertToInt(sql.ConvertToBigint(sql.Divide(sql.ConvertTimeToDouble(sox.Args[1]), TimeSpan.TicksPerMinute)))
                                                },
												source);
					}
					// DateTimeOffset(year, month, day, hour, minute, second, [millisecond,] timeSpan) 
					//
					if(sox.Args.Count >= 7 &&
						sox.Args[0].ClrType == typeof(int) && sox.Args[1].ClrType == typeof(int) && sox.Args[2].ClrType == typeof(int) &&
						sox.Args[3].ClrType == typeof(int) && sox.Args[4].ClrType == typeof(int) && sox.Args[5].ClrType == typeof(int))
					{

						SqlExpression char2 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(2, false, source) }, source);
						SqlExpression char4 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(4, false, source) }, source);
						SqlExpression char5 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(5, false, source) }, source);

						// add leading zeros to year by RIGHT(CONVERT(NCHAR(5),10000+@ms),4) 
						SqlExpression yyRaw = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] {char5,
                                       sql.Add(sql.ValueFromObject(10000, false, source),sox.Args[0])}, source);
						SqlExpression year = sql.FunctionCall(typeof(string), "RIGHT", new SqlExpression[2] { yyRaw, sql.ValueFromObject(4, false, source) }, source);

						SqlExpression month = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[1] }, source);
						SqlExpression day = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[2] }, source);

						SqlExpression hour = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[3] }, source);
						SqlExpression minute = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[4] }, source);
						SqlExpression second = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[5] }, source);
						SqlExpression date = sql.Concat(year, sql.ValueFromObject("-", false, source), month, sql.ValueFromObject("-", false, source), day);
						SqlExpression time = sql.Concat(hour, sql.ValueFromObject(":", false, source), minute, sql.ValueFromObject(":", false, source), second);

						SqlExpression datetimeoffset = new SqlVariable(typeof(void), null, "DATETIMEOFFSET", source);
						SqlExpression result, dateAndTime;
						int timeSpanIndex;

						if(sox.Args.Count == 7 && sox.Args[6].ClrType == typeof(TimeSpan))
						{
							timeSpanIndex = 6;
							dateAndTime = sql.Concat(date, sql.ValueFromObject(' ', false, source), time);
							result = sql.FunctionCall(typeof(DateTimeOffset), "CONVERT", new SqlExpression[3] { datetimeoffset, dateAndTime, sql.ValueFromObject(120, false, source) }, source);
						}
						else if(sox.Args.Count == 8 && sox.Args[6].ClrType == typeof(int) && sox.Args[7].ClrType == typeof(TimeSpan))
						{
							timeSpanIndex = 7;
							// add leading zeros to milliseconds by RIGHT(CONVERT(NCHAR(4),1000+@ms),3) 
							SqlExpression msRaw = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] {char4,
                                       sql.Add(sql.ValueFromObject(1000, false, source),sox.Args[6])}, source);
							SqlExpression ms = sql.FunctionCall(typeof(string), "RIGHT", new SqlExpression[2] { msRaw, sql.ValueFromObject(3, false, source) }, source);
							dateAndTime = sql.Concat(date, sql.ValueFromObject(' ', false, source), time, sql.ValueFromObject('.', false, source), ms);
							result = sql.FunctionCall(typeof(DateTimeOffset), "CONVERT", new SqlExpression[3] { datetimeoffset, dateAndTime, sql.ValueFromObject(121, false, source) }, source);
						}
						else
						{
							throw Error.UnsupportedDateTimeOffsetConstructorForm();
						}

						return sql.FunctionCall(typeof(DateTimeOffset), "TODATETIMEOFFSET",
												new SqlExpression[2] 
                                                { 
                                                    result, 
                                                    sql.ConvertToInt(sql.ConvertToBigint(sql.Divide(sql.ConvertTimeToDouble(sox.Args[timeSpanIndex]), TimeSpan.TicksPerMinute)))
                                                },
												source);
					}
				}
				throw Error.UnsupportedDateTimeOffsetConstructorForm();
			}
		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);
			}
		}
Beispiel #17
0
		internal SqlNew New(MetaType type, ConstructorInfo cons, IEnumerable<SqlExpression> args, IEnumerable<MemberInfo> argMembers, IEnumerable<SqlMemberAssign> bindings, Expression sourceExpression)
		{
			SqlNew tb = new SqlNew(type, typeProvider.From(type.Type), cons, args, argMembers, bindings, sourceExpression);
			return tb;
		}
		internal override SqlExpression VisitNew(SqlNew sox)
		{
			this.isNew = true;
			return base.VisitNew(sox);
		}
			private SqlExpression TranslateNewTimeSpan(SqlNew sox)
			{
				if(sox.Args.Count == 1)
				{
					return sql.ConvertTo(typeof(TimeSpan), sox.Args[0]);
				}
				else if(sox.Args.Count == 3)
				{
					// TimeSpan(hours, minutes, seconds)
					SqlExpression hours = sql.ConvertToBigint(sox.Args[0]);
					SqlExpression minutes = sql.ConvertToBigint(sox.Args[1]);
					SqlExpression seconds = sql.ConvertToBigint(sox.Args[2]);
					SqlExpression TicksFromHours = sql.Multiply(hours, TimeSpan.TicksPerHour);
					SqlExpression TicksFromMinutes = sql.Multiply(minutes, TimeSpan.TicksPerMinute);
					SqlExpression TicksFromSeconds = sql.Multiply(seconds, TimeSpan.TicksPerSecond);
					return sql.ConvertTo(typeof(TimeSpan), sql.Add(TicksFromHours, TicksFromMinutes, TicksFromSeconds));
				}
				else
				{
					SqlExpression days = sql.ConvertToBigint(sox.Args[0]);
					SqlExpression hours = sql.ConvertToBigint(sox.Args[1]);
					SqlExpression minutes = sql.ConvertToBigint(sox.Args[2]);
					SqlExpression seconds = sql.ConvertToBigint(sox.Args[3]);
					SqlExpression TicksFromDays = sql.Multiply(days, TimeSpan.TicksPerDay);
					SqlExpression TicksFromHours = sql.Multiply(hours, TimeSpan.TicksPerHour);
					SqlExpression TicksFromMinutes = sql.Multiply(minutes, TimeSpan.TicksPerMinute);
					SqlExpression TicksFromSeconds = sql.Multiply(seconds, TimeSpan.TicksPerSecond);
					SqlExpression totalTicks = sql.Add(TicksFromDays, TicksFromHours, TicksFromMinutes, TicksFromSeconds);
					if(sox.Args.Count == 4)
					{
						// TimeSpan(days, hours, minutes, seconds)
						return sql.ConvertTo(typeof(TimeSpan), totalTicks);
					}
					else if(sox.Args.Count == 5)
					{
						// TimeSpan(days, hours, minutes, seconds, milliseconds)
						SqlExpression milliseconds = sql.ConvertToBigint(sox.Args[4]);
						SqlExpression ticksFromMs = sql.Multiply(milliseconds, TimeSpan.TicksPerMillisecond);
						return sql.ConvertTo(typeof(TimeSpan), sql.Add(totalTicks, ticksFromMs));
					}
				}
				throw Error.UnsupportedTimeSpanConstructorForm();
			}