Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как правильно записать Blob в TStream в UDF ?


Страницы:   1 2

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо