如果 blob 包含特定数据,则更新 blob 时出现问题

发布于 2024-08-02 05:24:46 字数 1930 浏览 3 评论 0原文

我有需要存储在 SQL 数据库的 BLOB 字段中的二进制数据。 在更新(存储到数据库中)的情况下,二进制数据以字符串形式出现(BDS2006,无 unicode)。 当 BLOB 字段为 READ 时,需要将二进制数据作为字符串返回。 因此,我使用了这两段代码(qry 是一个 TQuery):

阅读:

var s: string;
begin
  qry.SQL.Text := 'SELECT BlobField FROM Table WHERE ID=xxx';
  qry.Open;
  if qry.RecordCount > 0 then
    begin
      qry.First;
      s := qry.FieldByName('BlobField').AsString;
    end;
end;

更新:

var s: string;
begin
  s := ...binary data...
  qry.SQL.Text := 'UPDATE Table Set BlobField=:blobparam WHERE ID=xxx';
  qry.ParamByName('blobparam').AsBlob = s;
  qry.ExecSQL;
end;

我不确定这是否是正确/良好/好的方法,但它已经工作了好几年了。

现在,一组特定的二进制数据存在问题,这些数据在更新到数据库中然后从数据库中读取后被更改/损坏。 当比较 ExecSQL 之前的 param 值与读取后 s 的值时,数据的最后一个字节(在本例中总共 1519 字节)从 02h 更改为 00h。

由于我不确定我的代码是否正常工作,因此我尝试使用 TBlobStream 来检查结果是否发生变化。

读取:

var s: string;
    bs: TStream;
    st: TStringStream;
begin
  qry.SQL.Text := 'SELECT BlobField FROM Table WHERE ID=xxx';
  qry.Open;
  if qry.RecordCount > 0 then
    begin
      qry.First;
      st := TStringStream.Create('');
      bs := qry.CreateBlobStream(qry.FieldByName('BlobField'), bmRead);
      bs.Position := 0;
      st.CopyFrom(bs, bs.Size);
      st.Position := 0;
      s := st.ReadString(st.Size);
    end;
end;

更新:

var s: string;
    bs: TStream;
    st: TStringStream;
begin
  s := ...binary data...
  st := TStringStream.Create(s);
  st.Position := 0;
  qry.SQL.Text := 'UPDATE Table Set BlobField=:blobparam WHERE ID=xxx';
  qry.ParamByName('blobparam').LoadFromStream(st, ftBlob);
  qry.ExecSQL;
end;

结果相同,读取数据的最后一个字节已损坏。

我的问题可能是什么?


编辑:

仅使用流会产生相同的问题。

我发现只有当数据正好是 1519 字节时才会发生这种情况。然后,只有到那时,最后一个字节才会被设置为 0,无论它之前是什么。当然,该问题可能还有其他情况,但这是我每次都可以重现的情况。

如果我在末尾再添加一个字节,使其成为 1520 字节,则一切正常。 我只是没有看到任何特殊的东西可能会导致它。

I have binary data that needs to be stored in a BLOB field in a SQL-database.
In case of an UPDATE (storing into the database), the binary data comes as a string (BDS2006, no unicode).
When the BLOB field is READ, the binary data needs to be returned as a string.
Therefore, I have used these two pieces of code (qry is a TQuery):

READ:

var s: string;
begin
  qry.SQL.Text := 'SELECT BlobField FROM Table WHERE ID=xxx';
  qry.Open;
  if qry.RecordCount > 0 then
    begin
      qry.First;
      s := qry.FieldByName('BlobField').AsString;
    end;
end;

UPDATE:

var s: string;
begin
  s := ...binary data...
  qry.SQL.Text := 'UPDATE Table Set BlobField=:blobparam WHERE ID=xxx';
  qry.ParamByName('blobparam').AsBlob = s;
  qry.ExecSQL;
end;

I'm not sure if that's the right/good/ok way to do it, but it has worked fine for a couple of years.

Now there is a problem with a specific set of binary data, which after being UPDATE'd into the database and then READ from the database is changed/corrupted.
When comparing the param value before ExecSQL with the value of s after reading, the last byte of data (in this case 1519 bytes total), is changed from 02h to 00h.

Since I am not sure if my code works correctly, I have tried to use TBlobStream, to check if the results change.

READ:

var s: string;
    bs: TStream;
    st: TStringStream;
begin
  qry.SQL.Text := 'SELECT BlobField FROM Table WHERE ID=xxx';
  qry.Open;
  if qry.RecordCount > 0 then
    begin
      qry.First;
      st := TStringStream.Create('');
      bs := qry.CreateBlobStream(qry.FieldByName('BlobField'), bmRead);
      bs.Position := 0;
      st.CopyFrom(bs, bs.Size);
      st.Position := 0;
      s := st.ReadString(st.Size);
    end;
end;

UPDATE:

var s: string;
    bs: TStream;
    st: TStringStream;
begin
  s := ...binary data...
  st := TStringStream.Create(s);
  st.Position := 0;
  qry.SQL.Text := 'UPDATE Table Set BlobField=:blobparam WHERE ID=xxx';
  qry.ParamByName('blobparam').LoadFromStream(st, ftBlob);
  qry.ExecSQL;
end;

The result is the same, the last byte of the read data is corrupted.

What could be my problem?


EDIT:

Using only streams produces the same problem.

I found that this only happens if the data is exactly 1519 bytes. Then, and only then, the last byte is set to 0, no matter what it was before. Of course there might be other cases for the problem, but that's one that I can reproduce every time.

If I add one more byte to the end, making it 1520 bytes, everything works fine.
I just don't see anything special here that could cause it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

硬不硬你别怂 2024-08-09 05:24:46

我同意 Gerry 的观点,即尾随 NULL 看起来像是一个字符串问题。

您修改后的代码仍然使用 TStringStream 写入数据。您是否尝试过使用 TBlobStream 写入数据,并看看这是否有所不同?

或者,在问题数据末尾添加一些打包字节,以检查它是否与特定大小/边界问题相关。或者尝试用固定的测试模式替换问题数据,以缩小问题范围。

FWIW 我很长一段时间都没有问题地使用 blob,但从未将它们视为字符串。

祝你好运,缩小问题范围。

更新:在我看来,您的代码很好,但是您在数据库/数据访问软件的某个地方遇到了其他人的错误。您使用什么数据库/驱动程序/访问代码?

I agree with Gerry that the trailing NULL looks like a string problem.

Your modified code still writes the data using TStringStream. Have you tried writing the data using a TBlobStream, and seeing if that makes a difference?

Alternatively, add some packing bytes at the end of the problem data, to check if it is related to a specific size/boundary issue. Or try replacing the problem data with a fixed test pattern, to narrow the problem down.

FWIW I have used blobs without problem for a long time, but have never treated them as strings.

Good luck narrowing the issue down.

UPDATE: looks to me like your code is fine, but you are running into somebody else's bug somewhere in the database/data access software. What database/driver/access code are you using?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文