Get-BulkRowsCopiedCount - Read the rows copied counter as Int64 - #10677
Open
andreasjordan wants to merge 1 commit into
Open
Get-BulkRowsCopiedCount - Read the rows copied counter as Int64#10677andreasjordan wants to merge 1 commit into
andreasjordan wants to merge 1 commit into
Conversation
The _rowsCopied field of SqlBulkCopy is an Int64 in current Microsoft.Data.SqlClient (the 4 byte counter of the legacy library, which Get-AdjustedTotalRowsCopied works around, was fixed upstream). The cast to [int] therefore throws above [int32]::MaxValue rows, the catch returned the -1 failure sentinel, and the callers fed that sentinel into the wrap adjustment as if it were a wrapped counter: a copy of 3 billion rows reported 4294967295 rows copied while the destination held the correct count. The callers now skip the final adjustment when the helper signals failure, so the running total from the notifications stands instead of a number that is off by billions. The wrap adjustment itself stays, it is still correct for genuinely wrapped values from an old library. Fixes #10675 (do Copy-DbaDbTableData, Import-DbaCsv, Import-DbaParquet, Get-BulkRowsCopiedCount) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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 #10675
Problem
The report: the verbose rows-copied total of
Copy-DbaDbTableDatacan over-report against the destination's real row count on the final batch, while the copied data itself is correct.What reproduced and what did not
On the current stack (dbatools.library with Microsoft.Data.SqlClient 6.1.5, SQL Server 2022 -> 2025) a multi-batch copy shows correct live counters and a correct final total, with the batch size aligned to the row count and not - the reported symptom does not reproduce below
[int32]::MaxValuerows. @niphlod is right that the wrapping 4-byte counter itself is history:SqlBulkCopy._rowsCopiedis an Int64 in current Microsoft.Data.SqlClient, so the counter never wraps any more.But the machinery the issue points at does over-report the final total, exactly once the copy exceeds
[int32]::MaxValuerows:Get-BulkRowsCopiedCountreads_rowsCopiedby reflection and casts it to[int]. Above 2,147,483,647 rows that cast throws.catchreturns -1, the helper's failure sentinel.Get-AdjustedTotalRowsCopied, whose integer-wrap branch takes a negative value for a wrapped counter and adds ~1.3 billion phantom rows.Demonstrated by setting the field via reflection: a 3,000,000,000-row copy reports 4,294,967,295 rows copied while the destination holds the correct 3,000,000,000. The data is right, the reported total is not - the shape the issue describes. Ironically the over-report comes from the workaround for the old 4-byte counter, on a library whose counter no longer wraps.
What changed
Get-BulkRowsCopiedCountreturns the counter as[long]([OutputType([long])]); the value passes through unharmed on both the Int64 field of current SqlClient and the Int32 field of the legacy library.Copy-DbaDbTableData,Import-DbaCsv,Import-DbaParquet- skip the final adjustment when the helper signals failure with -1, keeping the running total from the copy notifications instead of adding a bogus wrap correction.What deliberately did not change
Get-AdjustedTotalRowsCopiedkeeps its wrap logic untouched: it is still correct for genuinely wrapped (negative) values that an old library delivers through theSqlRowsCopiedevent.Write-DbaDbTableDatauses only the event-side adjustment and never callsGet-BulkRowsCopiedCount, so it has no sentinel path and stays as it is.Tests
New
tests/Get-BulkRowsCopiedCount.Tests.ps1(unit,InModuleScope, no instance needed): the helper returns the counter below and above[int32]::MaxValue, and the callers' final-adjustment pattern stays correct above it. Red ondevelopment(Expected 3000000000, but got -1.), green with the fix.Full runs of the four affected test files through the testing-dbatools harness (SQL 2022 -> SQL 2025), both editions: 79/79 green on pwsh and on 5.1.
Copying two billion real rows is not something CI or the lab can afford, which is why the regression test sets the counter field by reflection instead - the same access path the helper itself uses.
created by Claude and reviewed by Andreas Jordan
馃 Generated with Claude Code