Subject Re: [IBO] OnCalculateField: writing to calculated field of type blob throws AV
Author Markus Ostenried
Hi Helen,

On Sun, Mar 8, 2009 at 02:11, Helen Borrie <helebor@...> wrote:
> Markus,
>
> It seems that your AV might be not to do with the blobnode at all, but come from calling Create on an undeclared stream object.
>
> See how this goes for you:
>
> procedure TForm1.IB_Query1CalculateField(Sender: TIB_Statement;
>  ARow: TIB_Row; AField: TIB_Column);
>
> var
>  instream: TStringStream;
> begin
>  with ARow do
>  if AField.NoCaseFieldName = 'blob_calc' then
>  begin
>    instream := TStringStream.Create('abc');
>    with AField as TIB_ColumnBlob do
>    try
>      Assign (instream);
>      if not (ByName('RDB$DESCRIPTION')).isNull then
>         Assign(ByName('RDB$DESCRIPTION'));
>    finally
>      instream.Free;
>    end;
>  end;
> end;
>
> Also, notice that for OnCalculateField you should refer
> to the Row object explicitly, to ensure that each row
> processed starts with everything fresh and free.
(select * from rdb$database isn't exactly the ideal
"set" to work with, though, since it can only be one row!!)

my code was just an example to show in as few lines as possible how to
reproduce the error I'm encountering, that's why I didn't declare the
stream variable but only called the constructor (I know that would be
a memory leak) and I used rdb$database only for demonstration. In my
application I have a "real set" and of course I use ARow there to get
the data my calculated field is based on.

When rewriting my example I encountered something interesting. This works:

procedure TForm1.IB_Query1CalculateField(Sender: TIB_Statement; ARow: TIB_Row;
AField: TIB_Column);
begin
if (AField.NoCaseFieldName = 'blob_calc') then begin
AField.Assign(TStringStream.Create('abc'));
end;
end;

But this gives the error I described:

procedure TForm1.IB_Query1CalculateField(Sender: TIB_Statement; ARow: TIB_Row;
AField: TIB_Column);
begin
if SameText(AField.FieldName, 'blob_calc') then begin
AField.Assign(TStringStream.Create('abc'));
end;
end;

The only difference is the comparison of the field name. My button
click to set it all up looks like this:

procedure TForm1.Button1Click(Sender: TObject);
var
IB_Connection1: TIB_Connection;
IB_Query1: TIB_Query;
begin
IB_Connection1 := TIB_Connection.Create(Self);
with IB_Connection1 do begin
Name := 'IB_Connection1';
SQLDialect := 3;
Path := 'C:\Program
Files\Firebird\Firebird_2_1\examples\empbuild\EMPLOYEE.FDB';
Protocol := cpTCP_IP;
end;

IB_Query1 := TIB_Query.Create(Self);
with IB_Query1 do begin
Name := 'IB_Query1';
IB_Connection := IB_Connection1;
SQL.Add('select * from rdb$database');
CalculatedFields.Add('blob_calc blob sub_type 0');
OnCalculateField := IB_Query1CalculateField;
end;

IB_Connection1.Connect;
IB_Query1.Open;
end;

I will have a look at my application to see if changing from
SameText() to NoCaseFieldName helps there, too. But I'm clueless as to
why it should :) Thanks for your suggestion, Helen.

Regards,
Markus