String right truncation pyodbc.ProgrammingError when using `fast_executemany`
See original GitHub issueEnvironment
To diagnose, we usually need to know the following, including version numbers. On Windows, be sure to specify 32-bit Python or 64-bit:
- Python: 3.6.3
- pyodbc: 4.0.23
- OS: Debian Stretch
- DB: SQL Server
- driver: Microsoft ODBC Driver 17 for SQL Server libmsodbcsql-17.0.so.1.1
Issue
When executing a parameterized “UPDATE” statement with fast_executemany, the following exception is thrown.
ERROR - encoding with 'utf-16le' codec failed (SystemError: <built-in function utf_16_le_encode> returned a result with an error set)
pyodbc.ProgrammingError: ('String data, right truncation: length 666 buffer 510', 'HY000')
The column widths in the target database have more than enough size to hold the data. This seems equivalent to Issue #337 except that in this case, I’m using 4.0.23 of pyodbc and MS ODBC Driver 17, which fixed the issue in that post but continue to be a problem for me.
I’ve trimmed down the data to just two rows and can consistently reproduce the problem with just those two rows.
I’m using SQL Alchemy to construct the statements and am using the connection.execute(stmt, [row1, row2]) method to execute.
Turning fast_executemany off fixes the problem, but unacceptably impacts performance.
Issue Analytics
- State:
- Created 5 years ago
- Comments:9 (2 by maintainers)
Top Related StackOverflow Question
I’ve narrowed this down to be a variation of #280
When the SQL statement contains more than one statement (i.e. more complex transactions, try catch blocks, etc…) and fast_executemany=True, the SQLDescribeParam call doesn’t work and thus VARCHARs are allocated a default buffer size of 510 bytes. This seems to be a known behaviour of
SQLDescribeParam:The following code will reproduce the error (note the “print” statement in the SQL, but this could be TRY/CATCH BLOCKS, etc…
(note that in the actual application, the SQL is significantly more complicated; this is the simplest case that will reproduce the error)
This produces the output with errors:
However, changing any one of the below will avoid the exception:
fast_executemanytoFalseNote that unlike the solution in the wiki, a temporary table is not being used, and
ColumnEncryption=EnabledIt’s unclear to me why this problem happens when
fast_executemany=Truebut not whenFalseas I would think thatSQLDescribeParameterwould have the same behaviour in either case, but I’m going to guess it’s because in the latter case, a memory array doesn’t need to be pre-allocated.Looking at @v-chojas 's
setinputsizesPR – but as far as I can tell, it hasn’t been merged into master, and it doesn’t look like it is impacting the array allocation inparams.cpp::ExecuteMulti? Any ideas for a workaround?A common thread seems to be the buffer is capped at 510, which is 2 x 255 – which suggests fast_executemany sometimes assumes a maximum string length of 255 characters (510 bytes)