test(query): executing with an empty bound batch keeps the result schema - #7
Open
fornwall wants to merge 1 commit into
Open
test(query): executing with an empty bound batch keeps the result schema#7fornwall wants to merge 1 commit into
fornwall wants to merge 1 commit into
Conversation
Implements the 'empty stream/empty batch' TODO in TestQuery.test_query as a self-contained statement-level test, gated on statement_bind: test_parameter_execute_empty_bind executes a parameterized SELECT with a zero-row bound batch (the DBAPI executemany empty-parameter-set shape) and asserts the returned stream has zero rows but still carries the query's real result schema, matching a non-empty execution of the same query. The result schema is a property of the query, not of the number of bound rows; the ADBC spec does not spell the zero-row case out explicitly, so this asserts the self-consistency invariant. Signed-off-by: Fredrik Fornwall <fredrik@fornwall.net>
fornwall
force-pushed
the
test/bind-empty-batch-schema
branch
from
July 15, 2026 08:03
346e3c9 to
b458a6a
Compare
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.
Fixes:
Split out of #4 (one PR per test). Adds one generic, driver-agnostic test for a gap found while reviewing an ADBC driver (the adbc-spanner Rust driver) against this suite; candidate for upstreaming to adbc-drivers/validation later.
TestStatement.test_parameter_execute_empty_bind(gated onstatement_bind)Implements the long-standing
# TODO: also test with empty stream/empty batchinTestQuery.test_query(comment adjusted there): executes a parameterizedSELECTwith a zero-row bound batch and asserts the returned stream has zero rows but still carries the query's real result schema, identical to a non-empty execution of the same query.AdbcStatementBindsays only that bind is for "bulk inserts or prepared statements"). This test asserts a self-consistency invariant, stated here explicitly rather than cited: the result schema is a property of the query, not of the number of bound rows, so an emptyexecutemanyparameter set must not change the schema a client sees.Results on real drivers
empty bind returned schema <empty>, but a non-empty execution returns : int64).ExecuteQuerywith the zero-row bound batch returns a stream whose import crashes the process (Fatal Python error: Segmentation faultinsidepyarrowImportRecordBatchReader→ImportSchema). This is the released manifestation of the C driver-framework zero-row-bind bug just fixed in test(c/validation): add coverage for option, GetInfo and bind gaps found reviewing adbc-spanner arrow-adbc#21; the released 1.11.0 wheel predates that fix, so the test should start passing once a release containing it ships. The crash (rather than a clean wrong-schema failure) is stronger evidence that this case needs coverage.Why this test binds an Arrow batch rather than using
executemanyThe zero-row bind has to reach the driver for this test to mean anything, and the
DBAPI layer deliberately prevents that for the most obvious spelling of it.
Cursor.executemanyshort-circuits an empty parameter set entirely(
dbapi.py#L981-L995, per apache/arrow-adbc#3319):So
executemany(query, [])never binds and never executes -- noAdbcStatementBind,no
AdbcStatementExecuteQuery, nothing for a driver to get wrong. That path is safeby construction and is not what this test covers.
Two things put the test on the driver-reaching path instead:
returnabove only fires for the latter. Arrow data takes the earlier
_is_arrow_databranch and is bound unconditionally, with norow-count check -- the comment above notes why: for C Data objects the length
can't be inspected without consuming the stream.
execute_query, which produces a result set.executemanycan affordto do nothing because it "does not generate a result set"
(
dbapi.py#L934); there is no schema to answer for. A query muststill produce one, and
ArrowArrayStream::get_schemais mandatory and invariant --which is exactly what the sqlite 1.11.0 segfault is: the driver had no schema to
give and emitted a malformed one rather than failing cleanly.
The test therefore drives
set_sql_query/prepare/bind/execute_queryoncursor.adbc_statementdirectly. Those are 1:1 with the C entry points, so despitebeing written in Python this exercises the same call sequence a C or Go client would.
Framework checks
uv run pytest tests/(210 passed, 1 skipped),uv run ty check(clean),pre-commit run --all-files(all hooks pass) — all on this branch independently.🤖 Generated with Claude Code
https://claude.ai/code/session_01LGf8PVEe2tYkw8Q6Pd95tq