Skip to content

Fix missing description for statements that do not start with SELECT - #33

Merged
CollierKing merged 1 commit into
CollierKing:mainfrom
danielalyoshin:fix/description-from-columns
Oct 2, 2026
Merged

CollierKing merged 1 commit into
CollierKing:mainfrom
danielalyoshin:fix/description-from-columns

Conversation

@danielalyoshin

@danielalyoshin danielalyoshin commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Problem

cursor.description is None for statements that return rows but do not start with SELECT, PRAGMA or WITH (#32): a leading comment, EXPLAIN QUERY PLAN, VALUES, a SELECT in brackets. SQLAlchemy then treats them as returning nothing and raises This result object does not return rows.

Fix

_build_description now uses the column names from D1 whenever there are any, and keeps the keyword test only as the fallback for replies with no columns. Statements D1 sends no columns for (INSERT, UPDATE, CREATE and so on) still get None.

The async adapter in dialect_async.py had its own copy of the keyword test, so it now follows the cursor's description instead.

Tests

  • Unit tests with fake /raw replies through httpx.MockTransport: a leading -- or /* */ comment, a bracketed SELECT, EXPLAIN QUERY PLAN and VALUES all get a description; an INSERT with no columns still gets None; a SELECT with no columns keeps []; a commented SELECT returns rows through both the sync and the async engine. The new tests fail without the fix. Unit suite: 54 passed on Python 3.11 and 3.9.
  • REST API integration against a real D1: new TestDescriptionWithoutSelectKeyword class. 6 of its 7 tests fail on main (the INSERT guard passes on both). With the fix, the REST API and base URL integration files pass: 93 passed.
  • ruff check, ruff format --diff, mypy src/, codespell and pre-commit run --all-files are clean.
  • Worker integration tests were not run here. The Worker path shares _build_description, so it gets the same change.

Left as is: in the Worker path, the raw() fallback for empty results still only runs for statements that start with SELECT, because it runs the statement a second time.

This PR and #34 touch different lines and merge cleanly together.

Fixes #32

cursor.description was only built when the SQL started with SELECT,
PRAGMA or WITH, or contained RETURNING. A leading comment, EXPLAIN and
VALUES all return rows, but came back with no description, so
SQLAlchemy treated them as returning nothing.

Use the column names D1 sends whenever there are any, and keep the
keyword test as the fallback for replies without them. The async
adapter now follows the cursor's description instead of its own copy
of the keyword test.

Fixes CollierKing#32
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.

cursor.description is None for statements that do not start with SELECT, PRAGMA or WITH

2 participants