public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Zero": return("0"); case "MinValue": return("-922337203685.477580"); //秒 Ticks / 1000,000,0 case "MaxValue": return("922337203685.477580"); } return(null); } var left = ExpressionLambdaToSql(exp.Expression, tsc); switch (exp.Member.Name) { case "Days": return($"floor(({left})/{60 * 60 * 24})"); case "Hours": return($"mod(({left})/{60 * 60},24)"); case "Milliseconds": return($"(cast({left} as bigint)*1000)"); case "Minutes": return($"mod(({left})/60,60)"); case "Seconds": return($"mod({left},60)"); case "Ticks": return($"(cast({left} as bigint)*10000000)"); case "TotalDays": return($"(({left})/{60 * 60 * 24})"); case "TotalHours": return($"(({left})/{60 * 60})"); case "TotalMilliseconds": return($"(cast({left} as bigint)*1000)"); case "TotalMinutes": return($"(({left})/60)"); case "TotalSeconds": return($"({left})"); } return(null); }
public override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, ExpTSC tsc) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Empty": return("''"); } return(null); } var left = ExpressionLambdaToSql(exp.Expression, tsc); switch (exp.Member.Name) { case "Length": return($"char_length({left})"); } return(null); }
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Now": return(_common.Now); case "UtcNow": return(_common.NowUtc); case "Today": return("current_date"); case "MinValue": return("timestamp '0001/1/1 0:00:00'"); case "MaxValue": return("timestamp'9999/12/31 23:59:59'"); } return(null); } var left = ExpressionLambdaToSql(exp.Expression, tsc); switch (exp.Member.Name) { case "Date": return($"cast(extract(year from {left}) || '-' || extract(month from {left}) || '-' || extract(day from {left}) as timestamp)"); case "TimeOfDay": return($"datediff(second from cast(extract(year from {left}) || '-' || extract(month from {left}) || '-' || extract(day from {left}) as timestamp) to {left})"); case "DayOfWeek": return($"extract(weekday from {left})"); case "Day": return($"extract(day from {left})"); case "DayOfYear": return($"datediff(day from {left} to cast(extract(year from {left}) || '-' || extract(month from {left}) || '-' || extract(day from {left}) as timestamp))"); case "Month": return($"extract(month from {left})"); case "Year": return($"extract(year from {left})"); case "Hour": return($"extract(hour from {left})"); case "Minute": return($"extract(minute from {left})"); case "Second": return($"extract(second from {left})"); case "Millisecond": return($"extract(millisecond from {left})"); case "Ticks": return($"(extract(second from {left})*10000000+621355968000000000)"); } return(null); }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc) { Func <Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc); switch (exp.NodeType) { case ExpressionType.ArrayLength: var arrOper = (exp as UnaryExpression)?.Operand; if (arrOper.Type == typeof(byte[])) { return($"octet_length({getExp(arrOper)})"); } break; case ExpressionType.Convert: var operandExp = (exp as UnaryExpression)?.Operand; var gentype = exp.Type.NullableTypeOrThis(); if (gentype != operandExp.Type.NullableTypeOrThis()) { switch (gentype.ToString()) { case "System.Boolean": return($"({getExp(operandExp)} not in ('0','false'))"); case "System.Byte": return($"cast({getExp(operandExp)} as smallint)"); case "System.Char": return($"substring(cast({getExp(operandExp)} as varchar(10)) from 1 for 1)"); case "System.DateTime": return(ExpressionConstDateTime(operandExp) ?? $"cast({getExp(operandExp)} as timestamp)"); case "System.Decimal": return($"cast({getExp(operandExp)} as decimal(18,6))"); case "System.Double": return($"cast({getExp(operandExp)} as decimal(18,10))"); case "System.Int16": return($"cast({getExp(operandExp)} as smallint)"); case "System.Int32": return($"cast({getExp(operandExp)} as integer)"); case "System.Int64": return($"cast({getExp(operandExp)} as bigint)"); case "System.SByte": return($"cast({getExp(operandExp)} as smallint)"); case "System.Single": return($"cast({getExp(operandExp)} as decimal(14,7))"); case "System.String": return($"cast({getExp(operandExp)} as blob sub_type 1)"); case "System.UInt16": return($"cast({getExp(operandExp)} as integer)"); case "System.UInt32": return($"cast({getExp(operandExp)} as bigint)"); case "System.UInt64": return($"cast({getExp(operandExp)} as decimal(21,0))"); case "System.Guid": return($"substring(cast({getExp(operandExp)} as char(36)) from 1 for 36)"); } } break; case ExpressionType.Call: var callExp = exp as MethodCallExpression; switch (callExp.Method.Name) { case "Parse": case "TryParse": switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString()) { case "System.Boolean": return($"({getExp(callExp.Arguments[0])} not in ('0','false'))"); case "System.Byte": return($"cast({getExp(callExp.Arguments[0])} as smallint)"); case "System.Char": return($"substring(cast({getExp(callExp.Arguments[0])} as varchar(10)) from 1 for 1)"); case "System.DateTime": return(ExpressionConstDateTime(callExp.Arguments[0]) ?? $"cast({getExp(callExp.Arguments[0])} as timestamp)"); case "System.Decimal": return($"cast({getExp(callExp.Arguments[0])} as decimal(18,6))"); case "System.Double": return($"cast({getExp(callExp.Arguments[0])} as decimal(18,10))"); case "System.Int16": return($"cast({getExp(callExp.Arguments[0])} as smallint)"); case "System.Int32": return($"cast({getExp(callExp.Arguments[0])} as integer)"); case "System.Int64": return($"cast({getExp(callExp.Arguments[0])} as bigint)"); case "System.SByte": return($"cast({getExp(callExp.Arguments[0])} as smallint)"); case "System.Single": return($"cast({getExp(callExp.Arguments[0])} as decimal(14,7))"); case "System.String": return($"cast({getExp(callExp.Arguments[0])} as blob sub_type 1)"); case "System.UInt16": return($"cast({getExp(callExp.Arguments[0])} as integer)"); case "System.UInt32": return($"cast({getExp(callExp.Arguments[0])} as bigint)"); case "System.UInt64": return($"cast({getExp(callExp.Arguments[0])} as decimal(18,0))"); case "System.Guid": return($"substring(cast({getExp(callExp.Arguments[0])} as char(36)) from 1 for 36)"); } return(null); case "NewGuid": return(null); case "Next": if (callExp.Object?.Type == typeof(Random)) { return("cast(rand()*1000000000 as integer)"); } return(null); case "NextDouble": if (callExp.Object?.Type == typeof(Random)) { return("rand()"); } return(null); case "Random": if (callExp.Method.DeclaringType.IsNumberType()) { return("rand()"); } return(null); case "ToString": if (callExp.Object != null) { return(callExp.Arguments.Count == 0 ? $"cast({getExp(callExp.Object)} as blob sub_type 1)" : null); } return(null); } var objExp = callExp.Object; var objType = objExp?.Type; if (objType?.FullName == "System.Byte[]") { return(null); } var argIndex = 0; if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable)) { objExp = callExp.Arguments.FirstOrDefault(); objType = objExp?.Type; argIndex++; } if (objType == null) { objType = callExp.Method.DeclaringType; } if (objType != null || objType.IsArrayOrList()) { if (argIndex >= callExp.Arguments.Count) { break; } tsc.SetMapColumnTmp(null); var args1 = getExp(callExp.Arguments[argIndex]); var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp); var oldDbParams = objExp?.NodeType == ExpressionType.MemberAccess ? tsc.SetDbParamsReturnOld(null) : null; //#900 UseGenerateCommandParameterWithLambda(true) 子查询 bug、以及 #1173 参数化 bug tsc.isNotSetMapColumnTmp = true; var left = objExp == null ? null : getExp(objExp); tsc.isNotSetMapColumnTmp = false; tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType); if (oldDbParams != null) { tsc.SetDbParamsReturnOld(oldDbParams); } switch (callExp.Method.Name) { case "Contains": //判断 in //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格 return($"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})"); } } break; case ExpressionType.NewArrayInit: var arrExp = exp as NewArrayExpression; var arrSb = new StringBuilder(); arrSb.Append("("); for (var a = 0; a < arrExp.Expressions.Count; a++) { if (a > 0) { arrSb.Append(","); } if (a % 500 == 499) { arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格 } arrSb.Append(getExp(arrExp.Expressions[a])); } if (arrSb.Length == 1) { arrSb.Append("NULL"); } return(arrSb.Append(")").ToString()); case ExpressionType.ListInit: var listExp = exp as ListInitExpression; var listSb = new StringBuilder(); listSb.Append("("); for (var a = 0; a < listExp.Initializers.Count; a++) { if (listExp.Initializers[a].Arguments.Any() == false) { continue; } if (a > 0) { listSb.Append(","); } listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault())); } if (listSb.Length == 1) { listSb.Append("NULL"); } return(listSb.Append(")").ToString()); case ExpressionType.New: var newExp = exp as NewExpression; if (typeof(IList).IsAssignableFrom(newExp.Type)) { if (newExp.Arguments.Count == 0) { return("(NULL)"); } if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) { return("(NULL)"); } return(getExp(newExp.Arguments[0])); } return(null); } return(null); }
public override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, ExpTSC tsc) { Func <Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc); if (exp.Object == null) { switch (exp.Method.Name) { case "IsNullOrEmpty": var arg1 = getExp(exp.Arguments[0]); return($"({arg1} is null or {arg1} = '')"); case "IsNullOrWhiteSpace": var arg2 = getExp(exp.Arguments[0]); return($"({arg2} is null or {arg2} = '' or ltrim({arg2}) = '')"); case "Concat": return(_common.StringConcat(exp.Arguments.Select(a => getExp(a)).ToArray(), null)); case "Format": if (exp.Arguments[0].NodeType != ExpressionType.Constant) { throw new Exception($"未实现函数表达式 {exp} 解析,参数 {exp.Arguments[0]} 必须为常量"); } var expArgsHack = exp.Arguments.Count == 2 && exp.Arguments[1].NodeType == ExpressionType.NewArrayInit ? (exp.Arguments[1] as NewArrayExpression).Expressions : exp.Arguments.Where((a, z) => z > 0); //3个 {} 时,Arguments 解析出来是分开的 //4个 {} 时,Arguments[1] 只能解析这个出来,然后里面是 NewArray [] var expArgs = expArgsHack.Select(a => $"'||{_common.IsNull(ExpressionLambdaToSql(a, tsc), "''")}||'").ToArray(); return(string.Format(ExpressionLambdaToSql(exp.Arguments[0], tsc), expArgs)); case "Join": if (exp.IsStringJoin(out var tolistObjectExp, out var toListMethod, out var toListArgs1)) { var newToListArgs0 = Expression.Call(tolistObjectExp, toListMethod, Expression.Lambda( Expression.Call( typeof(SqlExtExtensions).GetMethod("StringJoinOracleGroupConcat"), Expression.Convert(toListArgs1.Body, typeof(object)), Expression.Convert(exp.Arguments[0], typeof(object))), toListArgs1.Parameters)); var newToListSql = getExp(newToListArgs0); return(newToListSql); } break; } } else { var left = getExp(exp.Object); switch (exp.Method.Name) { case "StartsWith": case "EndsWith": case "Contains": var args0Value = getExp(exp.Arguments[0]); if (args0Value == "NULL") { return($"({left}) IS NULL"); } if (exp.Method.Name == "StartsWith") { return($"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(to_char({args0Value})||'%')")}"); } if (exp.Method.Name == "EndsWith") { return($"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'||to_char({args0Value}))")}"); } if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) { return($"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"); } return($"({left}) LIKE ('%'||to_char({args0Value})||'%')");
public override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, ExpTSC tsc) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Zero": return("numtodsinterval(0,'second')"); case "MinValue": return("numtodsinterval(-233720368.5477580,'second')"); case "MaxValue": return("numtodsinterval(233720368.5477580,'second')"); } return(null); } var left = ExpressionLambdaToSql(exp.Expression, tsc); switch (exp.Member.Name) { case "Days": return($"extract(day from {left})"); case "Hours": return($"extract(hour from {left})"); case "Milliseconds": return($"cast(substr(extract(second from {left})-floor(extract(second from {left})),3,3) as number)"); case "Minutes": return($"extract(minute from {left})"); case "Seconds": return($"floor(extract(second from {left}))"); case "Ticks": return($"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))*10000000"); case "TotalDays": return($"extract(day from {left})"); case "TotalHours": return($"(extract(day from {left})*24+extract(hour from {left}))"); case "TotalMilliseconds": return($"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))*1000"); case "TotalMinutes": return($"(extract(day from {left})*1440+extract(hour from {left})*60+extract(minute from {left}))"); case "TotalSeconds": return($"(extract(day from {left})*86400+extract(hour from {left})*3600+extract(minute from {left})*60+extract(second from {left}))"); } return(null); }
public override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, ExpTSC tsc) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Now": return(_common.Now); case "UtcNow": return(_common.NowUtc); case "Today": return("trunc(systimestamp)"); case "MinValue": return("to_timestamp('0001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS.FF6')"); case "MaxValue": return("to_timestamp('9999-12-31 23:59:59','YYYY-MM-DD HH24:MI:SS.FF6')"); } return(null); } var left = ExpressionLambdaToSql(exp.Expression, tsc); switch (exp.Member.Name) { case "Date": return($"trunc({left})"); case "TimeOfDay": return($"({left}-trunc({left}))"); case "DayOfWeek": return($"case when to_char({left},'D')='7' then 0 else cast(to_char({left},'D') as number) end"); case "Day": return($"cast(to_char({left},'DD') as number)"); case "DayOfYear": return($"cast(to_char({left},'DDD') as number)"); case "Month": return($"cast(to_char({left},'MM') as number)"); case "Year": return($"cast(to_char({left},'YYYY') as number)"); case "Hour": return($"cast(to_char({left},'HH24') as number)"); case "Minute": return($"cast(to_char({left},'MI') as number)"); case "Second": return($"cast(to_char({left},'SS') as number)"); case "Millisecond": return($"cast(to_char({left},'FF3') as number)"); case "Ticks": return($"cast(to_char({left},'FF7') as number)"); } return(null); }
public override string ExpressionLambdaToSqlOther(Expression exp, ExpTSC tsc) { Func <Expression, string> getExp = exparg => ExpressionLambdaToSql(exparg, tsc); switch (exp.NodeType) { case ExpressionType.ArrayLength: var arrOper = (exp as UnaryExpression)?.Operand; if (arrOper.Type == typeof(byte[])) { return($"dbms_lob.getlength({getExp(arrOper)})"); } break; case ExpressionType.Convert: var operandExp = (exp as UnaryExpression)?.Operand; var gentype = exp.Type.NullableTypeOrThis(); if (gentype != operandExp.Type.NullableTypeOrThis()) { switch (exp.Type.NullableTypeOrThis().ToString()) { //case "System.Boolean": return $"({getExp(operandExp)} not in ('0','false'))"; case "System.Byte": return($"cast({getExp(operandExp)} as number)"); case "System.Char": return($"substr(to_char({getExp(operandExp)}), 1, 1)"); case "System.DateTime": return($"to_timestamp({getExp(operandExp)},'YYYY-MM-DD HH24:MI:SS.FF6')"); case "System.Decimal": return($"cast({getExp(operandExp)} as number)"); case "System.Double": return($"cast({getExp(operandExp)} as number)"); case "System.Int16": case "System.Int32": case "System.Int64": case "System.SByte": return($"cast({getExp(operandExp)} as number)"); case "System.Single": return($"cast({getExp(operandExp)} as number)"); case "System.String": return($"to_char({getExp(operandExp)})"); case "System.UInt16": case "System.UInt32": case "System.UInt64": return($"cast({getExp(operandExp)} as number)"); case "System.Guid": if (tsc.mapType == typeof(byte[])) { return($"hextoraw({getExp(operandExp)})"); } return($"to_char({getExp(operandExp)})"); } } break; case ExpressionType.Call: var callExp = exp as MethodCallExpression; switch (callExp.Method.Name) { case "Parse": case "TryParse": switch (callExp.Method.DeclaringType.NullableTypeOrThis().ToString()) { //case "System.Boolean": return $"({getExp(callExp.Arguments[0])} not in ('0','false'))"; case "System.Byte": return($"cast({getExp(callExp.Arguments[0])} as number)"); case "System.Char": return($"substr(to_char({getExp(callExp.Arguments[0])}), 1, 1)"); case "System.DateTime": return($"to_timestamp({getExp(callExp.Arguments[0])},'YYYY-MM-DD HH24:MI:SS.FF6')"); case "System.Decimal": return($"cast({getExp(callExp.Arguments[0])} as number)"); case "System.Double": return($"cast({getExp(callExp.Arguments[0])} as number)"); case "System.Int16": case "System.Int32": case "System.Int64": case "System.SByte": return($"cast({getExp(callExp.Arguments[0])} as number)"); case "System.Single": return($"cast({getExp(callExp.Arguments[0])} as number)"); case "System.UInt16": case "System.UInt32": case "System.UInt64": return($"cast({getExp(callExp.Arguments[0])} as number)"); case "System.Guid": if (tsc.mapType == typeof(byte[])) { return($"hextoraw({getExp(callExp.Arguments[0])})"); } return($"to_char({getExp(callExp.Arguments[0])})"); } return(null); case "NewGuid": return(null); case "Next": if (callExp.Object?.Type == typeof(Random)) { return("cast(dbms_random.value*1000000000 as smallint)"); } return(null); case "NextDouble": if (callExp.Object?.Type == typeof(Random)) { return("dbms_random.value"); } return(null); case "Random": if (callExp.Method.DeclaringType.IsNumberType()) { return("dbms_random.value"); } return(null); case "ToString": if (callExp.Object != null) { return(callExp.Arguments.Count == 0 ? $"to_char({getExp(callExp.Object)})" : null); } return(null); } var objExp = callExp.Object; var objType = objExp?.Type; if (objType?.FullName == "System.Byte[]") { return(null); } var argIndex = 0; if (objType == null && callExp.Method.DeclaringType == typeof(Enumerable)) { objExp = callExp.Arguments.FirstOrDefault(); objType = objExp?.Type; argIndex++; if (objType == typeof(string)) { switch (callExp.Method.Name) { case "First": case "FirstOrDefault": return($"substr({getExp(callExp.Arguments[0])}, 1, 1)"); } } } if (objType == null) { objType = callExp.Method.DeclaringType; } if (objType != null || objType.IsArrayOrList()) { if (argIndex >= callExp.Arguments.Count) { break; } tsc.SetMapColumnTmp(null); var args1 = getExp(callExp.Arguments[argIndex]); var oldMapType = tsc.SetMapTypeReturnOld(tsc.mapTypeTmp); var oldDbParams = tsc.SetDbParamsReturnOld(null); var left = objExp == null ? null : getExp(objExp); tsc.SetMapColumnTmp(null).SetMapTypeReturnOld(oldMapType); tsc.SetDbParamsReturnOld(oldDbParams); switch (callExp.Method.Name) { case "Contains": //判断 in //在各大 Provider AdoProvider 中已约定,500元素分割, 3空格\r\n4空格 return($"(({args1}) in {left.Replace(", \r\n \r\n", $") \r\n OR ({args1}) in (")})"); } } break; case ExpressionType.NewArrayInit: var arrExp = exp as NewArrayExpression; var arrSb = new StringBuilder(); arrSb.Append("("); for (var a = 0; a < arrExp.Expressions.Count; a++) { if (a > 0) { arrSb.Append(","); } if (a % 500 == 499) { arrSb.Append(" \r\n \r\n"); //500元素分割, 3空格\r\n4空格 } arrSb.Append(getExp(arrExp.Expressions[a])); } if (arrSb.Length == 1) { arrSb.Append("NULL"); } return(arrSb.Append(")").ToString()); case ExpressionType.ListInit: var listExp = exp as ListInitExpression; var listSb = new StringBuilder(); listSb.Append("("); for (var a = 0; a < listExp.Initializers.Count; a++) { if (listExp.Initializers[a].Arguments.Any() == false) { continue; } if (a > 0) { listSb.Append(","); } listSb.Append(getExp(listExp.Initializers[a].Arguments.FirstOrDefault())); } if (listSb.Length == 1) { listSb.Append("NULL"); } return(listSb.Append(")").ToString()); case ExpressionType.New: var newExp = exp as NewExpression; if (typeof(IList).IsAssignableFrom(newExp.Type)) { if (newExp.Arguments.Count == 0) { return("(NULL)"); } if (typeof(IEnumerable).IsAssignableFrom(newExp.Arguments[0].Type) == false) { return("(NULL)"); } return(getExp(newExp.Arguments[0])); } return(null); } return(null); }