mkleehammer / pyodbc

Python ODBC bridge
https://github.com/mkleehammer/pyodbc/wiki
MIT No Attribution
2.95k stars 563 forks source link

Decimal value length incorrectly calculated when fast_executemany = True #1232

Closed boneill81 closed 1 year ago

boneill81 commented 1 year ago

Environment

Issue

Expected behavior: Decimals of correct length inserted to database column of correct precision,scale.

Observed behavior: Decimals of allowable length fail to insert and throw truncation errors such as the following:

'String data, right truncation: length 24 buffer 22', 'HY000'

Error occurs only when fast_executemany = True and appears to be caused by pyodbc including the sign and decimal point in the length calculation for the decimal value.

Minimum Reproducible Example

import pyodbc

"""
In the following example, inserting the test decimal fails when
fast_executemany = True. The reason appears to be that pyodbc includes
the sign and decimal point in the length calculation of the value being inserted.
This does not happen in SQL Server Management Studio or when fast_executemany = True.

This is likely related to the way in which pyodbc converts values
to their "ODBC C" equivalents when fast_executemany = True.
https://github.com/mkleehammer/pyodbc/wiki/Cursor#executemanysql-params-with-fast_executemanytrue

Hence this is perhaps just a snippet to help others whom encounter the same issue
when inserting decimal values with fast_executemany = True.
"""

connection_string = (
    "DRIVER=ODBC Driver 17 for SQL Server;"
    "SERVER=dbserver;"
    "Trusted_Connection=yes;"
    "DATABASE=sandbox;"
)

with pyodbc.connect(connection_string).cursor() as crsr:
    crsr.execute('''IF OBJECT_ID('pyodbc_test','U') IS NULL
                     CREATE TABLE pyodbc_test (test_dec decimal(11,8));''')
    crsr.fast_executemany = True
    crsr.executemany("INSERT INTO pyodbc_test (test_dec) VALUES (?)", [('-53.12345678',)])
    print("Decimal inserted.")
gordthompson commented 1 year ago

duplicate of #845