Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2003.09.15;
Скачать: [xml.tar.bz2];

Вниз

Как правильно записать Blob в TStream в UDF ?   Найти похожие ветки 

 
Vorobyev Sergey   (2003-08-22 14:11) [0]

У меня есть следующий код (немного переделанный, в исходном варианте результат записывался не в 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.


 
Digitman   (2003-08-22 14:20) [1]

PMemoryStream = ^TMemoryStream;

...
function BlobToMemStream(Blob: PBlob): PMemoryStream; cdecl; export;
.....

function InternalGetBlob(Blob: PBlob; Buffer: Pointer; Size: Integer): ULong;
var
BytesRead: Integer;
begin
Result:= 0;
if Assigned(Blob) then with Blob^ do
if Assigned(BlobHandle) and Assigned(GetSegment) then
while (Size > 0) and Boolean(GetSegment(BlobHandle, PChar(Buffer) + Result, Size, BytesRead)) do begin
Inc(Result, BytesRead);
Dec(Size, BytesRead);
end;
end;

function BlobToMemStream(Blob: PBlob): PMemoryStream;
var
tmp: TMemoryStream;
begin
Result:= nil;
if Assigned(Blob) then
with Blob^ do
try
if Assigned(BlobHandle) and Assigned(GetSegment) then begin
tmp:= TMemoryStream.Create;
try
tmp.Size:= TotalSize;
InternalGetBlob(Blob, tmp.Memory, TotalSize);
Result:= PMemoryStream(Blob);
Result^:= tmp;
AttachedThreads.RegisterObject(Result^);
except
tmp.Free;
raise;
end;
end else
Result:= nil;
except
Result:= nil;
end;
end;


 
Vorobyev Sergey   (2003-08-22 14:37) [2]


> Digitman © (22.08.03 14:20) [1]

Проверил, все равно только первые 16384 байт берет, остальные обрезает..


 
Digitman   (2003-08-22 14:43) [3]

а ты уверен, что содержимое блоба в действительности иное ? т.е. полный размер блоба, скажем, 16386 байт и два последних байта точно не равны нулю ? может ты блоб своими руками некорректно сформировал, а при его чтении ждешь "правильного" результата ?


 
Digitman   (2003-08-22 14:44) [4]

покажи, как ры реализуешь обратную операцию : TStream -> Blob


 
Vorobyev Sergey   (2003-08-22 14:51) [5]


> покажи, как ры реализуешь обратную операцию : TStream ->
> Blob

не понял, зачем?


 
Digitman   (2003-08-22 14:54) [6]


> Vorobyev Sergey


затем, что есть сомнения в корректности алгоритма формирования содержимого блоб ДО того, как ты пытаешься считывать его


 
Vorobyev Sergey   (2003-08-22 14:58) [7]

Содержимое блоб формируется другими модулями, там все нормально..

Полный размер блоба около 300кБ, там содержится просто текст..

Если считывать Blob в TStream в программе, например что-то типа
IBQuery1.FieldByName("BlobField").SaveToStream(Stream), то все считывается нормально..
потом идет анализ этого Stream и т.п.
Но чтобы не делать этого на клиенте, хочется реализовать на сервере, а в UDF никак не могу считать Blob в TStream..

Попробуй сам.
Запиши в блоб текст больше 16к.
Затем считай его в Stream своей процедурой в UDF и сохрани результат в файл ( Stream.SaveToFile)
Я так и проверял..


 
Verg   (2003-08-22 15:09) [8]

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 15:11) [9]


> Verg © (22.08.03 15:09) [8]

Не понял, конечно, почему так, но проверил..
НЕ РАБОТАЕТ!!!


 
Verg   (2003-08-22 15:14) [10]

http://www.ibase.ru/d_udf.htm

файл udfdemo.zip

Глянь...


 
Verg   (2003-08-22 15:18) [11]

Да, кстати, перед каждым вызовом getSegment надо BytesRead:=0;


 
Vorobyev Sergey   (2003-08-22 15:34) [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 берутся только из этого объема текста..


 
Digitman   (2003-08-22 15:38) [13]


> Verg


насчет Min() - да, здесь ты прав, это будет корректней

а насчет обнуления результирующего сч-ка перед GetSegment() - в этом нет никакого смысла


 
Verg   (2003-08-22 15:50) [14]

Я работаю под 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 16:05) [15]


> 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.


 
Digitman   (2003-08-22 16:36) [16]


> Vorobyev Sergey


не знаю я....

у меня все работает ....

только что сгонял туда-сюда 17000 байт текста - все в порядке : что записал, то и прочитал


 
Vorobyev Sergey   (2003-08-23 13:08) [17]

Ну хорошо... забудем про 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

-------------------------------------------------------------

И ВОТ ГДЕ ЗДЕСЬ ОШИБКА ???


 
Verg   (2003-08-23 16:20) [18]


.....
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.


 
Verg   (2003-08-23 16:27) [19]

Кстати, без MIN на fb1.5 RC5 - вешается клиент, а сервер - 99% CPU Usage.
Без bytes_read:=0 - GetSegment читает из блоба кусок непредсказуемой длины.


 
Vorobyev Sergey   (2003-08-23 16:34) [20]


> Verg © (23.08.03 16:20) [18]

Заработало!!!!!! Verg, спасибо!!
Теперь буду разбираться, что же я делал раньше не так..
И почему же все-таки нужно bytes_read := 0 и Min(bytes_left,MaxSegLength)..
Пригодится в будущем..


 
Verg   (2003-08-23 16:40) [21]


> Min(bytes_left,MaxSegLength)..


Ну это-то понятно, ведь функция называется Get Segment.
А вот bytes_read := 0 - это "просто надо" :))
Давно было не помню, хотя разбирался когда-то....

> это шаман-чукча с бубном писал !)


:))))


 
Verg   (2003-08-23 17:03) [22]

Вот еще что из памяти всплыло - достаточно чтобы старшее слово (старшие 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 19:24) [23]

Ну я и баклан!!! :)))


> 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-ать :)))

Старею, блин...



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2003.09.15;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.01 c
1-48622
Hawk2
2003-09-02 19:43
2003.09.15
Что за ошибка: Invalid pointer operation.


14-48686
Vlad Oshin
2003-08-27 15:57
2003.09.15
Rouse_, понапиши перлов что ли...


1-48528
dataMaster
2003-09-02 12:06
2003.09.15
Как в ComboBox отключить какой-нибудь пукнт


7-48798
Вася Пупкин
2003-07-01 18:09
2003.09.15
Загрузочный вирус! Казалось бы.. [D6, WinXP] (восстановление)


3-48437
denick
2003-08-24 04:03
2003.09.15
Помогите пожалуйста с SQL запросом.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский