Проблема с UDF возвращающие Blob

Access Violation, некорректное выполнение запросов или вызовов API, ошибки утилит командной строки, в общем все, что вам мешает работать

Модераторы: kdv, dimitr

Ответить
_so_
Сообщения: 144
Зарегистрирован: 04 ноя 2004, 22:17

Проблема с UDF возвращающие Blob

Сообщение _so_ » 04 май 2005, 11:31

Есть много udf состоящие напрмер:
DECLARE EXTERNAL FUNCTION BCOMMAUNION
BLOB,
BLOB,
BLOB
RETURNS PARAMETER 3
ENTRY_POINT 'BCommaUnion' MODULE_NAME 'oeudf.dll';
Так вот обнаружилось на Ib7.1 sp2 и Ib 7.5, что если второй парметр передается null, то UDF всегда возвращает null. Вне зависимости от того что пишем в udf.
Проверил на FB1.5 emb работает правильно. Кто встречал это и как с этим бороться?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 04 май 2005, 11:43

твоя udf, тебе и отлаживать.

_so_
Сообщения: 144
Зарегистрирован: 04 ноя 2004, 22:17

Сообщение _so_ » 04 май 2005, 16:35

Да не из-за udf похоже дело. В FB работает и 6.0 раньше точно работало.
Если внутри UDF вызвать с параметром
BCOMMAUNION (<Парметрй>, StrToBlob('')) , то тоже работает.

_so_
Сообщения: 144
Зарегистрирован: 04 ноя 2004, 22:17

Сообщение _so_ » 04 май 2005, 16:55

Поставили debug. Из debug видно, что в blob пишется не пустая строка, а blob возвращает null.
Вот например реализация:

Код: Выделить всё

type
  PBlob = ^TBlob;
  TBlob = record
    GetSegment: function(Handle: pointer; Buffer: PChar; MaxLength: integer; var ReadLength: integer): WordBool; cdecl;
    Handle: pointer;               // handle
    SegCount,                      // number of segments
    MaxSegLength,                  // max length of segment
    TotalLength: integer;          // total blob length
    PutSegment: procedure(Handle: pointer; Buffer: PChar; Length: integer); cdecl;
  end;

const
  MaxBlobPutLength = 80;
  MaxVarCharLength = 32767;
  MaxResultStringLength = 8190;


{ udfs }


function FillBuffer(var Blob: TBlob; Buf: PChar; FreeBufLen: integer; var ReadLen: Integer): boolean;
var
  EndOfBlob: boolean;
  FreeBufLenX, GotLength: integer;
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
    EndOfBlob := True;
  end;
  Buf[ReadLen] := #0;
  Result := EndOfBlob;
end;

function ReadBlob(var Blob: TBlob): string;
var
  ReadLen: Integer;
begin
  with Blob do
    if Assigned(Handle) and (TotalLength > 0) then
    begin
      SetLength(Result, TotalLength);
      FillBuffer(Blob, PChar(Result), TotalLength, ReadLen);
      SetLength(Result, ReadLen);
    end else
      Result := '';
end;

procedure WriteBlob(var Blob: TBlob; const S: string);
var
  SLen, PutLen: integer;
  PS: PChar;
begin
  SLen := length(S);
  PS := PChar(S);

  if not Assigned(Blob.Handle) then
    Exit;

  if SLen = 0 then
  begin
    PutLen := 0;
    with Blob do
      PutSegment(Handle, PS, PutLen);
  end else
  begin
    while SLen > 0 do
    begin
      if SLen > MaxBlobPutLength then
        PutLen := MaxBlobPutLength
      else
        PutLen := SLen;

      with Blob do
        PutSegment(Handle, PS, PutLen);

      dec(SLen, PutLen);
      inc(PS, PutLen);
    end;
  end;
end;

procedure BCommaUnion(Comma1, Comma2, Res: PBlob);
begin
  WriteBlob(Res^, ReadBlob(Comma1^) + ReadBlob(Comma2^));
end;
Теперь если вызвать:
select BlobToStr(BCOmmaUnion(StrToBlob('800'), Props)) as Props from classes where Props is null
То возвращает в клонке refs пустые строки.

select BlobToStr(BCOmmaUnion(StrToBlob('800'), StrToBlob(BlobToStr(Props)))) as Props from classes where Props is null
То возвращает правильно '800'
Отлаживать здесь нечего все udf работают чере одни и те же фунции
ReadBlob и WriteBlob.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 04 май 2005, 18:14

Поставили debug. Из debug видно,
что поставили? я имел в виду отладить функцию в отладчике Delphi.
Отлаживать здесь нечего
ну не знаю. я бы посмотрел...

_so_
Сообщения: 144
Зарегистрирован: 04 ноя 2004, 22:17

Сообщение _so_ » 05 май 2005, 15:28

Уговорил и что я увидел в параметр Res приходит блоб с handle равным 0.
Если перестроить запрос на:

Код: Выделить всё

select BlobToStr(BCOmmaUnion(Props, StrToBlob('800'))) as Props from classes where Props is null
То тоже все работает. Явный глюк IB. Может Dimitr что-нибудь скажет исправляли что-то похожее в FB.

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 06 май 2005, 08:45

увы, ничего такого не припоминаю. Если на FB1.0 тоже работает, то мы тут не причем, иначе и вправду фиксилось.

_so_
Сообщения: 144
Зарегистрирован: 04 ноя 2004, 22:17

Сообщение _so_ » 06 май 2005, 11:09

Что делать-то не использовать udf в которых последний параметр и резулбтирующий параметр равен blob?
Я препоминаю раньше мы и со строками работали также через параметр в UDF, и там были похожие глюки (я помнится писал kdv на support). Переписали все через функции, но с блобами так нельзя.
Может кто-нибудь напишет в Borland (плохо у меня с английским, а то сам бы давно написал).

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 06 май 2005, 11:11

я увидел в параметр Res приходит блоб с handle равным 0.
давай почетче сформулируем. То есть, при передаче null вместо второго параметра, при входе в udf получаем третий параметр пустой?

_so_
Сообщения: 144
Зарегистрирован: 04 ноя 2004, 22:17

Сообщение _so_ » 06 май 2005, 11:42

Да утретьего параметра (результирующего) блоба handle равен нулю. Поэтому писать как бы не куда. И следвательно udf возвращает null.

Ответить