diff Source/Data/Sql/SqlProvider/FirebirdSqlProvider.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/FirebirdSqlProvider.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,299 @@
+using System;
+using System.Data;
+using System.Text;
+
+#region ReSharper disable
+// ReSharper disable SuggestUseVarKeywordEverywhere
+// ReSharper disable SuggestUseVarKeywordEvident
+#endregion
+
+namespace BLToolkit.Data.Sql.SqlProvider
+{
+	using DataProvider;
+	using Mapping;
+	using Reflection;
+
+	using Linq;
+
+	public class FirebirdSqlProvider : BasicSqlProvider, IMappingSchemaProvider
+	{
+		public FirebirdSqlProvider()
+		{
+		}
+
+//		public override int CommandCount(SqlQuery sqlQuery)
+//		{
+//			return sqlQuery.IsInsert && sqlQuery.Set.WithIdentity ? 2 : 1;
+//		}
+
+//		protected override void BuildCommand(int commandNumber, StringBuilder sb)
+//		{
+//			SequenceNameAttribute attr = GetSequenceNameAttribute(true);
+//
+//			AppendIndent(sb)
+//				.Append("SELECT gen_id(")
+//				.Append(attr.SequenceName)
+//				.AppendLine(", 0) FROM rdb$database");
+//		}
+
+		protected override ISqlProvider CreateSqlProvider()
+		{
+			return new FirebirdSqlProvider();
+		}
+
+		protected override void BuildSelectClause(StringBuilder sb)
+		{
+			if (SqlQuery.From.Tables.Count == 0)
+			{
+				AppendIndent(sb);
+				sb.Append("SELECT").AppendLine();
+				BuildColumns(sb);
+				AppendIndent(sb);
+				sb.Append("FROM rdb$database").AppendLine();
+			}
+			else
+				base.BuildSelectClause(sb);
+		}
+
+		protected override bool   SkipFirst   { get { return false;       } }
+		protected override string SkipFormat  { get { return "SKIP {0}";  } }
+		protected override string FirstFormat { get { return "FIRST {0}"; } }
+
+		public override bool IsIdentityParameterRequired { get { return true; } }
+
+		protected override void BuildGetIdentity(StringBuilder sb)
+		{
+			var identityField = SqlQuery.Insert.Into.GetIdentityField();
+
+			if (identityField == null)
+				throw new SqlException("Identity field must be defined for '{0}'.", SqlQuery.Insert.Into.Name);
+
+			AppendIndent(sb).AppendLine("RETURNING");
+			AppendIndent(sb).Append("\t");
+			BuildExpression(sb, identityField, false, true);
+		}
+
+		public override ISqlExpression GetIdentityExpression(SqlTable table, SqlField identityField, bool forReturning)
+		{
+			if (table.SequenceAttributes != null)
+				return new SqlExpression("GEN_ID(" + table.SequenceAttributes[0].SequenceName + ", 1)", Precedence.Primary);
+
+			return base.GetIdentityExpression(table, identityField, forReturning);
+		}
+
+		public override ISqlExpression ConvertExpression(ISqlExpression expr)
+		{
+			expr = base.ConvertExpression(expr);
+
+			if (expr is SqlBinaryExpression)
+			{
+				SqlBinaryExpression be = (SqlBinaryExpression)expr;
+
+				switch (be.Operation)
+				{
+					case "%": return new SqlFunction(be.SystemType, "Mod",     be.Expr1, be.Expr2);
+					case "&": return new SqlFunction(be.SystemType, "Bin_And", be.Expr1, be.Expr2);
+					case "|": return new SqlFunction(be.SystemType, "Bin_Or",  be.Expr1, be.Expr2);
+					case "^": return new SqlFunction(be.SystemType, "Bin_Xor", 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)
+			{
+				SqlFunction func = (SqlFunction)expr;
+
+				switch (func.Name)
+				{
+					case "Convert" :
+						if (TypeHelper.GetUnderlyingType(func.SystemType) == typeof(bool))
+						{
+							ISqlExpression ex = AlternativeConvertToBoolean(func, 1);
+							if (ex != null)
+								return ex;
+						}
+
+						return new SqlExpression(func.SystemType, "Cast({0} as {1})", Precedence.Primary, FloorBeforeConvert(func), func.Parameters[0]);
+
+					case "DateAdd" :
+						switch ((Sql.DateParts)((SqlValue)func.Parameters[0]).Value)
+						{
+							case Sql.DateParts.Quarter  :
+								return new SqlFunction(func.SystemType, func.Name, new SqlValue(Sql.DateParts.Month), Mul(func.Parameters[1], 3), func.Parameters[2]);
+							case Sql.DateParts.DayOfYear:
+							case Sql.DateParts.WeekDay:
+								return new SqlFunction(func.SystemType, func.Name, new SqlValue(Sql.DateParts.Day),   func.Parameters[1],         func.Parameters[2]);
+							case Sql.DateParts.Week     :
+								return new SqlFunction(func.SystemType, func.Name, new SqlValue(Sql.DateParts.Day),   Mul(func.Parameters[1], 7), func.Parameters[2]);
+						}
+
+						break;
+				}
+			}
+			else if (expr is SqlExpression)
+			{
+				SqlExpression e = (SqlExpression)expr;
+
+				if (e.Expr.StartsWith("Extract(Quarter"))
+					return Inc(Div(Dec(new SqlExpression(e.SystemType, "Extract(Month from {0})", e.Parameters)), 3));
+
+				if (e.Expr.StartsWith("Extract(YearDay"))
+					return Inc(new SqlExpression(e.SystemType, e.Expr.Replace("Extract(YearDay", "Extract(yearDay"), e.Parameters));
+
+				if (e.Expr.StartsWith("Extract(WeekDay"))
+					return Inc(new SqlExpression(e.SystemType, e.Expr.Replace("Extract(WeekDay", "Extract(weekDay"), e.Parameters));
+			}
+
+			return expr;
+		}
+
+		protected override void BuildFunction(StringBuilder sb, SqlFunction func)
+		{
+			func = ConvertFunctionParameters(func);
+			base.BuildFunction(sb, func);
+		}
+
+		protected override void BuildDataType(StringBuilder sb, SqlDataType type)
+		{
+			switch (type.SqlDbType)
+			{
+				case SqlDbType.Decimal       :
+					base.BuildDataType(sb, type.Precision > 18 ? new SqlDataType(type.SqlDbType, type.Type, 18, type.Scale) : type);
+					break;
+				case SqlDbType.TinyInt       : sb.Append("SmallInt");        break;
+				case SqlDbType.Money         : sb.Append("Decimal(18,4)");   break;
+				case SqlDbType.SmallMoney    : sb.Append("Decimal(10,4)");   break;
+#if !MONO
+				case SqlDbType.DateTime2     :
+#endif
+				case SqlDbType.SmallDateTime :
+				case SqlDbType.DateTime      : sb.Append("TimeStamp");       break;
+				case SqlDbType.NVarChar      :
+					sb.Append("VarChar");
+					if (type.Length > 0)
+						sb.Append('(').Append(type.Length).Append(')');
+					break;
+				default                      : base.BuildDataType(sb, type); break;
+			}
+		}
+
+		static void SetNonQueryParameter(IQueryElement element)
+		{
+			if (element.ElementType == QueryElementType.SqlParameter)
+				((SqlParameter)element).IsQueryParameter = false;
+		}
+
+		public override SqlQuery Finalize(SqlQuery sqlQuery)
+		{
+			CheckAliases(sqlQuery, int.MaxValue);
+
+			new QueryVisitor().Visit(sqlQuery.Select, SetNonQueryParameter);
+
+			if (sqlQuery.QueryType == QueryType.InsertOrUpdate)
+			{
+				foreach (var key in sqlQuery.Insert.Items)
+					new QueryVisitor().Visit(key.Expression, SetNonQueryParameter);
+
+				foreach (var key in sqlQuery.Update.Items)
+					new QueryVisitor().Visit(key.Expression, SetNonQueryParameter);
+
+				foreach (var key in sqlQuery.Update.Keys)
+					new QueryVisitor().Visit(key.Expression, SetNonQueryParameter);
+			}
+
+			new QueryVisitor().Visit(sqlQuery, element =>
+			{
+				if (element.ElementType == QueryElementType.InSubQueryPredicate)
+					new QueryVisitor().Visit(((SqlQuery.Predicate.InSubQuery)element).Expr1, SetNonQueryParameter);
+			});
+
+			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);
+		}
+
+		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 = false;
+
+		public override object Convert(object value, ConvertType convertType)
+		{
+			switch (convertType)
+			{
+				case ConvertType.NameToQueryField:
+				case ConvertType.NameToQueryTable:
+					if (QuoteIdentifiers)
+					{
+						string name = value.ToString();
+
+						if (name.Length > 0 && name[0] == '"')
+							return value;
+
+						return '"' + name + '"';
+					}
+
+					break;
+
+				case ConvertType.NameToQueryParameter:
+				case ConvertType.NameToCommandParameter:
+				case ConvertType.NameToSprocParameter:
+					return "@" + value;
+
+				case ConvertType.SprocParameterToName:
+					if (value != null)
+					{
+						string str = value.ToString();
+						return str.Length > 0 && str[0] == '@' ? str.Substring(1) : str;
+					}
+
+					break;
+			}
+
+			return value;
+		}
+
+		protected override void BuildInsertOrUpdateQuery(StringBuilder sb)
+		{
+			BuildInsertOrUpdateQueryAsMerge(sb, "FROM rdb$database");
+		}
+
+		#region IMappingSchemaProvider Members
+
+		readonly FirebirdMappingSchema _mappingSchema = new FirebirdMappingSchema();
+
+		MappingSchema IMappingSchemaProvider.MappingSchema
+		{
+			get { return _mappingSchema; }
+		}
+
+		#endregion
+	}
+}