Azure / Azure/azure-sdk-for-rust

Native buffered queries truncate after one page

Open
#5,281 0 comments 1 reaction 0 assignees View on GitHub
Client Cosmos
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.