Repository navigation
Preserve exact BIGINT values in pagination cursors - #3863
Joel Town Road (hippi345) wants to merge 2 commits into
Conversation
TryResolveJsonElementToScalarVariable stored every JSON number as a double, so 19-digit primary keys lost precision and the next-page $after token failed ParseParamAsSystemType with HTTP 400.
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
🟡 Changes recommended
The decimal fallback can round tiny nonzero fractions to zero, corrupting pagination boundaries.
1 open issue
What changed in this PR
Addresses #3856 by preserving exact BIGINT values in DAB pagination cursors.
Changes:
- Resolves JSON numbers as Int64 first, then integral decimal, before falling back to double.
- Adds regression tests for large integer cursors and ordinary numeric values.
| File | Description |
|---|---|
| src/Service.Tests/UnitTests/SqlPaginationUtilUnitTests.cs | Tests numeric precision and cursor-value parsing. |
| src/Core/Resolvers/SqlPaginationUtil.cs | Prioritizes exact integer types during scalar conversion. |
Review effort: Balanced
| else if (element.TryGetDecimal(out decimal decimalValue) && | ||
| decimalValue == decimal.Truncate(decimalValue)) |
There was a problem hiding this comment.
The Int64-first approach looks right for fixing #3856. Before merging, could we address the decimal fallback identified above? TryGetDecimal can successfully round 1e-30 to zero, which then passes the integrality check. Since this helper also processes ORDER BY values, that changes the pagination boundary and can cause repeated or skipped rows.
For this BIGINT-focused fix, could we keep TryGetInt64 followed by the existing double fallback, without the intermediate decimal conversion? Please also add regression cases for positive/negative tiny fractions and long.MinValue/long.MaxValue to confirm we preserve floating-point behavior while fixing BIGINT cursors.

Why make this change?
$aftertoken becomes scientific notation (for example5.123692796229828E+18) andParseParamAsSystemTypereturns 400 instead of the next page.What is this change?
SqlPaginationUtil.TryResolveJsonElementToScalarVariable(used byMakeCursorFromJsonElement) now resolves JSON numbers asInt64first, then as an integraldecimalwhen the value is outsideInt64, and only then asdouble.BaseSqlQueryStructure.ParseParamAsSystemTypecan parse them asInt64.int/doubleunchanged.How was this tested?
Before (unmodified
TryResolveJsonElementToScalarVariable, new tests only):After the fix:
dotnet format src/Azure.DataApiBuilder.sln --verify-no-changescompleted with no formatting changes.Sample Request(s)
nextLink(or pass$afterfrom that response). The cursorFieldValuestays5123692796229827916and page 2 returns 200 with the next rows instead of 400.first/afteron the same BIGINT key. MCPread_recordsusing thataftercursor follows the same path.This change was prepared with AI assistance and reviewed by the author.