Skip to content

fix: preserve negative timedelta values in MySQL parameters - #150

Merged
kesmit13 merged 3 commits into
singlestore-labs:mainfrom
Kayvan-Zahiri:codex/preserve-negative-timedelta-parameters
Nov 2, 2026
Merged

kesmit13 merged 3 commits into
singlestore-labs:mainfrom
Kayvan-Zahiri:codex/preserve-negative-timedelta-parameters

Conversation

@Kayvan-Zahiri

@Kayvan-Zahiri Kayvan-Zahiri commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The MySQL parameter encoder combines normalized timedelta.days (negative) with the nonnegative seconds and microseconds fields. This changes negative durations when formatting SQL parameters:

from datetime import timedelta
from singlestoredb.mysql import connect
cursor = connect(defer_connect=True).cursor()
cursor.mogrify('SELECT %s', (timedelta(seconds=-1),))
# Before: "SELECT '-1:59:59'"
# After:  "SELECT '-00:00:01'"

A negative microsecond similarly becomes '-1:59:59.999999' instead of '-00:00:00.000001'.

Change

Format the absolute duration and attach its sign once, preserving the existing positive/zero formatting. Add offline public cursor mogrify() regressions and converter round-trip assertions for negative subsecond, second, minute, hour, multi-day, fractional values, and positive/zero controls.

Validation

  • Before: 6 negative cases fail; 4 existing-behavior controls pass.
  • After: all 10 cases pass, also in SINGLESTOREDB_PURE_PYTHON=1 mode.
  • Installed the required pre-commit hook and ran every applicable configured hook against the two changed files; all pass, including Flake8 and MyPy.
  • git diff --check passes.

Python 3.12, editable SDK. These tests use deferred connections and never connect to a server. The full MySQL/HTTP protocol suites, accelerated binding path, and management/cloud tests were not run. An exploratory doctest run of unchanged singlestoredb.converters had two existing examples expecting printed None (Python prints nothing for that return value); its other 11 examples passed. No unrelated docstring changes included.


Note

Low Risk
Scoped change to timedelta parameter formatting with regression tests; fixes incorrect literals rather than altering unrelated binding behavior.

Overview
Fixes incorrect TIME literals when binding negative datetime.timedelta values. The encoder previously mixed negative days with nonnegative seconds/microseconds, producing wrong strings (e.g. -1:59:59 instead of -00:00:01).

MySQL (escape_timedelta) and HTTP (encode_timedelta) now take the absolute duration, format hours/minutes/seconds as before, and prepend a single - when days < 0. Positive and zero durations are unchanged.

Adds offline tests that assert cursor.mogrify() and encode_timedelta() match expected literals and round-trip through timedelta_fromisoformat.

Reviewed by Cursor Bugbot for commit e32e0ef. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The localized fix correctly handles negative durations, with focused regression coverage and no unresolved findings.

No open issues 🎉

What changed in this PR

Corrects MySQL parameter encoding for negative timedelta values by formatting the absolute duration and applying the sign once.

Changes:

  • Preserves negative duration magnitudes without changing positive or zero formatting.
  • Adds offline cursor mogrify() regressions and converter round-trip assertions for signed durations.
File Description
singlestoredb/​tests/​test_timedelta_parameters.py Adds negative-duration regressions and positive/zero controls.
singlestoredb/​mysql/​converters.py Separates the duration’s sign from its magnitude during encoding.

Review effort: Balanced

@kesmit13

Copy link
Copy Markdown
Collaborator

Nice catch. This looks like we inherited this issue from the original PyMySQL code. There is another copy of that converter in singlestoredb/http/connection.py that would need the fix as well.

@Kayvan-Zahiri

Copy link
Copy Markdown
Contributor Author

Thanks, good catch. encode_timedelta in singlestoredb/http/connection.py had the same problem, so it gets the same fix in c42b1fc. The test now runs the same cases through the HTTP encoder too; those fail without the change and pass with it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Both encoder changes correctly preserve sign and magnitude, with focused regression coverage and no unresolved blocking issues.

No open issues 🎉

Review effort: Balanced

@kesmit13 kesmit13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to name the new test file test_parameters.py. That way if we need to add tests for other parameter types, the filename won't be so specific. Other than that, I can approve. It's still marked as a draft though. Not sure if there is a reason for that.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the signed-duration encoding change.

No open issues 🎉

Review effort: Balanced

@Kayvan-Zahiri

Copy link
Copy Markdown
Contributor Author

Renamed to test_parameters.py (329b748). No reason for the draft; it just wasn't flipped.

@kesmit13
kesmit13 force-pushed the codex/preserve-negative-timedelta-parameters branch from 329b748 to e32e0ef Compare November 2, 2026 20:17
@kesmit13
kesmit13 merged commit 07cd0d4 into singlestore-labs:main Nov 2, 2026
13 checks passed

This branch was successfully deployed

1 active deployment
Base — e32e0efa Deployed Nov 2, 2026 by kesmit13 via test-coverage #607
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants