TSQLQuery правильно передает только первые 1 МБ данных для больших строк
(см. Редактирование # 1 с трассировкой стека и Редактирование # 2 с обходным решением в конце публикации)
При устранении неполадокTSQLQuery.FieldByName (). AsString - & gt; TStringStream портит данныеЯ обнаружил, чтоTSQLQuery.FieldByName().AsBytes
будет транслироваться только 1 МБvarchar(max)
данные правильно.
TSQLQuery.FieldByName().AsString
and .AsWideString
also exhibit the same behavior.
Что вызвало бы.AsBytes
предоставить правильное количество байтов дляTFileStream
, ноnull
все байты, которые превышают 1 МБ?
Этот тестовый пример создает два выходных файла.Plus14.txt
1 МБ + 14 байт.Plus36.txt
1 МБ + 36 байт. В обоих случаях байты размером более 1 МБnull
байтовые значения. Я даже попробовал строку 16 МБ. Первые 1 МБ выходного файла были правильными; следующие 15 МБ были всеnull
байт.
use tempdb
go
create procedure RunMe
as
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
go
grant execute on RunMe to public
go
Delphi DFM
Форма по умолчанию, с этимTSQLConnection
упал на него (и одинTButton
):
object SQLConnection1: TSQLConnection
DriverName = 'MSSQL'
GetDriverFunc = 'getSQLDriverMSSQL'
LibraryName = 'dbxmss.dll'
LoginPrompt = False
Params.Strings = (
'User_Name=user'
'Password=password'
'SchemaOverride=%.dbo'
'DriverUnit=Data.DBXMSSQL'
'DriverPackageLoader=TDBXDynalinkDriverLoader,DBXCommonDriver160.' +
'bpl'
'DriverAssemblyLoader=Borland.Data.TDBXDynalinkDriverLoader,Borla' +
'nd.Data.DbxCommonDriver,Version=16.0.0.0,Culture=neutral,PublicK' +
'eyToken=91d62ebb5b0d1b1b'
'MetaDataPackageLoader=TDBXMsSqlMetaDataCommandFactory,DbxMSSQLDr' +
'iver160.bpl'
'MetaDataAssemblyLoader=Borland.Data.TDBXMsSqlMetaDataCommandFact' +
'ory,Borland.Data.DbxMSSQLDriver,Version=16.0.0.0,Culture=neutral' +
',PublicKeyToken=91d62ebb5b0d1b1b'
'GetDriverFunc=getSQLDriverMSSQL'
'LibraryName=dbxmss.dll'
'VendorLib=sqlncli10.dll'
'VendorLibWin64=sqlncli10.dll'
'HostName=localhost'
'Database=tempdb'
'MaxBlobSize=-1'
'LocaleCode=0000'
'IsolationLevel=ReadCommitted'
'OSAuthentication=False'
'PrepareSQL=True'
'BlobSize=-1'
'ErrorResourceFile='
'OS Authentication=True'
'Prepare SQL=False')
VendorLib = 'sqlncli10.dll'
Left = 8
Top = 8
end
Delphi PAS
Код дляTButton.OnClick
:
procedure TForm1.Button1Click(Sender: TObject);
var qry: TSQLQuery;
procedure save(str: string);
var data: TBytes; fs: TFileStream;
begin
fs := TFileStream.Create(Format('c:\%s.txt', [str]), fmCreate);
try
data := qry.FieldByName(str).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 := 'set nocount on; exec RunMe';
qry.Open;
save('Plus14');
save('Plus36');
finally
FreeAndNil(qry);
end;
SQLConnection1.Close;
end;
<<< Edit #1 - Stack Trace >>>
Я проследил код Embarcadero и нашел место, гдеnull
байты сначала появляются.
FMethodTable.FDBXRow_GetBytes
Data.DBXDynalink.TDBXDynalinkByteReader.GetBytes(0,0,(...),0,1048590,True)
Data.SqlExpr.TCustomSQLDataSet.GetFieldData(1,$7EC80018)
Data.SqlExpr.TCustomSQLDataSet.GetFieldData(???,$7EC80018)
Data.DB.TDataSet.GetFieldData($66DB18,$7EC80018,True)
Data.SqlExpr.TSQLBlobStream.ReadBlobData
Data.SqlExpr.TSQLBlobStream.Read((no value),1048590)
System.Classes.TStream.ReadBuffer((no value),1048590)
1MB + 14b
Data.DB.TBlobField.GetAsBytes
Unit1.save('Plus14')
когдаFDBXRow_GetBytes
возвращается,Value: TBytes
составляет 1048590 байт, сnull
значения, установленные для последних 14 байтов.
Я не уверен, что попробовать дальше. Любая помощь очень ценится.
<<< Edit #2 - Workaround >>>Я поставилSQLConnection1.MaxBlobSize := 2097152
и теперь все байты правильно передаются в выходные файлы. Таким образом, проблема возникает только тогда, когда.MaxBlobSize = -1
.
Срочность решения проблемы ушла, когда я нашел обходной путь. Тем не менее, я все еще хотел бы получить-1
работать, если это возможно, так как значения из моей базы данных иногда превышают 50 мегабайт. Поэтому любые предложения или помощь по-прежнему приветствуются.
Я отправил сообщение об ошибке в Embarcadero (QC # 108475). Я сообщу, как только ошибка будет подтверждена / исправлена.
<<< Edit #4 - Escalated Bug Report >>>Сегодня я обнаружил, что использование этого обходного пути иногда вызываетTClientDataSet
броситьEOleException
с текстом & apos;Catastrophic Failure& APOS ;. ВидимоTClientDataSet
предпочитаетMaxBlobSize := '-1';
, Следовательно, я расширил отчет об ошибках на Embarcadero. Надеемся, что они предоставят исправление или лучший обходной путь для этого в ближайшее время.