Search code examples
sqlt-sqlsql-server-2012varbinary

Update varbinary(MAX) field in SQLServer 2012 Lost Last 4 bits


Recently I would like to do some data patching, and try to update a column of type varbinary(MAX), the update value is like this:

0xFFD8F...6DC0676

However, after update query run successfully, the value becomes:

0x0FFD8...6DC067

It seems the last 4 bits are lost, or whole value right shifting a byte...

I tried deleting entire row and run an Insert Query, same things happen!

Can anyone tell me why is this happening & how can I solve it? Thanks!

I have tried several varying length of binary, for maximum 43658 characters (Each represents 4 bits, total around 21 KB), the update query runs normally. 1 more character will make the above "bug" appears...

PS1: For a shorter length varbinary as update value, everything is okay

PS2: I can post whole binary string out if it helps, but it is really long and I am not sure if it's suitable to post here

EDITED: Thanks for any help!

As someone suggested, the value inserted maybe of odd number of 4-bits, so there is a 0 append in front of it. Here is my update information on the value:

The value is of 43677 characters long exluding "0x", which menas Yes, it is odd

It does explain why a '0' is inserted before, but does not explain why the last character disappears...

Then I do an experiment:

I insert a even length value, with me manually add a '0' before the original value,

Now the value to be updated is

0x0FFD8F...6DC0676

which is of 43678 characters long, excluding "0x"

The result is no luck, the updated value is still

0x0FFD8...6DC067


Solution

  • It seems that the binary constant 0xFFD8F...6DC0676 that you used for update contains odd number of hex digits. And the SqlServer added half-byte at the beginning of the pattern so that it represent whole number of bytes.

    You can see the same effect running the following simple query:

    select 0x1, 0x104
    

    This will return 0x01 and 0x0104.

    The truncation may be due to some limitaions in SSMS, that can be observed in the following experiment:

    declare @b varbinary(max)
    set @b = 0x123456789ABCDEF0
    set @b = convert(varbinary(max), replicate(@b, 65536/datalength(@b)))
    select datalength(@b) DataLength, @b Data
    

    The results returned are 65536 and 0x123456789ABCDEF0...EF0123456789ABCD, however if in SSMS I copy Data column I'm getting pattern of 43677 characters length (this is without leading 0x), which is 21838.5 bytes effectively. So it seems you should not (if you do) rely on long binary data values obtained via copy/paste in SSMS.

    The reliable alternative can be using intermediate variable:

    declare @data varbinary(max)
    select @data = DataXXX from Table_XXX where ID = XXX
    update Table_YYY set DataYYY = @data where ID = YYY