[fpc-devel] DatabaseError/DatabaseErrorFmt with Component parameter,	TParams.GetByName
    Bram Kuijvenhoven 
    kuifwaremailinglists at xs4all.nl
       
    Mon Sep 26 14:10:07 CEST 2005
    
    
  
Hi FPC,
I found that using a TParams.GetByName call using an invalid parameter name causes a crash when the TParams is not owned by a TDataset.
I'm not sure whether it is a requirement of TParams usage to have it owned by a TDataset object, but otherwise, below is an explanation of what is going wrong.
Now the details about the crash. Start by looking at
dsparams.inc, lin 146 to 151:
  Function TParams.ParamByName(const Value: string): TParam;
  begin
    Result:=FindParam(Value);
    If (Result=Nil) then
      DatabaseErrorFmt(SParameterNotFound,[Value],Dataset);
  end;
If no parameter with name Value is found, it calls DatabaseErrorFmt with its formal parameter Component getting the value that Dataset returns. Look at TParams.GetDataSet:
dsparams.inc, line 32 to 38:
  Function TParams.GetDataSet: TDataSet;
  begin
    If (FOwner is TDataset) Then
      Result:=TDataset(FOwner)
    else
      Result:=Nil;
  end;
As you can see, Dataset will take value nil if the TParams instance has no Owner. Now look at DatabaseErrorFmt:
db.pp, line 1823 to 1827:
  Procedure DatabaseErrorFmt (Const Fmt : String; Args : Array Of const;
                              Comp : TComponent);
  begin
    Raise EDatabaseError.CreateFmt(Format('%s : %s',[Comp.Name,Fmt]),Args);
  end;
No check is done on Assigned(Comp), so the dereferencing Comp.Name will cause an Access Violation (instead of a nice 'Parameter blablabla not found' message).
Perhaps we should fix TParams.ParamByName to
  Function TParams.ParamByName(const Value: string): TParam;
  begin
    Result:=FindParam(Value);
    If (Result=Nil) then
      begin
      if DataSet<>nil then
        DatabaseErrorFmt(SParameterNotFound,[Value],DataSet)
      else
        DatabaseErrorFmt(SParameterNotFound,[Value]);
      end;
  end;
or
  Function TParams.ParamByName(const Value: string): TParam;
  var
    TmpDataset:TDataset;
  begin
    Result:=FindParam(Value);
    If (Result=Nil) then
      begin
      TmpDataSet:=DataSet;
      if TmpDataSet<>nil then
        DatabaseErrorFmt(SParameterNotFound,[Value],TmpDataset)
      else
        DatabaseErrorFmt(SParameterNotFound,[Value]);
      end;
  end;
Regards,
Bram Kuijvenhoven
    
    
More information about the fpc-devel
mailing list