Skip to content

Fix iter_rows_keyset infinite loop on NULL by column (#1)#2

Merged
varjoranta merged 1 commit into
mainfrom
fix/iter-keyset-null-by
May 13, 2026
Merged

Fix iter_rows_keyset infinite loop on NULL by column (#1)#2
varjoranta merged 1 commit into
mainfrom
fix/iter-keyset-null-by

Conversation

@varjoranta
Copy link
Copy Markdown
Owner

Summary

  • db.iter_rows_keyset looped forever when the by column had NULL at a full-page boundary, because WHERE by > NULL is always false and the next page refetched the same rows.
  • Raise ValueError before yielding the offending page, so callers don't get partial results from an invalid stream.
  • Guard only fires when the page is full (len(rows) == batch_size); a short final page ending in NULL is harmless because the cursor terminates anyway.

Fixes #1.

Test plan

  • One new integration test parametrized across SQLite + asyncpg + psycopg (3 NULL emails + 1 non-NULL + batch_size=2 reproduces on both NULL-orderings).
  • uv run pytest: 487 passed, 1 skipped (was 484/1).
  • uv run ruff check: clean.

Out of scope

Tied non-NULL by values silently drop rows from the same WHERE-cursor family. Different fix shape (compound (by, pk) cursor with dialect-specific NULL ordering); will track separately.

When the keyset cursor's `by` column was NULL at a full-page
boundary, `WHERE by > NULL` evaluated false, so the next page
re-fetched the same rows forever -- silent hang, no error.

Raise ValueError before yielding the offending page, so callers
don't get partial results from an invalid stream. Only triggers
when the page is full (a short final page ending in NULL is
harmless -- the cursor terminates anyway).

Fixes #1.
@varjoranta varjoranta force-pushed the fix/iter-keyset-null-by branch from 4cf158e to 0c3985b Compare May 13, 2026 07:32
@varjoranta varjoranta merged commit 2871a85 into main May 13, 2026
7 checks passed
@varjoranta varjoranta deleted the fix/iter-keyset-null-by branch May 13, 2026 07:38
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.

iter_rows_keyset infinite loop when by column contains NULL values

1 participant