![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как правильно записать Blob в TStream в UDF ?
Vorobyev Sergey © (2003-08-22 14:11:00)
У меня есть следующий код (немного переделанный, в исходном варианте результат записывался не в TStream, а в PChar)
procedure BlobAsStream(Blob:TBlob; Stream:TMemoryStream);
var bytes_left, total_bytes_read, bytes_read:integer;
st:string;
begin
if (not Assigned(Blob.Handle)) then exit;
with Blob do
begin
bytes_left := TotalLength; // I have TotalSize bytes to read.
if (bytes_left = 0) then exit; // if I"ve nothing to copy, exit.
SetString(st, nil, TotalLength);
total_bytes_read := 0; // total bytes read is 0.
repeat
// Using BlobHandle, store at most "bytes_left" bytes in
// the buffer starting where I last left off
GetSegment(Handle, @st[total_bytes_read + 1], bytes_left, bytes_read);
// Increment total_bytes_read by the number of bytes actually read.
Inc(total_bytes_read, bytes_read);
// Decrement bytes_left by the number of bytes actually read.
Dec(bytes_left, bytes_read);
until bytes_left <= 0;
end;
Stream.Write(st[1], Blob.TotalLength);
end;
В результате получается такая БЯКА..
В строковой переменнойstесть все данные до размера 16384, а дальше все нули.. Т.е. как будто бы все далее обрезается.. Почему?
Подскажите, пожалуйста..
Проверял под IB6, Yaffil.
Verg (2003-08-23 19:24:00) [1]
Ну я и баклан!!! :)))
> function(BlobHandle: PInt;
> Buffer: PChar;
> BufferSize: ushort;
> var ResultLength: ushort):
> Short; cdecl;
Вот же оно где!
Vorobyev Sergey
> bytes_read, bytes_left, total_bytes_read: Long;
НЕТ!
НАДО:
> bytes_read : ushort;
> bytes_left, total_bytes_read: Long;
Digitman
> var
> BytesRead: Integer;
НЕТ!
НАДО:
> var
> BytesRead: word;
Не, ну ржал минут 15-ать :)))
Старею, блин...
Verg (2003-08-23 17:03:00) [2]
Вот еще что из памяти всплыло - достаточно чтобы старшее слово (старшие 16 бит) в bytes_read на входе GetSegment было равно 0...
Теперь дальше....
Когда-то GetSegment описывался так:
function(BlobHandle: PInt;
Buffer: PChar;
BufferSize: ushort;
var ResultLength: ushort): Short; cdecl;
а теперь
так
GetSegment : function(Handle : Pointer; Buffer : PChar;
MaxLength : Long; var ReadLength : Long) : WordBool; cdecl;
... и к чему это ???
Verg (2003-08-23 16:40:00) [3]
> Min(bytes_left,MaxSegLength)..
Ну это-то понятно, ведь функция называется Get Segment.
А вот bytes_read := 0 - это "просто надо" :))
Давно было не помню, хотя разбирался когда-то....
> это шаман-чукча с бубном писал !)
:))))
Vorobyev Sergey (2003-08-23 16:34:00) [4]
> Verg © (23.08.03 16:20) [18]
Заработало!!!!!! Verg, спасибо!!
Теперь буду разбираться, что же я делал раньше не так..
И почему же все-таки нужноbytes_read := 0иMin(bytes_left,MaxSegLength)..
Пригодится в будущем..
Verg (2003-08-23 16:27:00) [5]
Кстати, без MIN на fb1.5 RC5 - вешается клиент, а сервер - 99% CPU Usage.
Без bytes_read:=0 - GetSegment читает из блоба кусок непредсказуемой длины.
Verg (2003-08-23 16:20:00) [6]
.....
bytes_read:=0;// Using BlobHandle, store at most "bytes_left" bytes in
// the buffer starting where I last left off
GetSegment(BlobHandle, @st[total_bytes_read + 1], Min(bytes_left,MaxSegLength),
bytes_read);
....
Мли-ин, ну сделай так уже..! Ну работает! А как у тебя - НЕ работает!
Ведь заставил же... проверить...
Кстати, покажи описание TBlob.
Vorobyev Sergey (2003-08-23 13:08:00) [7]
Ну хорошо... забудем про Stream-ы...
попробуйте в точности так, у меня (описано ниже)..
Если у вас пойдет, то я сдаюсь... :-(
1. Запишите в блоб текст, размером > 16384
2. в UDF опишите следующую функцию (без всяких TStream-ов):
...
function BlobAsPChar(Blob: PBlob): PChar; cdecl; export;
var
bytes_read, bytes_left, total_bytes_read: Long;
st: String;
begin
result := nil;
if (not Assigned(Blob)) or
(not Assigned(Blob^.BlobHandle)) then exit;
with Blob^ do
begin
bytes_left := TotalSize; // I have TotalSize bytes to read.
if (bytes_left = 0) then exit; // if I"ve nothing to copy, exit.
SetString(st, nil, TotalSize);
total_bytes_read := 0; // total bytes read is 0.
repeat
// Using BlobHandle, store at most "bytes_left" bytes in
// the buffer starting where I last left off
GetSegment(BlobHandle, @st[total_bytes_read + 1], bytes_left,
bytes_read);
// Increment total_bytes_read by the number of bytes actually read.
Inc(total_bytes_read, bytes_read);
// Decrement bytes_left by the number of bytes actually read.
Dec(bytes_left, bytes_read);
until bytes_left <= 0;
end;
Result := AllocMem(Length(st) + 1);
Result := StrLCopy(Result, PChar(st) + 16380 {!!!}, Length(st));
end;
...
exports
BlobAsPChar;
3. Описание функции в базе
DECLARE EXTERNAL FUNCTION GET_TEXT
BLOB
RETURNS CSTRING(20000) FREE_IT
ENTRY_POINT "BlobAsPChar" MODULE_NAME "test_udf.dll"
4. Запрос (выводит текст, начиная с 16380 символа в блоб)
select get_text(data) from table1
-------------------------------------------------------------
И ВОТ ГДЕ ЗДЕСЬ ОШИБКА ???
Digitman (2003-08-22 16:36:00) [8]
> Vorobyev Sergey
не знаю я....
у меня все работает ....
только что сгонял туда-сюда 17000 байт текста - все в порядке : что записал, то и прочитал
Digitman (2003-08-22 16:05:00) [9]
> Verg
это не оригинал)... это шаман-чукча с бубном писал !)
вот оригинал :
InterBase 6
Developer’s
Guide
blob_get_segment The first field in the Blob struct, blob_get_segment, is a pointer to a
function that is called to read a segment from a Blob if one is passed
to the UDF. The function takes four arguments: a Blob handle, the
address of a buffer into which to place Blob a segment of data that
is read, the size of that buffer, and the address of variable into to
store the size of the segment that is read. If Blob data is not read by
the UDF, set blob_get_segment to NULL.
Verg (2003-08-22 15:50:00) [10]
Я работаю под Fb1.5 RCx - никаких проблем с BLOB-ами.
> Digitman © (22.08.03 15:38) [13]
Вот оригинал:
function FillBuffer(var BLOb : TBLOb; Buf : PChar; FreeBufLen : Integer;
var ReadLen : Integer) : Boolean;
var
EndOfBLOb : Boolean;
FreeBufLenX, GotLength : Long;
begin
try
ReadLen := 0;
repeat
GotLength := 0; { !?! }
if FreeBufLen > MaxBLObPutLength then FreeBufLenX := MaxBLObPutLength
else FreeBufLenX := FreeBufLen;
with BLOb do
EndOfBLOb := not GetSegment(Handle, Buf + ReadLen, FreeBufLenX, GotLength);
Inc(ReadLen, GotLength);
Dec(FreeBufLen, GotLength);
until EndOfBLOb or (FreeBufLen = 0);
except
on E: Exception do begin
{$Ifdef Debug}
Writeln(X, E.Message);
Writeln(X, ReadLen, " ", FreeBufLen, " ", GotLength, " ", EndOfBLOb);
Flush(X);
{$Endif}
EndOfBLOb := True;
end;
end;
Buf[ReadLen] := #0;
Result := EndOfBLOb;
end;
Что-бы зничило { !?! }.
Я на всякий случай оставил.
Digitman (2003-08-22 15:38:00) [11]
> Verg
насчет Min() - да, здесь ты прав, это будет корректней
а насчет обнуления результирующего сч-ка перед GetSegment() - в этом нет никакого смысла
Vorobyev Sergey (2003-08-22 15:34:00) [12]
> Verg © (22.08.03 15:14) [10]
> http://www.ibase.ru/d_udf.htm
>
> файл udfdemo.zip
>
> Глянь...
Это все я уже перелопатил давно..
Потом пробовал функции из FreeUDFLib и т.п.
> Verg © (22.08.03 15:18) [11]
> Да, кстати, перед каждым вызовом getSegment надо BytesRead:=0;
И так попробовал.. НЕ ВЫХОДИТ!!!
Попробую описать конкретней задачу:
Есть таблица в которой есть блоб-поле data, там записаны текстовые данные..
Запросом
select id, GetImportantWords(data) as text from table1выбираю значения..
Где GetImportantWords - функция из UDF, которая анализирует блоб и вовращает эти ImportantWords..
Использую внутреннюю функцию (не экспортируемую)BlobAsStream для получения текста для дальнейшего анализа, так вот получается что есть только 16384 байт этого текста!!!
И соответственно эти ImportantWords берутся только из этого объема текста..
Verg (2003-08-22 15:18:00) [13]
Да, кстати, перед каждым вызовом getSegment надо BytesRead:=0;
Verg (2003-08-22 15:14:00) [14]
http://www.ibase.ru/d_udf.htm
файл udfdemo.zip
Глянь...
Vorobyev Sergey (2003-08-22 15:11:00) [15]
> Verg © (22.08.03 15:09) [8]
Не понял, конечно, почему так, но проверил..
НЕ РАБОТАЕТ!!!
Verg (2003-08-22 15:09:00) [16]
const segsize = 80;
....
Далее из Digitman
> while (Size > 0) and Boolean(GetSegment(BlobHandle, PChar(Buffer)
> + Result, min(Size, SegSize), BytesRead)) do begin
Vorobyev Sergey (2003-08-22 14:58:00) [17]
Содержимое блоб формируется другими модулями, там все нормально..
Полный размер блоба около 300кБ, там содержится просто текст..
Если считывать Blob в TStream в программе, например что-то типа
IBQuery1.FieldByName("BlobField").SaveToStream(Stream), то все считывается нормально..
потом идет анализ этого Stream и т.п.
Но чтобы не делать этого на клиенте, хочется реализовать на сервере, а в UDF никак не могу считать Blob в TStream..
Попробуй сам.
Запиши в блоб текст больше 16к.
Затем считай его в Stream своей процедуройв UDF и сохрани результат в файл (Stream.SaveToFile)
Я так и проверял..
Digitman (2003-08-22 14:54:00) [18]
> Vorobyev Sergey
затем, что есть сомнения в корректности алгоритма формирования содержимого блоб ДО того, как ты пытаешься считывать его
Vorobyev Sergey (2003-08-22 14:51:00) [19]
> покажи, как ры реализуешь обратную операцию : TStream ->
> Blob
не понял, зачем?
Digitman (2003-08-22 14:44:00) [20]
покажи, как ры реализуешь обратную операцию : TStream -> Blob