using Ant.Core;
using Ant.DbExpressions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Ant.SqlServer
{
///
/// 解析SQL语句帮助类
///
partial class SqlGenerator : DbExpressionVisitor
{
static string GenParameterName(int ordinal)
{
if (ordinal < CacheParameterNames.Count)
{
return CacheParameterNames[ordinal];
}
return ParameterPrefix + ordinal.ToString();
}
static string CreateRowNumberName(List columns)
{
int ROW_NUMBER_INDEX = 1;
string row_numberName = "ROW_NUMBER_0";
while (columns.Any(a => string.Equals(a.Alias, row_numberName, StringComparison.OrdinalIgnoreCase)))
{
row_numberName = "ROW_NUMBER_" + ROW_NUMBER_INDEX.ToString();
ROW_NUMBER_INDEX++;
}
return row_numberName;
}
static DbExpression EnsureDbExpressionReturnCSharpBoolean(DbExpression exp)
{
if (exp.Type != UtilConstants.TypeOfBoolean && exp.Type != UtilConstants.TypeOfBoolean_Nullable)
return exp;
if (SafeDbExpressionTypes.Contains(exp.NodeType))
{
return exp;
}
//将且认为不符合上述条件的都是诸如 a.Id>1,a.Name=="name" 等不能作为 bool 返回值的表达式
//构建 case when
return ConstructReturnCSharpBooleanCaseWhenExpression(exp);
}
public static DbCaseWhenExpression ConstructReturnCSharpBooleanCaseWhenExpression(DbExpression exp)
{
// case when 1>0 then 1 when not (1>0) then 0 else Null end
DbCaseWhenExpression.WhenThenExpressionPair whenThenPair = new DbCaseWhenExpression.WhenThenExpressionPair(exp, DbConstantExpression.True);
DbCaseWhenExpression.WhenThenExpressionPair whenThenPair1 = new DbCaseWhenExpression.WhenThenExpressionPair(DbExpression.Not(exp), DbConstantExpression.False);
List whenThenExps = new List(2);
whenThenExps.Add(whenThenPair);
whenThenExps.Add(whenThenPair1);
DbCaseWhenExpression caseWhenExpression = DbExpression.CaseWhen(whenThenExps, DbConstantExpression.Null, UtilConstants.TypeOfBoolean);
return caseWhenExpression;
}
static Stack GatherBinaryExpressionOperand(DbBinaryExpression exp)
{
DbExpressionType nodeType = exp.NodeType;
Stack items = new Stack();
items.Push(exp.Right);
DbExpression left = exp.Left;
while (left.NodeType == nodeType)
{
exp = (DbBinaryExpression)left;
items.Push(exp.Right);
left = exp.Left;
}
items.Push(left);
return items;
}
static void EnsureMethodDeclaringType(DbMethodCallExpression exp, Type ensureType)
{
if (exp.Method.DeclaringType != ensureType)
throw UtilExceptions.NotSupportedMethod(exp.Method);
}
static void EnsureMethod(DbMethodCallExpression exp, MethodInfo methodInfo)
{
if (exp.Method != methodInfo)
throw UtilExceptions.NotSupportedMethod(exp.Method);
}
static void EnsureTrimCharArgumentIsSpaces(DbExpression exp)
{
var m = exp as DbMemberExpression;
if (m == null)
throw new NotSupportedException();
DbParameterExpression p;
if (!DbExpressionExtensions.TryParseToParameterExpression(m, out p))
{
throw new NotSupportedException();
}
var arg = p.Value;
if (arg == null)
throw new NotSupportedException();
var chars = arg as char[];
if (chars.Length != 1 || chars[0] != ' ')
{
throw new NotSupportedException();
}
}
static bool TryGetCastTargetDbTypeString(Type sourceType, Type targetType, out string dbTypeString, bool throwNotSupportedException = true)
{
dbTypeString = null;
sourceType = Utils.GetUnderlyingType(sourceType);
targetType = Utils.GetUnderlyingType(targetType);
if (sourceType == targetType)
return false;
if (targetType == UtilConstants.TypeOfDecimal)
{
//Casting to Decimal is not supported when missing the precision and scale information.I have no idea to deal with this case now.
if (sourceType != UtilConstants.TypeOfInt16 && sourceType != UtilConstants.TypeOfInt32 && sourceType != UtilConstants.TypeOfInt64 && sourceType != UtilConstants.TypeOfByte)
{
if (throwNotSupportedException)
throw new NotSupportedException(AppendNotSupportedCastErrorMsg(sourceType, targetType));
else
return false;
}
}
if (CastTypeMap.TryGetValue(targetType, out dbTypeString))
{
return true;
}
if (throwNotSupportedException)
throw new NotSupportedException(AppendNotSupportedCastErrorMsg(sourceType, targetType));
else
return false;
}
static string AppendNotSupportedCastErrorMsg(Type sourceType, Type targetType)
{
return string.Format("Does not support the type '{0}' converted to type '{1}'.", sourceType.FullName, targetType.FullName);
}
static void DbFunction_DATEADD(SqlGenerator generator, string interval, DbMethodCallExpression exp)
{
generator._sqlBuilder.Append("DATEADD(");
generator._sqlBuilder.Append(interval);
generator._sqlBuilder.Append(",");
exp.Arguments[0].Accept(generator);
generator._sqlBuilder.Append(",");
exp.Object.Accept(generator);
generator._sqlBuilder.Append(")");
}
static void DbFunction_DATEPART(SqlGenerator generator, string interval, DbExpression exp)
{
generator._sqlBuilder.Append("DATEPART(");
generator._sqlBuilder.Append(interval);
generator._sqlBuilder.Append(",");
exp.Accept(generator);
generator._sqlBuilder.Append(")");
}
static void DbFunction_DATEDIFF(SqlGenerator generator, string interval, DbExpression startDateTimeExp, DbExpression endDateTimeExp)
{
generator._sqlBuilder.Append("DATEDIFF(");
generator._sqlBuilder.Append(interval);
generator._sqlBuilder.Append(",");
startDateTimeExp.Accept(generator);
generator._sqlBuilder.Append(",");
endDateTimeExp.Accept(generator);
generator._sqlBuilder.Append(")");
}
#region AggregateFunction
static void Aggregate_Count(SqlGenerator generator)
{
generator._sqlBuilder.Append("COUNT(1)");
}
static void Aggregate_Equals(DbMethodCallExpression exp, SqlGenerator generator)
{
generator._sqlBuilder.Append("=");
}
static void Aggregate_LongCount(SqlGenerator generator)
{
generator._sqlBuilder.Append("COUNT_BIG(1)");
}
static void Aggregate_Max(SqlGenerator generator, DbExpression exp, Type retType)
{
AppendAggregateFunction(generator, exp, retType, "MAX", false);
}
static void Aggregate_Min(SqlGenerator generator, DbExpression exp, Type retType)
{
AppendAggregateFunction(generator, exp, retType, "MIN", false);
}
static void Aggregate_Sum(SqlGenerator generator, DbExpression exp, Type retType)
{
AppendAggregateFunction(generator, exp, retType, "SUM", true);
}
static void Aggregate_Average(SqlGenerator generator, DbExpression exp, Type retType)
{
AppendAggregateFunction(generator, exp, retType, "AVG", true);
}
///
/// 实现Case When操作
///
///
///
///
///
///
static void AppendAggregateFunction(SqlGenerator generator, DbExpression exp, Type retType, string functionName, bool withCast)
{
string dbTypeString = null;
if (withCast == true)
{
Type unType = Utils.GetUnderlyingType(retType);
if (unType != UtilConstants.TypeOfDecimal/* We don't know the precision and scale,so,we can not cast exp to decimal,otherwise cause problems. */ && CastTypeMap.TryGetValue(unType, out dbTypeString))
{
generator._sqlBuilder.Append("CAST(");
}
}
generator._sqlBuilder.Append(functionName, "(");
exp.Accept(generator);
generator._sqlBuilder.Append(")");
if (dbTypeString != null)
{
generator._sqlBuilder.Append(" AS ", dbTypeString, ")");
}
}
#endregion
}
}