fix: report temporal fractional precision - #23
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Python
datetime.datetime(2024, 2, 29, 23, 59, 59, 123456)bound by pyodbc 5.3.0 to a MatrixOneDATETIME(6)orTIMESTAMP(6)column is stored as.100000, losing five fractional-second digits.Direct SQL literals preserve
.123456, and a direct ODBC bind withSQL_TIMESTAMP_STRUCT.fraction=123456000,ColumnSize=26, andDecimalDigits=6also preserves.123456.Root cause
pyodbc calls
SQLGetTypeInfo(SQL_TYPE_TIMESTAMP)once per connection and computes its datetime bind precision asCOLUMN_SIZE - 20. The driver advertised:datetime:COLUMN_SIZE=21,MINIMUM_SCALE=0,MAXIMUM_SCALE=0timestamp:COLUMN_SIZE=14,MINIMUM_SCALE=0,MAXIMUM_SCALE=0pyodbc therefore truncated the Python fraction to one digit before calling
SQLBindParameter. MatrixOne supportsDATETIME(6)andTIMESTAMP(6), whose full display width is 26.Fix
Advertise
COLUMN_SIZE=26,MINIMUM_SCALE=0, andMAXIMUM_SCALE=6for both datetime and timestamp.Add an end-to-end
mo_odbc_deepregression that callsSQLGetTypeInfo(SQL_TYPE_TIMESTAMP), finds both rows, and asserts all three fields.Reproduction
Before / after
8f1ca365):timestamp_type_info=FAIL; pyodbc stored.100000.c0ea21ea):timestamp_type_info=PASS; raw timestamp fraction bind, SQLForeignKeys, timeout, and cancel remain PASS.The direct verifier loads the built DLL itself and does not depend on replacing the installed driver.
Test scope
mo_odbc_deep: PASSgit diff --check: PASSSQLGetTypeInfocomparison: expected FAIL / PASSSQL_TIMESTAMP_STRUCTfraction round trip: PASSSQLForeignKeysW: PASSHYT00): PASSHY008): PASSTest server: MatrixOne
592ad2190a90e063e3877059f4018427a10a4998.Note: Python
datetime.timemicroseconds are a separate portability limitation because standardSQL_TIME_STRUCThas no fraction field. Binding the TIME value as an ISO string preserves microseconds and is not changed by this PR.