Skip to content

fix(query): record real row count in registry for Arrow path (#333)#376

Merged
xe-nvdk merged 2 commits intomainfrom
fix/query-registry-arrow-row-count
Apr 9, 2026
Merged

fix(query): record real row count in registry for Arrow path (#333)#376
xe-nvdk merged 2 commits intomainfrom
fix/query-registry-arrow-row-count

Conversation

@xe-nvdk
Copy link
Copy Markdown
Member

@xe-nvdk xe-nvdk commented Apr 9, 2026

Summary

  • Complete(queryID, 0) was called synchronously right after arrowJSONQueryFunc returned, but the Arrow path streams via SetBodyStreamWriter — the real row count is only available inside the async callback. The query registry always recorded 0 for Arrow-path queries.
  • Added onComplete func(int) parameter to executeArrowJSONQuery and the arrowJSONQueryFunc type. The callback now calls onComplete(rc) after streamArrowJSON completes, delivering the real count to the registry.

Test plan

  • GOFLAGS="-tags=duckdb_arrow" go build ./internal/... passes
  • go test ./internal/api/... -tags=duckdb_arrow passes
  • Manual: run a query via the Arrow endpoint, check /api/v1/queries/{id}row_count should match actual rows returned, not 0

Closes #333

xe-nvdk added 2 commits April 8, 2026 19:19
Complete(queryID, 0) was called synchronously after arrowJSONQueryFunc
returned, but the Arrow path streams via SetBodyStreamWriter — the
actual row count from streamArrowJSON is only available inside the
async callback. This caused the query registry to always record 0 rows
for Arrow-path queries.

Fix: add onComplete func(int) to executeArrowJSONQuery and the
arrowJSONQueryFunc type. Call site 1 passes a closure that calls
h.queryRegistry.Complete(queryID, rc) with the real count; call site 2
(measurement handler, no registry) passes nil. The callback invokes
onComplete(rc) after streamArrowJSON returns.
The previous fix only covered the success path. The post-implementation
review found that error and timeout branches in executeArrowJSONQuery
returned handled=true without notifying the registry, leaving queries
stuck in "running" state permanently.

Changes:
- Add onFail func(string) and onTimeout func() alongside onComplete
- "no files found" path calls onComplete(0) — it is a success with 0 rows
- Timeout path calls onTimeout()
- Query error path calls onFail(err.Error())
- Update arrowJSONQueryFunc type and both call sites accordingly
- Update RELEASE_NOTES_2026.05.1.md
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the Arrow-native query path to accurately report row counts by introducing an onComplete callback. This allows the query registry to be updated with the actual row count from the asynchronous stream writer instead of a placeholder value. A review comment identifies a potential nil pointer dereference in the onComplete closure due to its asynchronous execution and suggests capturing the registry in a local variable to ensure thread safety.

Comment thread internal/api/query.go
Comment on lines +1284 to +1285
var onTimeout func()
if h.queryRegistry != nil && queryID != "" {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The onComplete closure captures h.queryRegistry directly. Since this closure is executed asynchronously by SetBodyStreamWriter, there's a potential for h.queryRegistry to become nil between the time the closure is defined and when it's executed, leading to a nil pointer dereference. It's safer to capture the queryRegistry value into a local variable and perform a nil check inside the closure.

Suggested change
var onTimeout func()
if h.queryRegistry != nil && queryID != "" {
registry := h.queryRegistry
id := queryID
onComplete = func(rc int) {
if registry != nil {
registry.Complete(id, rc)
}
}

@xe-nvdk xe-nvdk merged commit 70429b6 into main Apr 9, 2026
6 checks passed
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.

medium(query): Query registry gets 0 row count for Arrow path

1 participant