bulkcopy() silently truncates fractional seconds in string datetime values to microseconds
Maintainer thường phản hồi trong vòng 2 ngày
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 48/100
Hướng nghiên cứu
Start by tracing how Cursor.bulkcopy() parses string values into DATETIME2 and DATETIMEOFFSET, then compare that path with execute()/executemany() and the Arrow timestamp path. Reproduce with the supplied seven-digit fractional value and trailing-Z example, checking behavior on Python 3.10 and 3.11. Done means bulkcopy preserves all seven digits like executemany and accepts server-valid input, or rejects precision loss explicitly.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
When a string is bound to a DATETIME2 column through Cursor.bulkcopy(), the Rust core parses it with Python's datetime.fromisoformat before sending it. datetime only holds microseconds, so a seven-digit fraction is truncated to six with no warning. The same string through execute()/executemany() is sent to the server as text and SQL Server stores all seven digits.
On Python 3.10 the same parser also rejects a trailing Z, which the server accepts. From 3.11 that case works. This is probably fine since python 3.10 is EOL in a few days, but I wanted to raise since your docs explicitly say you need >=3.10 for bulkcopy.
To reproduce
import uuid
import mssql_python
conn = mssql_python.connect(CONN_STR, autocommit=True)
cur = conn.cursor()
table = f"dbo.Repro_{uuid.uuid4().hex[:8]}"
cur.execute(f"CREATE TABLE {table} (lbl VARCHAR(20), dt DATETIME2)")
value = "2024-07-01 12:00:00.1234567"
cur.executemany(f"INSERT INTO {table} VALUES (?, ?)", [("executemany", value)])
cur.bulkcopy(table, [("bulkcopy", value)])
cur.execute(f"SELECT lbl, CONVERT(varchar(27), dt, 121) FROM {table}")
print(cur.fetchall())
cur.execute(f"DROP TABLE {table}")
Observed:
Python 3.11:
[('executemany', '2024-07-01 12:00:00.1234567'),
('bulkcopy', '2024-07-01 12:00:00.1234560')]
Python 3.10, where fromisoformat also rejects Z:
cur.bulkcopy(table, [("bulkcopy", "2024-07-01T12:00:00Z")])
ValueError: Invalid datetime format '2024-07-01T12:00:00Z'. Expected ISO format like
'2024-01-15 09:30:00' or '2024-01-15T09:30:00': ValueError: Invalid isoformat string: ...
Note:
bulkcopy_arrow() with a timestamp[ns] column stores all seven digits, into both DATETIME2 and DATETIMEOFFSET:
import pyarrow as pa
ns = pa.array([1719835200_123456700], pa.timestamp("ns")) # 2024-07-01 12:00:00.1234567
cur.bulkcopy_arrow(table, pa.table({"lbl": ["arrow"], "dt": ns}))
# -> '2024-07-01 12:00:00.1234567'
Expected behavior
bulkcopy() stores the same value as executemany() for the same input string. In particular, a DATETIME2(7) column receives all seven digits, and inputs that SQL Server accepts are not rejected on the client.
Suggested fixes, in order of preference
- Parse ISO 8601 strings in Rust directly into the TDS DATETIME2/DATETIMEOFFSET representation, which has 100 ns resolution, the same way the Arrow path already consumes nanosecond buffers. This also removes the dependence on the running interpreter's fromisoformat behaviour.
- Alternatively, send string values for datetime columns to the server as text and let it convert, matching the execute path.
- At minimum, raise when a fraction has more digits than can be represented instead of truncating. Silent data loss is the worst of the three outcomes.
- Ngôn ngữ chính
- Python
- Star
- 481
- Fork
- 62
- Merge trung bình
- 2 ngày 14 giờ
- Pull request đã merge (30 ngày)
- 14
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của microsoft/mssql-python
-
Make azure-identity an optional dependencyCó thể đã có người làm @jahnvi480 đã nhận 1 ngày trước. Đang mởarea: connectivity-auth dependencies enhancement triage needed
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
microsoft/mssql-python#862 · 3 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
triage needed
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 38/100
microsoft/mssql-python#850 · 2 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 2 ngày
-
bulkcopy() & bulkcopy_arrow() fail with Schannel AcquireCredentialsHandleW error 0x8009030D (SEC_E_UNKNOWN_CREDENTIALS)Có thể đã có người làm @jahnvi480 đã nhận 9 ngày trước. Đang mởarea: bulk-copy bug inADO triage done
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 20/100
microsoft/mssql-python#848 · 5 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
macOS: encrypted connections fail after Homebrew moved the `openssl` alias to `openssl@4`Có thể làm lại được @bewithgaurav đã nhận 29 ngày trước và không có pull request nào đang mở. Đang mởarea: packaging-platform bug triage needed
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 55/100
microsoft/mssql-python#826 · 2 bình luận · 4 reaction · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Announcement: mssql-python is coming to Django through mssql-django 2.0Có thể làm lại được @bewithgaurav đã nhận 56 ngày trước và không có pull request nào đang mở. Đang mởannouncement
microsoft/mssql-python#748 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của microsoft/mssql-python
Issue tương tự
-
Skill submission: negative-test-first (testing discipline; PR creation is collaborator-only)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
ComposioHQ/awesome-claude-skills#2398 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
bug converter
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
grafana/sigma-rule-deployment#435 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 73/100
datamodel-code-generator/datamodel-code-generator#5589 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Shell: serve the home app's Cookie Policy on a hard reloadCó thể đã có người làm @2001anshkaushik đã nhận hôm nay. Đang mởfeature module:ai
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
rocketride-org/rocketride-server#2899 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
GEFSv12
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100