TSQLQuery截断数据

时间:2016-06-08 00:06:32

标签: sql-server database delphi sql-server-2008-r2 communication

我在2012年提出了这个问题:TSQLQuery only streams first 1MB of data correctly for large strings

我想让问题保持简单,所以不要将更多细节附加到另一个问题,希望人们再次看一下,这是一个只有核心细节的新问题。

问题摘要

  

TSQLConnection...MaxBobSize有两种设置。使用-1丢失数据(一个错误),并使用X MB内存不足:

     
      
  1. TSQLConnection.Params.Values['MaxBlobSize'] := '-1',使TSQLQuery查看db中每个var...(max)字段的数据长度,并分配与每个字段的数据长度匹配的缓冲区。正确设置每个缓冲区中的前1,048,576个字节,然后将剩余字节设置为NULL(0x00)。因此,数据丢失

  2.   
  3. TSQLConnection.Params.Values[MaxBlobSize] := 'X MB'使TSQLQuery为查询中返回的每个X MB字段预分配指定的var...(max) RAM。 X MB必须足够大才能容纳最大的var...(max)对象。即使在10MB,具有3个var...(max)字段和100行的查询也会预先分配3GB RAM来为查询提供服务,即使实际数据要小得多。如果机器用完RAM,用户会看到“灾难性故障”

  4.   

详情

2012年,我们与Embarcadero开了一个事件来修复第1号漏洞。他们说使用X MB而不是-1,这会导致我们的用户体验条件#2。我们继续使用MaxBlobSize := -1希望Embarcadero能够解决问题#1,或者我们的用户永远不会超过1MB的限制。

用户将10MB图像上传到数据库,并且很可能再次发生。当他们检索10MB图像时,前1MB显示正确,图像的其余部分丢失。完整的10MB图像正确存储在数据库中。所以用户已经遇到了错误#1。

这个问题在Delphi Seattle(XE10)中仍然存在,正如这个简单的测试案例所证明的那样。我使用WireShark验证了来自db的流量包括所有字段数据。

  1. 创建一个新的Delphi VCL Forms项目。
  2. SQLConnection1: TSQLConnection添加到表单,设置以访问数据库:

    • 驱动器= MSSQL
    • 主机名=本地主机
    • OSAuthentication =真
    • 数据库tempdb的=
    • LoginPrompt =假
  3. SQLConnection1.Params['MaxBlobSize']设置为-1

  4. 使用以下Button1: TButton代码添加OnClick()
  5. procedure TForm1.Button1Click(Sender: TObject);
    var
      qry: TSQLQuery;
    
      procedure save(fn: string);
      var
        data: TBytes;
        fs: TFileStream;
      begin
        fs := TFileStream.Create('c:\' + fn + '.txt', fmCreate);
        try
          data := qry.FieldByName(fn).AsBytes;
          if data <> nil then
            fs.WriteBuffer(data[0], Length(data));
        finally
          FreeAndNil(fs);
        end;
      end;
    
    begin
      SQLConnection1.Open;
      qry := TSQLQuery.Create(nil);
      try
        qry.MaxBlobSize := -1;
        qry.SQLConnection := SQLConnection1;
        qry.SQL.Text := Concat(
          'declare @s1 varchar(max), @s2 varchar(max) ',
    
          'set @s1 = ''0123456789ABCDEF'' ',
          'set @s2 = @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1  /* 128 bytes       */ ',
          'set @s1 = @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2  /* 1,024 bytes     */ ',
          'set @s2 = @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1  /* 8,192 bytes     */ ',
          'set @s1 = @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2 + @s2  /* 65,536 bytes    */ ',
          'set @s2 = @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1 + @s1  /* 524,288 bytes   */ ',
          'set @s1 = @s2 + @s2                                      /* 1,048,576 bytes */ ',
    
          'set @s2 = @s1 + ''this is a test''                       /* 1MB + 14 bytes  */ ',
          'set @s1 = @s1 + ''of the emergency broadcasting system'' /* 1MB + 36 bytes  */ ',
    
          'select @s2 as Plus14, @s1 as Plus36'
        );
        qry.Open;
        save('Plus14');
        save('Plus36');
      finally
        FreeAndNil(qry);
      end;
      SQLConnection1.Close;
    
    end;
    
    1. 运行应用程序并单击按钮。
    2. 在十六进制编辑器中打开每个文件,并在每个文件的末尾查找NULL(0x00)。
    3. 问题

      由于用户在使用MaxBobSize := X MB时看到内存不足问题,我们需要保留MaxBobSize := -1。是否有任何建议或解决方案可以将MaxBlobSize设置为-1,继续使用TSQLConnectionTSQLQuery,然后访问所有字段数据,即使字段超出1MB?

      如果无法使用上述组件,使用本机组件的另一种解决方案可能没问题。

0 个答案:

没有答案