Azure / Azure/azure-sdk-for-rust
Native buffered queries truncate after one page
- Dominant language
- Rust
- Stars
- 884
- Forks
- 365
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 109
Description
## Summary
The native C wrapper can return a successful first page for a buffered cross-partition query, omit the continuation token, and discard the remaining query state. Native consumers can therefore observe incomplete results without an error.
Discovered while reviewing #5122. This is a pre-existing native pagination limitation; the native fix is being removed from that change and tracked separately here.
## Affected code
`CosmosDriver` itself can keep an `OperationPlan` alive and advance it across pages. However, `sdk/cosmos/azure_data_cosmos_driver_native/src/submit.rs`, in `submit_operation_with_builder` (used by `cosmos_submit_operation`), executes only one page and derives the next token using:
```rust
plan.to_continuation_token()
.ok()
.map(|t| t.as_str().to_owned())
```
The plan is then dropped when the one-shot future completes.
Source baseline examined: `075917d6cb987055dfa93e31296b261574456b66`.
## Reproduction
1. Use a supported cross-partition non-streaming ORDER BY query with a finite output window, or an unordered DISTINCT query that returns multiple unique results. If testing after the admission gate in #5122, use a finite TOP/LIMIT so admission is not the failure under investigation.
2. Seed more results than fit into one page, including results across physical partition ranges.
3. Submit the query through the native `cosmos_submit_operation` path with `max_item_count = 1` (also reproduced with 2).
4. Consume the first completion and inspect the returned continuation.
This was reproduced using a populated deterministic Gateway-plan/transport fixture and an actual linked C consumer. With the original snapshot-error suppression restored, all four non-streaming/DISTINCT cases at page sizes 1 and 2 returned successful HTTP 200 completions, a NULL next token, and only the first page despite additional results. This reproduction does not depend on live no-TOP vector-query support.
## Actual behavior
- Non-streaming ORDER BY snapshotting returns `400/20125` (`CLIENT_NON_STREAMING_ORDER_BY_CONTINUATION_UNSUPPORTED`).
- Unordered DISTINCT snapshotting returns `400/20124` (`CLIENT_DISTINCT_CONTINUATION_UNSUPPORTED`).
- `.ok()` suppresses that error.
- The completion reports success with no next continuation.
- The remaining sorting/deduplication state is dropped with the plan. Submitting again without a token restarts the query; it does not retrieve the remaining page.
## Expected behavior
Native callers must be able to retrieve every admitted result through an in-process paging lifecycle, or receive an explicit error when the chosen API cannot represent progress. A missing serialized token must not silently imply EOF when buffered results remain.
## Suggested direction and acceptance criteria
- Add an ABI-compatible native retained-plan/pager interface, or another explicitly stateful paging mechanism. Preserve existing record layouts, entry-point signatures, and ownership contracts.
- Retain the admitted `OperationPlan` across page advancement without introducing serialized continuations for unordered DISTINCT or non-streaming ORDER BY.
- Ensure legacy one-shot submission does not silently discard pending results when snapshotting is unsupported.
- Define terminal/EOF, cancellation, concurrent advancement, queue rejection, and free/lifetime behavior explicitly.
- Ensure native consumers can access every result buffer and distinguish raw feed envelopes from pre-split item payloads without guessing from JSON shape.
- Add populated linked C regression cases with more results than the page size, multiple ranges/pages, page sizes 1 and 2, exact complete output, and explicit terminal behavior. Include text/binary payloads, envelope-shaped application objects, and payload lifetime after pager release.
- Preserve existing driver continuation restrictions and singleton behavior.
## Scope
This issue tracks the native pagination/response-access bug independently from the Rust SDK/driver admission policy in #5122. Live vector-service acceptance is a separate validation concern.
Contributor guide
Research direction
Start in sdk/cosmos/azure_data_cosmos_driver_native/src/submit.rs at submit_operation_with_builder, then trace OperationPlan lifetime and continuation handling through cosmos_submit_operation. Reproduce with the populated linked C consumer using max_item_count 1 and 2. Done means native callers can page through every result or receive an explicit error, with regression coverage for terminal behavior, payload access, and lifetime.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, rust
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100