internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) { // process the arguments SqlExpression result = base.VisitFunctionCall(fc); if(result is SqlFunctionCall) { SqlFunctionCall resultFunctionCall = (SqlFunctionCall)result; if(resultFunctionCall.Name == sql.LengthFunctionName) { SqlExpression expr = resultFunctionCall.Arguments[0]; if(expr.SqlType.IsLargeType && !expr.SqlType.SupportsLength) { result = sql.FunctionCallDataLength(expr); if(expr.SqlType.IsUnicodeType) { result = sql.ConvertToInt(sql.Divide(result, sql.ValueFromObject(2, expr.SourceExpression))); } } } // If the return type of the sql function is not compatible with // the expected CLR type of the function, inject a conversion. This // step must be performed AFTER SqlRetyper has run. Type clrType = resultFunctionCall.SqlType.GetClosestRuntimeType(); bool skipConversion = SkipConversionForDateAdd(resultFunctionCall.Name, resultFunctionCall.ClrType, clrType); if((resultFunctionCall.ClrType != clrType) && !skipConversion) { result = sql.ConvertTo(resultFunctionCall.ClrType, resultFunctionCall); } } return result; }
internal virtual SqlExpression VisitFunctionCall(SqlFunctionCall fc) { for (int i = 0, n = fc.Arguments.Count; i < n; i++) { fc.Arguments[i] = this.VisitExpression(fc.Arguments[i]); } return fc; }
internal override ProviderType ReturnTypeOfFunction(SqlFunctionCall functionCall) { var argumentTypes = this.GetArgumentTypes(functionCall); SqlType arg0 = (SqlType)argumentTypes[0]; SqlType arg1 = argumentTypes.Length > 1 ? (SqlType)argumentTypes[1] : (SqlType)null; switch(functionCall.Name) { case "LEN": case "DATALENGTH": switch(arg0.SqlDbType) { case SqlDbType.NVarChar: case SqlDbType.VarChar: case SqlDbType.VarBinary: if(arg0.IsLargeType) { return SqlTypeSystem.Create(SqlDbType.BigInt); } else { return SqlTypeSystem.Create(SqlDbType.Int); } default: return SqlTypeSystem.Create(SqlDbType.Int); } case "ABS": case "SIGN": case "ROUND": case "CEILING": case "FLOOR": case "POWER": switch(arg0.SqlDbType) { case SqlDbType.TinyInt: case SqlDbType.Int: case SqlDbType.SmallInt: return SqlTypeSystem.Create(SqlDbType.Int); case SqlDbType.Float: case SqlDbType.Real: return SqlTypeSystem.Create(SqlDbType.Float); default: return arg0; } case "PATINDEX": case "CHARINDEX": if(arg1.IsLargeType) return SqlTypeSystem.Create(SqlDbType.BigInt); return SqlTypeSystem.Create(SqlDbType.Int); case "SUBSTRING": if(functionCall.Arguments[2].NodeType == SqlNodeType.Value) { SqlValue val = (SqlValue)functionCall.Arguments[2]; if(val.Value is int) { switch(arg0.SqlDbType) { case SqlDbType.NVarChar: case SqlDbType.NChar: case SqlDbType.VarChar: case SqlDbType.Char: return SqlTypeSystem.Create(arg0.SqlDbType, (int)val.Value); default: return null; } } } switch(arg0.SqlDbType) { case SqlDbType.NVarChar: case SqlDbType.NChar: return SqlTypeSystem.Create(SqlDbType.NVarChar); case SqlDbType.VarChar: case SqlDbType.Char: return SqlTypeSystem.Create(SqlDbType.VarChar); default: return null; } case "STUFF": // if the stuff call is an insertion and is strictly additive // (no deletion of characters) the return type is the same as // a concatenation if(functionCall.Arguments.Count == 4) { SqlValue delLength = functionCall.Arguments[2] as SqlValue; if(delLength != null && (int)delLength.Value == 0) { return PredictTypeForBinary(SqlNodeType.Concat, functionCall.Arguments[0].SqlType, functionCall.Arguments[3].SqlType); } } return null; case "LOWER": case "UPPER": case "RTRIM": case "LTRIM": case "INSERT": case "REPLACE": case "LEFT": case "RIGHT": case "REVERSE": return arg0; default: return null; } }
private ProviderType[] GetArgumentTypes(SqlFunctionCall fc) { ProviderType[] array = new ProviderType[fc.Arguments.Count]; for(int i = 0, n = array.Length; i < n; i++) { array[i] = fc.Arguments[i].SqlType; } return array; }
internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) { if(fc.Name.Contains(".")) { // Assume UDF -- bracket the name. this.WriteName(fc.Name); } else { // No ".", so we assume it's a system function name and leave it alone. _commandStringBuilder.Append(fc.Name); } _commandStringBuilder.Append("("); for(int i = 0, n = fc.Arguments.Count; i < n; i++) { if(i > 0) _commandStringBuilder.Append(", "); this.Visit(fc.Arguments[i]); } _commandStringBuilder.Append(")"); return fc; }
internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) { SqlExpression[] args = new SqlExpression[fc.Arguments.Count]; for(int i = 0, n = fc.Arguments.Count; i < n; i++) { args[i] = this.VisitExpression(fc.Arguments[i]); } return new SqlFunctionCall(fc.ClrType, fc.SqlType, fc.Name, args, fc.SourceExpression); }
internal abstract ProviderType ReturnTypeOfFunction(SqlFunctionCall functionCall);
internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) { for(int i = 0, n = fc.Arguments.Count; i < n; i++) { fc.Arguments[i] = this.VisitExpression(fc.Arguments[i]); } if(fc.Arguments.Count > 0) { ProviderType oldType = fc.Arguments[0].SqlType; // if this has a real argument (not e.g. the symbol "DAY" in DATEDIFF(DAY,...)) if(oldType != null) { ProviderType newType = this.typeProvider.ReturnTypeOfFunction(fc); if(newType != null) { fc.SetSqlType(newType); } } } return fc; }
internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) { for (int i = 0, n = fc.Arguments.Count; i < n; i++) { fc.Arguments[i] = this.FetchExpression(fc.Arguments[i]); } return fc; }
internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) { if(fc.Name == "LEN") { bool changed; fc.Arguments[0] = ConvertToMax(fc.Arguments[0], out changed); if(fc.Arguments[0].SqlType.IsLargeType) { this.annotations.Add(fc, new CompatibilityAnnotation( Strings.LenOfTextOrNTextNotSupported(fc.SourceExpression), SqlServerProviderMode.Sql2000)); } } return base.VisitFunctionCall(fc); }