diff Source/Data/Sql/SqlProvider/DB2SqlProvider.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Data/Sql/SqlProvider/DB2SqlProvider.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,321 @@
+using System;
+using System.Text;
+
+using BLToolkit.Reflection;
+
+namespace BLToolkit.Data.Sql.SqlProvider
+{
+	using DataProvider;
+
+	public class DB2SqlProvider : BasicSqlProvider
+	{
+		public override bool TakeAcceptsParameter { get { return SqlQuery.Select.SkipValue != null; } }
+
+		SqlField _identityField;
+
+		public override int CommandCount(SqlQuery sqlQuery)
+		{
+			if (sqlQuery.IsInsert && sqlQuery.Insert.WithIdentity)
+			{
+				_identityField = sqlQuery.Insert.Into.GetIdentityField();
+
+				if (_identityField == null)
+					return 2;
+			}
+
+			return 1;
+		}
+
+		public override int BuildSql(int commandNumber, SqlQuery sqlQuery, StringBuilder sb, int indent, int nesting, bool skipAlias)
+		{
+			if (_identityField != null)
+			{
+				indent += 2;
+
+				AppendIndent(sb).AppendLine("SELECT");
+				AppendIndent(sb).Append("\t");
+				BuildExpression(sb, _identityField, false, true);
+				sb.AppendLine();
+				AppendIndent(sb).AppendLine("FROM");
+				AppendIndent(sb).AppendLine("\tNEW TABLE");
+				AppendIndent(sb).AppendLine("\t(");
+			}
+
+			var ret = base.BuildSql(commandNumber, sqlQuery, sb, indent, nesting, skipAlias);
+
+			if (_identityField != null)
+				sb.AppendLine("\t)");
+
+			return ret;
+		}
+
+		protected override void BuildCommand(int commandNumber, StringBuilder sb)
+		{
+			sb.AppendLine("SELECT identity_val_local() FROM SYSIBM.SYSDUMMY1");
+		}
+
+		protected override ISqlProvider CreateSqlProvider()
+		{
+			return new DB2SqlProvider();
+		}
+
+		protected override void BuildSql(StringBuilder sb)
+		{
+			AlternativeBuildSql(sb, false, base.BuildSql);
+		}
+
+		protected override void BuildSelectClause(StringBuilder sb)
+		{
+			if (SqlQuery.From.Tables.Count == 0)
+			{
+				AppendIndent(sb).AppendLine("SELECT");
+				BuildColumns(sb);
+				AppendIndent(sb).AppendLine("FROM SYSIBM.SYSDUMMY1 FETCH FIRST 1 ROW ONLY");
+			}
+			else
+				base.BuildSelectClause(sb);
+		}
+
+		protected override string LimitFormat
+		{
+			get { return SqlQuery.Select.SkipValue == null ? "FETCH FIRST {0} ROWS ONLY" : null; }
+		}
+
+		public override ISqlExpression ConvertExpression(ISqlExpression expr)
+		{
+			expr = base.ConvertExpression(expr);
+
+			if (expr is SqlBinaryExpression)
+			{
+				var be = (SqlBinaryExpression)expr;
+
+				switch (be.Operation)
+				{
+					case "%":
+						{
+							var expr1 = !TypeHelper.IsIntegerType(be.Expr1.SystemType) ? new SqlFunction(typeof(int), "Int", be.Expr1) : be.Expr1;
+							return new SqlFunction(be.SystemType, "Mod", expr1, be.Expr2);
+						}
+					case "&": return new SqlFunction(be.SystemType, "BitAnd", be.Expr1, be.Expr2);
+					case "|": return new SqlFunction(be.SystemType, "BitOr",  be.Expr1, be.Expr2);
+					case "^": return new SqlFunction(be.SystemType, "BitXor", be.Expr1, be.Expr2);
+					case "+": return be.SystemType == typeof(string)? new SqlBinaryExpression(be.SystemType, be.Expr1, "||", be.Expr2, be.Precedence): expr;
+				}
+			}
+			else if (expr is SqlFunction)
+			{
+				var func = (SqlFunction) expr;
+
+				switch (func.Name)
+				{
+					case "Convert"    :
+						if (TypeHelper.GetUnderlyingType(func.SystemType) == typeof(bool))
+						{
+							var ex = AlternativeConvertToBoolean(func, 1);
+							if (ex != null)
+								return ex;
+						}
+
+						if (func.Parameters[0] is SqlDataType)
+						{
+							var type = (SqlDataType)func.Parameters[0];
+
+							if (type.Type == typeof(string) && func.Parameters[1].SystemType != typeof(string))
+								return new SqlFunction(func.SystemType, "RTrim", new SqlFunction(typeof(string), "Char", func.Parameters[1]));
+
+							if (type.Length > 0)
+								return new SqlFunction(func.SystemType, type.SqlDbType.ToString(), func.Parameters[1], new SqlValue(type.Length));
+
+							if (type.Precision > 0)
+								return new SqlFunction(func.SystemType, type.SqlDbType.ToString(), func.Parameters[1], new SqlValue(type.Precision), new SqlValue(type.Scale));
+
+							return new SqlFunction(func.SystemType, type.SqlDbType.ToString(), func.Parameters[1]);
+						}
+
+						if (func.Parameters[0] is SqlFunction)
+						{
+							var f = (SqlFunction)func.Parameters[0];
+
+							return
+								f.Name == "Char" ?
+									new SqlFunction(func.SystemType, f.Name, func.Parameters[1]) :
+								f.Parameters.Length == 1 ?
+									new SqlFunction(func.SystemType, f.Name, func.Parameters[1], f.Parameters[0]) :
+									new SqlFunction(func.SystemType, f.Name, func.Parameters[1], f.Parameters[0], f.Parameters[1]);
+						}
+
+						{
+							var e = (SqlExpression)func.Parameters[0];
+							return new SqlFunction(func.SystemType, e.Expr, func.Parameters[1]);
+						}
+
+					case "Millisecond"   : return Div(new SqlFunction(func.SystemType, "Microsecond", func.Parameters), 1000);
+					case "SmallDateTime" :
+					case "DateTime"      :
+					case "DateTime2"     : return new SqlFunction(func.SystemType, "TimeStamp", func.Parameters);
+					case "TinyInt"       : return new SqlFunction(func.SystemType, "SmallInt",  func.Parameters);
+					case "Money"         : return new SqlFunction(func.SystemType, "Decimal",   func.Parameters[0], new SqlValue(19), new SqlValue(4));
+					case "SmallMoney"    : return new SqlFunction(func.SystemType, "Decimal",   func.Parameters[0], new SqlValue(10), new SqlValue(4));
+					case "VarChar"       :
+						if (TypeHelper.GetUnderlyingType(func.Parameters[0].SystemType) == typeof(decimal))
+							return new SqlFunction(func.SystemType, "Char", func.Parameters[0]);
+						break;
+					case "NChar"         :
+					case "NVarChar"      : return new SqlFunction(func.SystemType, "Char",      func.Parameters);
+					case "DateDiff"      :
+						{
+							switch ((Linq.Sql.DateParts)((SqlValue)func.Parameters[0]).Value)
+							{
+								case Linq.Sql.DateParts.Day         : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) / 86400",                                               Precedence.Multiplicative, func.Parameters[2], func.Parameters[1]);
+								case Linq.Sql.DateParts.Hour        : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) / 3600",                                                Precedence.Multiplicative, func.Parameters[2], func.Parameters[1]);
+								case Linq.Sql.DateParts.Minute      : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) / 60",                                                  Precedence.Multiplicative, func.Parameters[2], func.Parameters[1]);
+								case Linq.Sql.DateParts.Second      : return new SqlExpression(typeof(int), "(Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))",                                                         Precedence.Additive,       func.Parameters[2], func.Parameters[1]);
+								case Linq.Sql.DateParts.Millisecond : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) * 1000 + (MICROSECOND({0}) - MICROSECOND({1})) / 1000", Precedence.Additive,       func.Parameters[2], func.Parameters[1]);
+							}
+						}
+
+						break;
+				}
+			}
+
+			return expr;
+		}
+
+		protected override void BuildFunction(StringBuilder sb, SqlFunction func)
+		{
+			func = ConvertFunctionParameters(func);
+			base.BuildFunction(sb, func);
+		}
+
+		static void SetQueryParameter(IQueryElement element)
+		{
+			if (element.ElementType == QueryElementType.SqlParameter)
+				((SqlParameter)element).IsQueryParameter = false;
+		}
+
+		public override SqlQuery Finalize(SqlQuery sqlQuery)
+		{
+			new QueryVisitor().Visit(sqlQuery.Select, SetQueryParameter);
+
+			//if (sqlQuery.QueryType == QueryType.InsertOrUpdate)
+			//	foreach (var key in sqlQuery.Insert.Items)
+			//		if (((SqlField)key.Column).IsPrimaryKey)
+			//			new QueryVisitor().Visit(key.Expression, SetQueryParameter);
+
+			sqlQuery = base.Finalize(sqlQuery);
+
+			switch (sqlQuery.QueryType)
+			{
+				case QueryType.Delete : return GetAlternativeDelete(sqlQuery);
+				case QueryType.Update : return GetAlternativeUpdate(sqlQuery);
+				default               : return sqlQuery;
+			}
+		}
+
+		protected override void BuildFromClause(StringBuilder sb)
+		{
+			if (!SqlQuery.IsUpdate)
+				base.BuildFromClause(sb);
+		}
+
+		public override void BuildValue(StringBuilder sb, object value)
+		{
+			if (value is Guid)
+			{
+				var s = ((Guid)value).ToString("N");
+
+				sb
+					.Append("Cast(x'")
+					.Append(s.Substring( 6,  2))
+					.Append(s.Substring( 4,  2))
+					.Append(s.Substring( 2,  2))
+					.Append(s.Substring( 0,  2))
+					.Append(s.Substring(10,  2))
+					.Append(s.Substring( 8,  2))
+					.Append(s.Substring(14,  2))
+					.Append(s.Substring(12,  2))
+					.Append(s.Substring(16, 16))
+					.Append("' as char(16) for bit data)");
+			}
+			else
+				base.BuildValue(sb, value);
+		}
+
+		protected override void BuildColumnExpression(StringBuilder sb, ISqlExpression expr, string alias, ref bool addAlias)
+		{
+			var wrap = false;
+
+			if (expr.SystemType == typeof(bool))
+			{
+				if (expr is SqlQuery.SearchCondition)
+					wrap = true;
+				else
+				{
+					var ex = expr as SqlExpression;
+					wrap = ex != null && ex.Expr == "{0}" && ex.Parameters.Length == 1 && ex.Parameters[0] is SqlQuery.SearchCondition;
+				}
+			}
+
+			if (wrap) sb.Append("CASE WHEN ");
+			base.BuildColumnExpression(sb, expr, alias, ref addAlias);
+			if (wrap) sb.Append(" THEN 1 ELSE 0 END");
+		}
+
+		public static bool QuoteIdentifiers = true;
+
+		public override object Convert(object value, ConvertType convertType)
+		{
+			switch (convertType)
+			{
+				case ConvertType.NameToQueryParameter:
+					return "@" + value;
+
+				case ConvertType.NameToCommandParameter:
+				case ConvertType.NameToSprocParameter:
+					return ":" + value;
+
+				case ConvertType.SprocParameterToName:
+					if (value != null)
+					{
+						var str = value.ToString();
+						return str.Length > 0 && str[0] == ':'? str.Substring(1): str;
+					}
+
+					break;
+
+				case ConvertType.NameToQueryField:
+				case ConvertType.NameToQueryFieldAlias:
+				case ConvertType.NameToQueryTable:
+				case ConvertType.NameToQueryTableAlias:
+					if (QuoteIdentifiers)
+					{
+						var name = value.ToString();
+
+						if (name.Length > 0 && name[0] == '"')
+							return value;
+
+						return '"' + name + '"';
+					}
+
+					break;
+			}
+
+			return value;
+		}
+
+		protected override void BuildInsertOrUpdateQuery(StringBuilder sb)
+		{
+			BuildInsertOrUpdateQueryAsMerge(sb, "FROM SYSIBM.SYSDUMMY1 FETCH FIRST 1 ROW ONLY");
+		}
+
+		protected override void BuildEmptyInsert(StringBuilder sb)
+		{
+			sb.Append("VALUES ");
+
+			foreach (var col in SqlQuery.Insert.Into.Fields)
+				sb.Append("(DEFAULT)");
+
+			sb.AppendLine();
+		}
+	}
+}