Closed ghost closed 2 years ago
I am able to reproduce the issue. fast_executemany = True
causes PostgreSQL ODBC to drop fractional seconds
from datetime import datetime
import pyodbc
connection_string = (
"DRIVER=PostgreSQL Unicode;"
"SERVER=192.168.0.199;"
"UID=scott;PWD=tiger;"
"DATABASE=test;"
)
cnxn = pyodbc.connect(connection_string, autocommit=True)
print(cnxn.getinfo(pyodbc.SQL_DRIVER_VER)) # 13.02.0000
crsr = cnxn.cursor()
crsr.execute("TRUNCATE TABLE data_table")
data = [(datetime(2022, 2, 3, 17, 28, 15, 344014),)]
crsr.fast_executemany = True
crsr.executemany("INSERT INTO data_table (dt) VALUES (?)", data)
print(crsr.execute("SELECT * FROM data_table").fetchall())
# [(datetime.datetime(2022, 2, 3, 17, 28, 15), )]
The fractional seconds are preserved if fast_executemany = False
.
Fractional seconds are preserved with fast_executemany = True
when using ODBC Driver 17 for SQL Server.
A possible explanation for the difference is that PostgreSQL ODBC returns this
gh1023 1824-ae4 EXIT SQLDescribeParam with return code 0 (SQL_SUCCESS)
HSTMT 0x000000B57096CC00
UWORD 1
SWORD * 0x000000B570A431C2 (93)
SQLULEN * 0x000000B570A431C8 (26)
SWORD * 0x000000B570A431D0 (-1)
SWORD * 0x000000B57085F458 (1)
whereas msodbcsql returns this
gh1023 1094-a18 EXIT SQLDescribeParam with return code 0 (SQL_SUCCESS)
HSTMT 0x0000007F5ABA1180
UWORD 1
SWORD * 0x0000007F580E2CA2 (93)
SQLULEN * 0x0000007F580E2CA8 (27)
SWORD * 0x0000007F580E2CB0 (7)
SWORD * 0x0000007F5770EF38 (1)
Thanks. fast_executemany = False
helps.
According to Driver-support-for-fast_executemany this shouldn't impact speed significantly. One might put a note on that page linking this exceptional case.
The wiki page has been updated.
https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/decimal-digits "The number of digits to the right of the decimal point in the seconds part of the value (fractional seconds). This number cannot be negative."
Looks like buggy ODBC driver.
Hello,
I've been investigating the issues with ETL that is transferring data from MS SQL to PostgreSQL using following environment:
Was able to reproduce issue without sourcing data from MS SQL Server, just mocking some datetimes. datetime2(7) from MS SQL should be saved to timestamp(6) in PosgreSQL with 6 digits in milliseconds.
Actual output:
Expected output:
Notice that milliseconds are not saved into PostgreSQL, when executemany is used to save data.
This is how it looks in database: