@@ -9974,6 +9974,131 @@ def test_cursor_setinputsizes_with_executemany_float(db_connection):
99749974 cursor.execute("DROP TABLE IF EXISTS #test_inputsizes_float")
99759975
99769976
9977+ def test_setinputsizes_sql_decimal_with_executemany(db_connection):
9978+ """Test setinputsizes with SQL_DECIMAL accepts Python Decimal values (GH-503).
9979+
9980+ Without this fix, passing SQL_DECIMAL or SQL_NUMERIC via setinputsizes()
9981+ caused a RuntimeError because Decimal objects were not converted to
9982+ NumericData before the C binding validated the C type.
9983+ """
9984+ cursor = db_connection.cursor()
9985+
9986+ cursor.execute("DROP TABLE IF EXISTS #test_sis_decimal")
9987+ cursor.execute("""
9988+ CREATE TABLE #test_sis_decimal (
9989+ Name NVARCHAR(100),
9990+ CategoryID INT,
9991+ Price DECIMAL(18,2)
9992+ )
9993+ """)
9994+
9995+ cursor.setinputsizes([
9996+ (mssql_python.SQL_WVARCHAR, 100, 0),
9997+ (mssql_python.SQL_INTEGER, 0, 0),
9998+ (mssql_python.SQL_DECIMAL, 18, 2),
9999+ ])
10000+
10001+ cursor.executemany(
10002+ "INSERT INTO #test_sis_decimal (Name, CategoryID, Price) VALUES (?, ?, ?)",
10003+ [
10004+ ("Widget", 1, decimal.Decimal("19.99")),
10005+ ("Gadget", 2, decimal.Decimal("29.99")),
10006+ ("Gizmo", 3, decimal.Decimal("0.01")),
10007+ ],
10008+ )
10009+
10010+ cursor.execute("SELECT Name, CategoryID, Price FROM #test_sis_decimal ORDER BY CategoryID")
10011+ rows = cursor.fetchall()
10012+
10013+ assert len(rows) == 3
10014+ assert rows[0][0] == "Widget"
10015+ assert rows[0][1] == 1
10016+ assert rows[0][2] == decimal.Decimal("19.99")
10017+ assert rows[1][0] == "Gadget"
10018+ assert rows[1][1] == 2
10019+ assert rows[1][2] == decimal.Decimal("29.99")
10020+ assert rows[2][0] == "Gizmo"
10021+ assert rows[2][1] == 3
10022+ assert rows[2][2] == decimal.Decimal("0.01")
10023+
10024+ cursor.execute("DROP TABLE IF EXISTS #test_sis_decimal")
10025+
10026+
10027+ def test_setinputsizes_sql_numeric_with_executemany(db_connection):
10028+ """Test setinputsizes with SQL_NUMERIC accepts Python Decimal values (GH-503)."""
10029+ cursor = db_connection.cursor()
10030+
10031+ cursor.execute("DROP TABLE IF EXISTS #test_sis_numeric")
10032+ cursor.execute("""
10033+ CREATE TABLE #test_sis_numeric (
10034+ Value NUMERIC(10,4)
10035+ )
10036+ """)
10037+
10038+ cursor.setinputsizes([
10039+ (mssql_python.SQL_NUMERIC, 10, 4),
10040+ ])
10041+
10042+ cursor.executemany(
10043+ "INSERT INTO #test_sis_numeric (Value) VALUES (?)",
10044+ [
10045+ (decimal.Decimal("123.4567"),),
10046+ (decimal.Decimal("-99.0001"),),
10047+ (decimal.Decimal("0.0000"),),
10048+ ],
10049+ )
10050+
10051+ cursor.execute("SELECT Value FROM #test_sis_numeric ORDER BY Value")
10052+ rows = cursor.fetchall()
10053+
10054+ assert len(rows) == 3
10055+ assert rows[0][0] == decimal.Decimal("-99.0001")
10056+ assert rows[1][0] == decimal.Decimal("0.0000")
10057+ assert rows[2][0] == decimal.Decimal("123.4567")
10058+
10059+ cursor.execute("DROP TABLE IF EXISTS #test_sis_numeric")
10060+
10061+
10062+ def test_setinputsizes_sql_decimal_with_execute(db_connection):
10063+ """Test setinputsizes with SQL_DECIMAL works with single execute() too (GH-503)."""
10064+ cursor = db_connection.cursor()
10065+
10066+ cursor.execute("DROP TABLE IF EXISTS #test_sis_dec_exec")
10067+ cursor.execute("CREATE TABLE #test_sis_dec_exec (Price DECIMAL(18,2))")
10068+
10069+ cursor.setinputsizes([(mssql_python.SQL_DECIMAL, 18, 2)])
10070+ cursor.execute(
10071+ "INSERT INTO #test_sis_dec_exec (Price) VALUES (?)",
10072+ decimal.Decimal("99.95"),
10073+ )
10074+
10075+ cursor.execute("SELECT Price FROM #test_sis_dec_exec")
10076+ row = cursor.fetchone()
10077+ assert row[0] == decimal.Decimal("99.95")
10078+
10079+ cursor.execute("DROP TABLE IF EXISTS #test_sis_dec_exec")
10080+
10081+
10082+ def test_setinputsizes_sql_decimal_null(db_connection):
10083+ """Test setinputsizes with SQL_DECIMAL handles NULL values correctly (GH-503)."""
10084+ cursor = db_connection.cursor()
10085+
10086+ cursor.execute("DROP TABLE IF EXISTS #test_sis_dec_null")
10087+ cursor.execute("CREATE TABLE #test_sis_dec_null (Price DECIMAL(18,2))")
10088+
10089+ cursor.setinputsizes([(mssql_python.SQL_DECIMAL, 18, 2)])
10090+ cursor.execute(
10091+ "INSERT INTO #test_sis_dec_null (Price) VALUES (?)",
10092+ None,
10093+ )
10094+
10095+ cursor.execute("SELECT Price FROM #test_sis_dec_null")
10096+ row = cursor.fetchone()
10097+ assert row[0] is None
10098+
10099+ cursor.execute("DROP TABLE IF EXISTS #test_sis_dec_null")
10100+
10101+
997710102def test_cursor_setinputsizes_reset(db_connection):
997810103 """Test that setinputsizes is reset after execution"""
997910104
0 commit comments