Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1349,9 +1349,6 @@ internal static ArgumentOutOfRangeException InvalidParameterDirection(ParameterD
internal static ArgumentException InvalidSizeValue(int value)
=> Argument(StringsHelper.GetString(Strings.ADP_InvalidSizeValue, value.ToString(CultureInfo.InvariantCulture)));

internal static ArgumentException ParameterValueOutOfRange(decimal value)
=> ADP.Argument(StringsHelper.GetString(Strings.ADP_ParameterValueOutOfRange, value.ToString((IFormatProvider)null)));

internal static ArgumentException ParameterValueOutOfRange(SqlDecimal value) => ADP.Argument(StringsHelper.GetString(Strings.ADP_ParameterValueOutOfRange, value.ToString()));

internal static ArgumentException ParameterValueOutOfRange(string value) => ADP.Argument(StringsHelper.GetString(Strings.ADP_ParameterValueOutOfRange, value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8306,7 +8306,7 @@ internal static SqlDecimal AdjustSqlDecimalScale(SqlDecimal d, int newScale)
return d;
}

internal static decimal AdjustDecimalScale(decimal value, int newScale)
internal static SqlDecimal AdjustDecimalScale(decimal value, int newScale)
{
#if NET
Span<int> decimalBits = stackalloc int[4];
Expand All @@ -8315,16 +8315,15 @@ internal static decimal AdjustDecimalScale(decimal value, int newScale)
int[] decimalBits = decimal.GetBits(value);
#endif
int oldScale = (decimalBits[3] & 0x00ff0000) >> 0x10;
SqlDecimal num = new SqlDecimal(value);

if (newScale != oldScale)
{
bool round = !LocalAppContextSwitches.TruncateScaledDecimal;
SqlDecimal num = new SqlDecimal(value);
num = SqlDecimal.AdjustScale(num, newScale - oldScale, round);
return num.Value;
}

return value;
return num;
}

internal byte[] SerializeSqlDecimal(SqlDecimal d, TdsParserStateObject stateObj)
Expand Down Expand Up @@ -10457,34 +10456,31 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet
// bug 49512, make sure the value matches the scale the user enters
if (!isNull)
{
SqlDecimal adjustedValue;

if (isSqlVal)
{
value = AdjustSqlDecimalScale((SqlDecimal)value, scale);

// If Precision is specified, verify value precision vs param precision
if (precision != 0)
{
if (precision < ((SqlDecimal)value).Precision)
{
throw ADP.ParameterValueOutOfRange((SqlDecimal)value);
}
}
adjustedValue = AdjustSqlDecimalScale((SqlDecimal)value, scale);
}
else
{
value = AdjustDecimalScale((Decimal)value, scale);

SqlDecimal sqlValue = new SqlDecimal((Decimal)value);
// If we encounter a System.Decimal at this point, we always convert it to
// a SqlDecimal. It's necessary in order to adjust the scale and to be able
// to transport the full range of numeric(38,X) values without overflowing.
adjustedValue = AdjustDecimalScale((decimal)value, scale);
isSqlVal = true;
}

// If Precision is specified, verify value precision vs param precision
if (precision != 0)
// If Precision is specified, verify value precision vs param precision
if (precision != 0)
{
if (precision < adjustedValue.Precision)
{
if (precision < sqlValue.Precision)
{
throw ADP.ParameterValueOutOfRange((Decimal)value);
}
throw ADP.ParameterValueOutOfRange(adjustedValue);
}
}

value = adjustedValue;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand Down Expand Up @@ -175,7 +175,7 @@ public void SqlParameterProperties(string connection)
string inputProcedureName = DataTestUtility.GetShortName("InputProc").ToString();
string outputProcedureName = DataTestUtility.GetShortName("OutputProc").ToString();
const int charColumnSize = 100;
const int decimalColumnPrecision = 10;
const int decimalColumnPrecision = 38;
const int decimalColumnScale = 4;
const int timeColumnScale = 5;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand Down Expand Up @@ -516,6 +516,36 @@ public static void TestScaledDecimalParameter_CommandInsert(string connectionStr
Assert.True(ValidateInsertedValues(connection, decimalTable.Name, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
}

[Fact]
public static void TestOutOfRangeDecimalParameter_CommandInsert()
{
using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
connection.Open();

using SqlCommand cmd = new("SELECT @Value", connection);
// A System.Decimal value has a maximum precision of 29 digits. We specify a Precision of 38 and a Scale of 2 in order
// to prove that the client can change the scale and precision of the decimal value in ways which System.Decimal doesn't
// intrinsically support.
SqlParameter p = new("@Value", decimal.MaxValue)
{
Precision = 38,
Scale = 2
};

cmd.Parameters.Add(p);

using SqlDataReader reader = cmd.ExecuteReader();

reader.Read();
// Read the original value back as a SqlDecimal, with matching scale and precision.
SqlDecimal roundtrippedDecimal = reader.GetSqlDecimal(0);

Assert.Equal(38, roundtrippedDecimal.Precision);
Assert.Equal(2, roundtrippedDecimal.Scale);
Assert.Throws<OverflowException>(() => roundtrippedDecimal.Value);
Assert.Equal($"{decimal.MaxValue}.00", roundtrippedDecimal.ToString());
}

[Theory]
[ClassData(typeof(ConnectionStringsProvider))]
public static void TestScaledDecimalParameter_BulkCopy(string connectionString, bool truncateScaledDecimal)
Expand Down
Loading