Closed denck007 closed 1 year ago
Could you post an ODBC trace?
This is a trace selecting of selecting 1 item from binary_data_table_varbinary
(the incorrectly parsed one)
kernel-v2-18808 79b8-3724 ENTER SQLAllocHandle
SQLSMALLINT 3 <SQL_HANDLE_STMT>
SQLHANDLE 0x0000027CAE88E3E0
SQLHANDLE * 0x0000027CDB812748
kernel-v2-18808 79b8-3724 EXIT SQLAllocHandle with return code 0 (SQL_SUCCESS)
SQLSMALLINT 3 <SQL_HANDLE_STMT>
SQLHANDLE 0x0000027CAE88E3E0
SQLHANDLE * 0x0000027CDB812748 ( 0x0000027CD37AA540)
kernel-v2-18808 79b8-3724 ENTER SQLFreeStmt
HSTMT 0x0000027CD37AA540
UWORD 0 <SQL_CLOSE>
kernel-v2-18808 79b8-3724 EXIT SQLFreeStmt with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 0 <SQL_CLOSE>
kernel-v2-18808 79b8-3724 ENTER SQLExecDirectW
HSTMT 0x0000027CD37AA540
WCHAR * 0x0000027CDB477DF0 [ 112] "SELECT TOP 1 binary_data_table_varbinary.id, binary_data_table_varbinary.value \ aFROM binary_data_table_varbinary"
SDWORD 112
kernel-v2-18808 79b8-3724 EXIT SQLExecDirectW with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
WCHAR * 0x0000027CDB477DF0 [ 112] "SELECT TOP 1 binary_data_table_varbinary.id, binary_data_table_varbinary.value \ aFROM binary_data_table_varbinary"
SDWORD 112
kernel-v2-18808 79b8-3724 ENTER SQLRowCount
HSTMT 0x0000027CD37AA540
SQLLEN * 0x000000AAD67E9DD8
kernel-v2-18808 79b8-3724 EXIT SQLRowCount with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
SQLLEN * 0x000000AAD67E9DD8 (-1)
kernel-v2-18808 79b8-3724 ENTER SQLNumResultCols
HSTMT 0x0000027CD37AA540
SWORD * 0x000000AAD67E9DC0
kernel-v2-18808 79b8-3724 EXIT SQLNumResultCols with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
SWORD * 0x000000AAD67E9DC0 (2)
kernel-v2-18808 79b8-3724 ENTER SQLDescribeCol
HSTMT 0x0000027CD37AA540
UWORD 1
UCHAR * 0x000000AAD67E9C70
SWORD 200
SWORD * 0x000000AAD67E9C5C
SWORD * 0x000000AAD67E9C50
SQLULEN * 0x000000AAD67E9C60
SWORD * 0x000000AAD67E9C58
SWORD * 0x000000AAD67E9C54
kernel-v2-18808 79b8-3724 EXIT SQLDescribeCol with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 1
UCHAR * 0x000000AAD67E9C70 [ 2] "id"
SWORD 200
SWORD * 0x000000AAD67E9C5C (2)
SWORD * 0x000000AAD67E9C50 (4)
SQLULEN * 0x000000AAD67E9C60 (10)
SWORD * 0x000000AAD67E9C58 (0)
SWORD * 0x000000AAD67E9C54 (0)
kernel-v2-18808 79b8-3724 ENTER SQLColAttribute
SQLHSTMT 0x0000027CD37AA540
SQLSMALLINT 1
SQLSMALLINT 8 <SQL_DESC_UNSIGNED>
SQLPOINTER 0x0000000000000000
SQLSMALLINT 0
SQLSMALLINT * 0x0000000000000000
SQLPOINTER 0x000000AAD67E9C68
kernel-v2-18808 79b8-3724 EXIT SQLColAttribute with return code 0 (SQL_SUCCESS)
SQLHSTMT 0x0000027CD37AA540
SQLSMALLINT 1
SQLSMALLINT 8 <SQL_DESC_UNSIGNED>
SQLPOINTER 0x0000000000000000
SQLSMALLINT 0
SQLSMALLINT * 0x0000000000000000
SQLPOINTER 0x000000AAD67E9C68 (0) <FALSE>
kernel-v2-18808 79b8-3724 ENTER SQLDescribeCol
HSTMT 0x0000027CD37AA540
UWORD 2
UCHAR * 0x000000AAD67E9C70
SWORD 200
SWORD * 0x000000AAD67E9C5C
SWORD * 0x000000AAD67E9C50
SQLULEN * 0x000000AAD67E9C60
SWORD * 0x000000AAD67E9C58
SWORD * 0x000000AAD67E9C54
kernel-v2-18808 79b8-3724 EXIT SQLDescribeCol with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 2
UCHAR * 0x000000AAD67E9C70 [ 5] "value"
SWORD 200
SWORD * 0x000000AAD67E9C5C (5)
SWORD * 0x000000AAD67E9C50 (-3)
SQLULEN * 0x000000AAD67E9C60 (0)
SWORD * 0x000000AAD67E9C58 (0)
SWORD * 0x000000AAD67E9C54 (1)
kernel-v2-18808 79b8-3724 ENTER SQLDescribeColW
HSTMT 0x0000027CD37AA540
UWORD 1
WCHAR * 0x0000027CDA00E890
SWORD 300
SWORD * 0x000000AAD67E9DA8
SWORD * 0x000000AAD67E9D90
SQLULEN * 0x000000AAD67E9D40
SWORD * 0x000000AAD67E9D34
SWORD * 0x000000AAD67E9D30
kernel-v2-18808 79b8-3724 EXIT SQLDescribeColW with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 1
WCHAR * 0x0000027CDA00E890 [ 2] "id"
SWORD 300
SWORD * 0x000000AAD67E9DA8 (2)
SWORD * 0x000000AAD67E9D90 (4)
SQLULEN * 0x000000AAD67E9D40 (10)
SWORD * 0x000000AAD67E9D34 (0)
SWORD * 0x000000AAD67E9D30 (0)
kernel-v2-18808 79b8-3724 ENTER SQLDescribeColW
HSTMT 0x0000027CD37AA540
UWORD 2
WCHAR * 0x0000027CDA00E890
SWORD 300
SWORD * 0x000000AAD67E9DA8
SWORD * 0x000000AAD67E9D90
SQLULEN * 0x000000AAD67E9D40
SWORD * 0x000000AAD67E9D34
SWORD * 0x000000AAD67E9D30
kernel-v2-18808 79b8-3724 EXIT SQLDescribeColW with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 2
WCHAR * 0x0000027CDA00E890 [ 5] "value"
SWORD 300
SWORD * 0x000000AAD67E9DA8 (5)
SWORD * 0x000000AAD67E9D90 (-3)
SQLULEN * 0x000000AAD67E9D40 (0)
SWORD * 0x000000AAD67E9D34 (0)
SWORD * 0x000000AAD67E9D30 (1)
kernel-v2-18808 79b8-3724 ENTER SQLFetch
HSTMT 0x0000027CD37AA540
kernel-v2-18808 79b8-3724 EXIT SQLFetch with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
kernel-v2-18808 79b8-3724 ENTER SQLGetData
HSTMT 0x0000027CD37AA540
UWORD 1
SWORD 4 <SQL_C_LONG>
PTR <unknown type>
SQLLEN 4
SQLLEN * 0x000000AAD67EAC58
kernel-v2-18808 79b8-3724 EXIT SQLGetData with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 1
SWORD 4 <SQL_C_LONG>
PTR <unknown type>
SQLLEN 4
SQLLEN * 0x000000AAD67EAC58 (4)
kernel-v2-18808 79b8-3724 ENTER SQLGetData
HSTMT 0x0000027CD37AA540
UWORD 2
SWORD -2 <SQL_C_BINARY>
PTR <unknown type>
SQLLEN 4096
SQLLEN * 0x000000AAD67EAC38
kernel-v2-18808 79b8-3724 EXIT SQLGetData with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 2
SWORD -2 <SQL_C_BINARY>
PTR <unknown type>
SQLLEN 4096
SQLLEN * 0x000000AAD67EAC38 (8)
kernel-v2-18808 79b8-3724 ENTER SQLFetch
HSTMT 0x0000027CD37AA540
kernel-v2-18808 79b8-3724 EXIT SQLFetch with return code 100 (SQL_NO_DATA_FOUND)
HSTMT 0x0000027CD37AA540
kernel-v2-18808 79b8-3724 ENTER SQLFreeStmt
HSTMT 0x0000027CD37AA540
UWORD 0 <SQL_CLOSE>
kernel-v2-18808 79b8-3724 EXIT SQLFreeStmt with return code 0 (SQL_SUCCESS)
HSTMT 0x0000027CD37AA540
UWORD 0 <SQL_CLOSE>
kernel-v2-18808 79b8-3724 ENTER SQLFreeHandle
SQLSMALLINT 3 <SQL_HANDLE_STMT>
SQLHANDLE 0x0000027CD37AA540
kernel-v2-18808 79b8-3724 EXIT SQLFreeHandle with return code 0 (SQL_SUCCESS)
SQLSMALLINT 3 <SQL_HANDLE_STMT>
SQLHANDLE 0x0000027CD37AA540
kernel-v2-18808 79b8-3724 ENTER SQLEndTran
SQLSMALLINT 2 <SQL_HANDLE_DBC>
SQLHANDLE 0x0000027CAE88E3E0
SQLSMALLINT 1
kernel-v2-18808 79b8-3724 EXIT SQLEndTran with return code 0 (SQL_SUCCESS)
SQLSMALLINT 2 <SQL_HANDLE_DBC>
SQLHANDLE 0x0000027CAE88E3E0
SQLSMALLINT 1
kernel-v2-18808 79b8-3724 ENTER SQLEndTran
SQLSMALLINT 2 <SQL_HANDLE_DBC>
SQLHANDLE 0x0000027CAE88E3E0
SQLSMALLINT 1
kernel-v2-18808 79b8-3724 EXIT SQLEndTran with return code 0 (SQL_SUCCESS)
SQLSMALLINT 2 <SQL_HANDLE_DBC>
SQLHANDLE 0x0000027CAE88E3E0
SQLSMALLINT 1
I am unable to reproduce your issue. When I run your test code against …
Microsoft SQL Server 2019 (RTM-CU3) (KB4538853) - 15.0.4023.6 (X64)
Mar 4 2020 00:59:26
Copyright (C) 2019 Microsoft Corporation
Developer Edition (64-bit) on Linux (Ubuntu 18.04.4 LTS) <X64>
… I get
sys.version_info=sys.version_info(major=3, minor=11, micro=5, releaselevel='final', serial=0)
pyodbc.version='4.0.39'
np.version.version='1.26.0'
sa.__version__='2.0.21'
VARBINARY
in conversion function: raw=b'\x00\x00\x00\x00\x00\x00\x00\x00' -> out=array([0., 0.], dtype=float32)
in conversion function: raw=b'\x00\x00\x80?\x00\x00\x80?' -> out=array([1., 1.], dtype=float32)
in conversion function: raw=b'\x00\x00\x00@\x00\x00\x80@' -> out=array([2., 4.], dtype=float32)
Result: (1, array([0., 0.], dtype=float32))
Result: (2, array([1., 1.], dtype=float32))
Result: (3, array([2., 4.], dtype=float32))
VARIANT
in conversion function: raw=b'\x00\x00\x00\x00\x00\x00\x00\x00' -> out=array([0., 0.], dtype=float32)
in conversion function: raw=b'\x00\x00\x80?\x00\x00\x80?' -> out=array([1., 1.], dtype=float32)
in conversion function: raw=b'\x00\x00\x00@\x00\x00\x80@' -> out=array([2., 4.], dtype=float32)
Result: (1, array([0., 0.], dtype=float32))
Result: (2, array([1., 1.], dtype=float32))
Result: (3, array([2., 4.], dtype=float32))
I tracked it down, it is related to SQLAlchemy (you used 2.0.21, I had 2.0.8). I searched through versions and found it starts working as expected starting with sqlalchemy==2.0.11. Their change log makes reference to binary data types now being handled on a per driver basis.
Upgrading to sqlalchemy>=2.0.11 fixes the problem.
Environment
Issue
I am implementing a columns to store binary data, the values come from a float32 numpy array. When I add an output converter to the pyodbc connection for the column, the converter function is run but the binary values are returned (not the converted values).
Here is a stand alone example demonstrating this. It creates a table with VARBINARY column and table with VARIANT column. The same value is inserted to both. Output converters are added for each type. The converter for VARBINARY is called but un-converted data is returned, converter for VARIANT is called and the correctly converted values are returned.
Output: