Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2011-04

Recent changes to TField.SetData

19 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

LacaK

Hi,
This fix
http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-db/src/base/fields.inc?r1=17199&r2=17220 fixes mising call to TField.Validate (before data are written into record buffer) and adds also call to TField.DataChanged (after data are written)

But It seems to me, that DataChanged is now called 2 times

First in TDataSet descendants in SetFieldData method (see bufdataset.pas, dbf.pas, paradox.pp, meds.pp) and second in above mentioned place.

So it would be good remove this call from TDataSet descendants. For example for bufdataset.pas:

 1860   if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
 1861     DataEvent(deFieldChange, Ptrint(Field));

Laco.

Reply by email

Martin Schreiber
to Michael Van Canneyt: Hm. No, we'll remove the call from TField. There may be other descendants (AnyDac, Zeos…
Michael Van Canneyt wrote 22 lines
On Mon, 4 Apr 2011, LacaK wrote: > But It seems to me, that DataChanged is now called 2 times > > First in TDataSet descendants in SetFieldData method (see > bufdataset.pas, dbf.pas, paradox.pp, meds.pp) and second in above > mentioned place. > > So it would be good remove this call from TDataSet descendants. For > example for bufdataset.pas: > > 1860 if not (State in [dsCalcFields, dsFilter, dsNewValue]) then > 1861 DataEvent(deFieldChange, Ptrint(Field)); Hm. No, we'll remove the call from TField. There may be other descendants (AnyDac, Zeos and whatnot) that also call DataEvent and OnValidate, and we cannot apply this change on them.

Thanks. For example the code in tmsebufdataset:
"
procedure tmsebufdataset.setfielddata(field: tfield; buffer: pointer);

var
  po1: pointer;
  datasize: integer;
begin
  field.validate(buffer);
  po1:= getfieldbuffer(field,buffer = nil,datasize);
  if buffer  nil then begin
   move(buffer^,po1^,datasize);
  end
  else begin
   fillchar(po1^,datasize,0);
  end;
  fieldchanged(field);
end;
"

Martin

Reply by email

Michael Van Canneyt
to LacaK: This fix http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-db/src/base/field…
LacaK wrote 16 lines
Hi, This fix http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-db/src/base/fields.inc?r1=17199&r2=17220 fixes mising call to TField.Validate (before data are written into record buffer) and adds also call to TField.DataChanged (after data are written) But It seems to me, that DataChanged is now called 2 times First in TDataSet descendants in SetFieldData method (see bufdataset.pas, dbf.pas, paradox.pp, meds.pp) and second in above mentioned place. So it would be good remove this call from TDataSet descendants. For example for bufdataset.pas: 1860 if not (State in [dsCalcFields, dsFilter, dsNewValue]) then 1861 DataEvent(deFieldChange, Ptrint(Field));

Hm.
No, we'll remove the call from TField.

There may be other descendants (AnyDac, Zeos and whatnot) that also call DataEvent and OnValidate, and we cannot apply this change on them.

Michael.

Reply by email

LacaK
to Michael Van Canneyt

Michael Van Canneyt wrote / napísal(a):

Show quoted text 30 lines
On Mon, 4 Apr 2011, LacaK wrote: > Hi, > This fix > http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-db/src/base/fields.inc?r1=17199&r2=17220 > > fixes mising call to TField.Validate (before data are written into > record buffer) and adds also call to TField.DataChanged (after data > are written) > > But It seems to me, that DataChanged is now called 2 times > > First in TDataSet descendants in SetFieldData method (see > bufdataset.pas, dbf.pas, paradox.pp, meds.pp) and second in above > mentioned place. > > So it would be good remove this call from TDataSet descendants. For > example for bufdataset.pas: > > 1860 if not (State in [dsCalcFields, dsFilter, dsNewValue]) then > 1861 DataEvent(deFieldChange, Ptrint(Field)); Hm. No, we'll remove the call from TField. There may be other descendants (AnyDac, Zeos and whatnot) that also call DataEvent and OnValidate, and we cannot apply this change on them.

Yes it seems, that we must do it in this way.
(Although I do not understand why Borland introduces this strange behavior)

Then please move approprate code at least into
TCustomBufDataset.SetFieldData
Thanks

Laco.

Reply by email

Unknown author
to LacaK
LacaK wrote 33 lines
Michael Van Canneyt wrote / napísal(a): > > > On Mon, 4 Apr 2011, LacaK wrote: > >> Hi, >> This fix >> http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-db/src/base/fields.inc?r1=17199&r2=17220 >> fixes mising call to TField.Validate (before data are written into record >> buffer) and adds also call to TField.DataChanged (after data are written) >> >> But It seems to me, that DataChanged is now called 2 times >> >> First in TDataSet descendants in SetFieldData method (see bufdataset.pas, >> dbf.pas, paradox.pp, meds.pp) and second in above mentioned place. >> >> So it would be good remove this call from TDataSet descendants. For >> example for bufdataset.pas: >> >> 1860 if not (State in [dsCalcFields, dsFilter, dsNewValue]) then >> 1861 DataEvent(deFieldChange, Ptrint(Field)); > > Hm. No, we'll remove the call from TField. > > There may be other descendants (AnyDac, Zeos and whatnot) that also call > DataEvent > and OnValidate, and we cannot apply this change on them. Yes it seems, that we must do it in this way. (Although I do not understand why Borland introduces this strange behavior) Then please move approprate code at least into TCustomBufDataset.SetFieldData Thanks

This code was already there.

Should the 'Validate' code be moved there too ?

Michael.

Reply by email

Luiz Americo Pereira Camara
to Unknown author
Show quoted text 16 lines
On Mon, 4 Apr 2011, LacaK wrote: > Michael Van Canneyt wrote / napísal(a): >> >> >> On Mon, 4 Apr 2011, LacaK wrote: > > Then please move approprate code at least into > TCustomBufDataset.SetFieldData > Thanks This code was already there. Should the 'Validate' code be moved there too ?

Yes. TDataset descendants are responsible to calling Validate, e.g., zeos call it inside TZAbstractRODataset.SetFieldData.

One of the reasons of letting descendants call it it's too improve granularity so Validate can be called in the middle of the routine, as is in zeos, instead to force the call before the TDataset routine.

Luiz

Reply by email

LacaK
to Luiz Americo Pereira Camara
Show quoted text 11 lines
>> >> Then please move approprate code at least into >> TCustomBufDataset.SetFieldData >> Thanks > > This code was already there. > > Should the 'Validate' code be moved there too ? Yes. TDataset descendants are responsible to calling Validate, e.g., zeos call it inside TZAbstractRODataset.SetFieldData.

I agree, but I do not like idea, that SAME piece of code must be repeated in many descendants of TDataSet (TCustomBufDataSet, TParadox, TMemDataset, TFixedFormatDataSet, TDbf, TCustomSqliteDataset etc.)

So it would be good, if we can put 'validate code' into any new method? and call it once from descendants (be precise only from descendants, which are intended for use in FPC, because components which are also for Delphi must do it in Delphi compatible way and can not use this new method)

One of the reasons of letting descendants call it it's too improve granularity so Validate can be called in the middle of the routine, as is in zeos, instead to force the call before the TDataset routine.

Yes, but I think, that in many cases can be expected, that 'validate' will be called before any other action,

It seems, that TDataSet descendants never call inherited TDataSet.SetFieldData(Field: TField; Buffer: Pointer); (because it is empty method)
So if we move 'validate code' there then in 'our' descendants we put only {$IFDEF FPC}

   inherited;

{$ENDIF}
at first line. This does not affect existing tdataset descendants, and FPC dataset descendants can be adjusted to benefit from this. (I know, it is not perfect solution ;-) but I very dislike repeat same 'validate' code in X places)

--or--
introduce any new method (ValidateFieldData ? ;-))) and let tdatsset
descendants use it:
{$IFDEF FPC}
 ValidateFieldData(Field: TField; Buffer: Pointer);
{$ENDIF}

--or--
some smarter solution ?

Laco.

Reply by email

Unknown author
to Luiz Americo Pereira Camara: Yes. TDataset descendants are responsible to calling Validate, e.g., zeos call it inside…
Luiz Americo Pereira Camara wrote 24 lines
On 4/4/2011 10:28, wrote: > > > On Mon, 4 Apr 2011, LacaK wrote: > >> Michael Van Canneyt wrote / napísal(a): >>> >>> >>> On Mon, 4 Apr 2011, LacaK wrote: >> >> Then please move approprate code at least into >> TCustomBufDataset.SetFieldData >> Thanks > > This code was already there. > > Should the 'Validate' code be moved there too ? Yes. TDataset descendants are responsible to calling Validate, e.g., zeos call it inside TZAbstractRODataset.SetFieldData. One of the reasons of letting descendants call it it's too improve granularity so Validate can be called in the middle of the routine, as is in zeos, instead to force the call before the TDataset routine.

Ok. I will move the code.

Michael.

Reply by email

LacaK
to LacaK: I agree, but I do not like idea, that SAME piece of code must be repeated in many…
Show quoted text 12 lines
--or-- introduce any new method (ValidateFieldData ? ;-))) and let tdatsset descendants use it: {$IFDEF FPC} ValidateFieldData(Field: TField; Buffer: Pointer); {$ENDIF} --or-- some smarter solution ?

The whole code, which is repeated (and can be put in one place) is:

  if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then
  begin
    DatabaseErrorFmt(SNotEditing,[Name],self);
    exit;
  end;
  if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then
  begin
    if ReadOnly then DatabaseErrorFmt(SReadOnlyField,
[Field.DisplayName], Self);
    Field.Validate(Buffer);
  end;
Laco.

Reply by email

Luiz Americo Pereira Camara
to LacaK: I agree, but I do not like idea, that SAME piece of code must be repeated in many…
LacaK wrote 16 lines
>>> >>> Then please move approprate code at least into >>> TCustomBufDataset.SetFieldData >>> Thanks >> >> This code was already there. >> >> Should the 'Validate' code be moved there too ? > > Yes. TDataset descendants are responsible to calling Validate, e.g., > zeos call it inside TZAbstractRODataset.SetFieldData. I agree, but I do not like idea, that SAME piece of code must be repeated in many descendants of TDataSet (TCustomBufDataSet, TParadox, TMemDataset, TFixedFormatDataSet, TDbf, TCustomSqliteDataset etc.)

If it was just adding the call before SetFieldData it would take less than 10min, but it's necessary to know where to put so does not break something.

Show quoted text 5 lines
So it would be good, if we can put 'validate code' into any new method? and call it once from descendants (be precise only from descendants, which are intended for use in FPC, because components which are also for Delphi must do it in Delphi compatible way and can not use this new method)

It's just to lines of code.

Show quoted text 7 lines
> > One of the reasons of letting descendants call it it's too improve > granularity so Validate can be called in the middle of the routine, > as is in zeos, instead to force the call before the TDataset routine. Yes, but I think, that in many cases can be expected, that 'validate' will be called before any other action,

It's necessary to do some checks before calling it.

Luiz

Reply by email

Unknown author
to LacaK: The whole code, which is repeated (and can be put in one place) is: if not (State in…
LacaK wrote 26 lines
> > > --or-- > introduce any new method (ValidateFieldData ? ;-))) and let tdatsset > descendants use it: > {$IFDEF FPC} > ValidateFieldData(Field: TField; Buffer: Pointer); > {$ENDIF} > > --or-- > some smarter solution ? > The whole code, which is repeated (and can be put in one place) is: if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then begin DatabaseErrorFmt(SNotEditing,[Name],self); exit; end; if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then begin if ReadOnly then DatabaseErrorFmt(SReadOnlyField, [Field.DisplayName], Self); Field.Validate(Buffer); end;

You are right in your dislike.

I will create a 'BeforeSetFieldData' in TDataset and put the code in there, and the same for 'AfterSetFieldData' with the OnChange code.

Michael.

Reply by email

LacaK
to Unknown author

wrote / napísal(a):

Show quoted text 38 lines
On Tue, 5 Apr 2011, LacaK wrote: > >> >> >> --or-- >> introduce any new method (ValidateFieldData ? ;-))) and let tdatsset >> descendants use it: >> {$IFDEF FPC} >> ValidateFieldData(Field: TField; Buffer: Pointer); >> {$ENDIF} >> >> --or-- >> some smarter solution ? >> > The whole code, which is repeated (and can be put in one place) is: > > if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then > begin > DatabaseErrorFmt(SNotEditing,[Name],self); > exit; > end; > if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then > begin > if Read > OnlythenDatabaseErrorFmtSReadOnlyField,[Field.DisplayName], > Self); > Field.Validate(Buffer); > end; You are right in your dislike. I will create a 'BeforeSetFieldData' in TDataset and put the code in there, and the same for 'AfterSetFieldData' with the OnChange code.

OK,
Then please do not forget commit necessary changes also in other descendants (not only in TCustomBufDataSet but also in TParadox, TMemDataset, TFixedFormatDataSet, TDbf) to completelly fix 'missing onvalidate call' problem.
Thanks

Laco.

Reply by email

LacaK
to LacaK
Show quoted text 28 lines
>> The whole code, which is repeated (and can be put in one place) is: >> >> if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then >> begin >> DatabaseErrorFmt(SNotEditing,[Name],self); >> exit; >> end; >> if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then >> begin >> if Read >> OnlythenDatabaseErrorFmtSReadOnlyField,[Field.DisplayName], >> Self); >> Field.Validate(Buffer); >> end; > > You are right in your dislike. > > I will create a 'BeforeSetFieldData' in TDataset and put the code in > there, > and the same for 'AfterSetFieldData' with the OnChange code. > OK, Then please do not forget commit necessary changes also in other descendants (not only in TCustomBufDataSet but also in TParadox, TMemDataset, TFixedFormatDataSet, TDbf) to completelly fix 'missing onvalidate call' problem. Thanks

I am still thinking about this.
I have other solution, which is relative simple , puts base logic into base TField methods (so all TDataSet descendants can benefit from it) and does not negatively affect existing TDataSet descendants and does not require introduce new methods (BeforeSetFieldData, AfterSetFieldData). Let's distributes repeating used code as follows:

1. base checks "before" into procedure TField.SetData(Buffer: Pointer;
NativeFormat : Boolean);
  820 begin
  821   If Not Assigned(FDataset) then
  822     DatabaseErrorFmt(SNoDataset,[FieldName]);
        if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then //here should be IMO also dsNewValue
          DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet);
        if ReadOnly and (FieldNo>0) and not (FDataSet.State in [dsSetKey, dsFilter]) then
          DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self);
  829   FDataSet.SetFieldData(Self,Buffer, NativeFormat);
--------------------------------------------------------------------------
2. into procedure TField.Validate(Buffer: Pointer);
  892 begin
        if FDataSet.State in [dsSetKey, dsFilter] then Exit;
  893   If assigned(OnValidate) Then

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

3. "after call" into procedure TDataSet.SetFieldData(Field: TField; Buffer: Pointer);
     begin
       if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
         DataEvent(deFieldChange, Ptrint(Field));
     end;

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

And now all what we must do, is put into method SetFieldData in TDataSet descendants one line:

Field.Validate(Buffer);

and one line at end:

inherited; //calls "field change" ... this is done by all TDataSet descendants in fcl-db as a last thing

It is only draft, so some detils may be changed ... ;-) What do you think ?

Laco.

Reply by email

Luiz Americo Pereira Camara
to Unknown author: You are right in your dislike. I will create a 'BeforeSetFieldData' in TDataset and put…
Show quoted text 35 lines
On Tue, 5 Apr 2011, LacaK wrote: > >> >> >> --or-- >> introduce any new method (ValidateFieldData ? ;-))) and let tdatsset >> descendants use it: >> {$IFDEF FPC} >> ValidateFieldData(Field: TField; Buffer: Pointer); >> {$ENDIF} >> >> --or-- >> some smarter solution ? >> > The whole code, which is repeated (and can be put in one place) is: > > if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then > begin > DatabaseErrorFmt(SNotEditing,[Name],self); > exit; > end; > if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then > begin > if ReadOnly then DatabaseErrorFmt(SReadOnlyField, > [Field.DisplayName], Self); > Field.Validate(Buffer); > end; You are right in your dislike. I will create a 'BeforeSetFieldData' in TDataset and put the code in there,

I still think that is overkill: adding a method to replace just two lines of code.

Anyway, if you decide this way, consider another name. Sometimes is to be called in the "middle" of SetFieldData

and the same for 'AfterSetFieldData' with the OnChange code.

This one is a bit more odd since currently only bufdataset will use it (or do you plan to replace the existing code in descendants?)

Luiz

Reply by email

LacaK
to LacaK: I am still thinking about this. I have other solution, which is relative simple , puts…

Small optimalization use dsWriteModes instead of fixed set:

- if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then //here should be IMO also dsNewValue
+ if not (FDataSet.State in dsWriteModes) then
Show quoted text 9 lines
DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet); if ReadOnly and (FieldNo>0) and not (FDataSet.State in [dsSetKey, dsFilter]) then DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self); 829 FDataSet.SetFieldData(Self,Buffer, NativeFormat); --------------------------------------------------------------------------

Laco.

Reply by email

LacaK
to LacaK: I am still thinking about this. I have other solution, which is relative simple , puts…

Hi,
here are diffs with changes, I hope they will be good for all TDataSet descendants (those specific to FPC and also those which are also for use in Delphi)
Code which is general (and is used repeatedly) is placed in TField methods and only small code remains which must be placed into each TDataSet descendant.
(I patched only TBufDataSet, but later can be updated also other TDataSet descendants ... remove redundant code and add Field.Validate(...)) Thanks
-Laco.

Show quoted text 91 lines
>>> The whole code, which is repeated (and can be put in one place) is: >>> >>> if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then >>> begin >>> DatabaseErrorFmt(SNotEditing,[Name],self); >>> exit; >>> end; >>> if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then >>> begin >>> if Read >>> OnlythenDatabaseErrorFmtSReadOnlyField,[Field.DisplayName], >>> Self); >>> Field.Validate(Buffer); >>> end; >> >> You are right in your dislike. >> >> I will create a 'BeforeSetFieldData' in TDataset and put the code in >> there, >> and the same for 'AfterSetFieldData' with the OnChange code. >> > OK, > Then please do not forget commit necessary changes also in other > descendants (not only in TCustomBufDataSet but also in TParadox, > TMemDataset, TFixedFormatDataSet, TDbf) to completelly fix 'missing > onvalidate call' problem. > Thanks > I am still thinking about this. I have other solution, which is relative simple , puts base logic into base TField methods (so all TDataSet descendants can benefit from it) and does not negatively affect existing TDataSet descendants and does not require introduce new methods (BeforeSetFieldData, AfterSetFieldData). Let's distributes repeating used code as follows: 1. base checks "before" into procedure TField.SetData(Buffer: Pointer; NativeFormat : Boolean); 820 begin 821 If Not Assigned(FDataset) then 822 DatabaseErrorFmt(SNoDataset,[FieldName]); if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then //here should be IMO also dsNewValue DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet); if ReadOnly and (FieldNo>0) and not (FDataSet.State in [dsSetKey, dsFilter]) then DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self); 829 FDataSet.SetFieldData(Self,Buffer, NativeFormat); -------------------------------------------------------------------------- 2. into procedure TField.Validate(Buffer: Pointer); 892 begin if FData Set.Statein[dsSetKey,dsFilter]thenExit 893 If assigned(OnValidate) Then -------------------------------------------------------------------------- 3. "after call" into procedure TDataSet.SetFieldData(Field: TField; Buffer: Pointer); begin if not (State in [dsCalcFields, dsFilter, dsNewValue]) then DataEvent(deFieldChange, Ptrint(Field)); end; -------------------------------------------------------------------------- And now all what we must do, is put into method SetFieldData in TDataSet descendants one line: Field.Validate(Buffer); and one line at end: inherited; //calls "field change" ... this is done by all TDataSet descendants in fcl-db as a last thing It is only draft, so some detils may be changed ... ;-) What do you think ? Laco.

Reply by email

LacaK
to LacaK

Michael,
do you plan do something else with this "OnValidate" problem ? Thanks
-Laco.

Show quoted text 110 lines
Hi, here are diffs with changes, I hope they will be good for all TDataSet descendants (those specific to FPC and also those which are also for use in Delphi) Code which is general (and is used repeatedly) is placed in TField methods and only small code remains which must be placed into each TDataSet descendant. (I patched only TBufDataSet, but later can be updated also other TDataSet descendants ... remove redundant code and add Field.Validate(...)) Thanks -Laco. > >>>> The whole code, which is repeated (and can be put in one place) is: >>>> >>>> if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then >>>> begin >>>> DatabaseErrorFmt(SNotEditing,[Name],self); >>>> exit; >>>> end; >>>> if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then >>>> begin >>>> if Read >>>> OnlythenDatabaseErrorFmtSReadOnlyField,[Field.DisplayName], >>>> Self); >>>> Field.Validate(Buffer); >>>> end; >>> >>> You are right in your dislike. >>> >>> I will create a 'BeforeSetFieldData' in TDataset and put the code >>> in there, >>> and the same for 'AfterSetFieldData' with the OnChange code. >>> >> OK, >> Then please do not forget commit necessary changes also in other >> descendants (not only in TCustomBufDataSet but also in TParadox, >> TMemDataset, TFixedFormatDataSet, TDbf) to completelly fix >> 'missing onvalidate call' problem. >> Thanks >> > I am still thinking about this. > I have other solution, which is relative simple , puts base logic > into base TField methods (so all TDataSet descendants can benefit > from it) and does not negatively affect existing TDataSet descendants > and does not require introduce new methods (BeforeSetFieldData, > AfterSetFieldData). > Let's distributes repeating used code as follows: > > 1. base checks "before" into procedure TField.SetData(Buffer: > Pointer; NativeFormat : Boolean); > > 820 begin > 821 If Not Assigned(FDataset) then > 822 DatabaseErrorFmt(SNoDataset,[FieldName]); > > if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) > then //here should be IMO also dsNewValue > DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet); > > if ReadOnly and (FieldNo>0) and not (FDataSet.State in > [dsSetKey, dsFilter]) then > DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self); > > 829 FDataSet.SetFieldData(Self,Buffer, NativeFormat); > -------------------------------------------------------------------------- > > > 2. into procedure TField.Validate(Buffer: Pointer); > > 892 begin > if FData S et.Statein[dsSetKey,dsFilter]thenExit893If > assigned(OnValidate) Then > > -------------------------------------------------------------------------- > > > 3. "after call" into procedure TDataSet.SetFieldData(Field: TField; > Buffer: Pointer); > begin > if not (State in [dsCalcFields, dsFilter, dsNewValue]) then > DataEvent(deFieldChange, Ptrint(Field)); > end; > > -------------------------------------------------------------------------- > > > And now all what we must do, is put into method SetFieldData in > TDataSet descendants one line: > > Field.Validate(Buffer); > and one line at end: > > inherited; //calls "field change" ... this is done by all TDataSet > descendants in fcl-db as a last thing > > > It is only draft, so some detils may be changed ... ;-) > What do you think ? > > Laco. > > ------------------------------------------------------------------------ _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Unknown author
to LacaK
LacaK wrote
Michael, do you plan do something else with this "OnValidate" problem ?

I thought I had done everything, or did I (again) forget something ?

Michael.

Show quoted text 110 lines
Thanks -Laco. > Hi, > here are diffs with changes, I hope they will be good for all TDataSet > descendants (those specific to FPC and also those which are also for use in > Delphi) > Code which is general (and is used repeatedly) is placed in TField methods > and only small code remains which must be placed into each TDataSet > descendant. > (I patched only TBufDataSet, but later can be updated also other TDataSet > descendants ... remove redundant code and add Field.Validate(...)) > Thanks > -Laco. > >> >>>>> The whole code, which is repeated (and can be put in one place) is: >>>>> >>>>> if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then >>>>> begin >>>>> DatabaseErrorFmt(SNotEditing,[Name],self); >>>>> exit; >>>>> end; >>>>> if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then >>>>> begin >>>>> if Read >>>>> OnlythenDatabaseErrorFmtSReadOnlyField,[Field.DisplayName], >>>>> Self); >>>>> Field.Validate(Buffer); >>>>> end; >>>> >>>> You are right in your dislike. >>>> >>>> I will create a 'BeforeSetFieldData' in TDataset and put the code in >>>> there, >>>> and the same for 'AfterSetFieldData' with the OnChange code. >>>> >>> OK, >>> Then please do not forget commit necessary changes also in other >>> descendants (not only in TCustomBufDataSet but also in TParadox, >>> TMemDataset, TFixedFormatDataSet, TDbf) to completelly fix 'missing >>> onvalidate call' problem. >>> Thanks >>> >> I am still thinking about this. >> I have other solution, which is relative simple , puts base logic into >> base TField methods (so all TDataSet descendants can benefit from it) and >> does not negatively affect existing TDataSet descendants and does not >> require introduce new methods (BeforeSetFieldData, AfterSetFieldData). >> Let's distributes repeating used code as follows: >> >> 1. base checks "before" into procedure TField.SetData(Buffer: Pointer; >> NativeFormat : Boolean); >> >> 820 begin >> 821 If Not Assigned(FDataset) then >> 822 DatabaseErrorFmt(SNoDataset,[FieldName]); >> >> if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then >> //here should be IMO also dsNewValue >> DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet); >> >> if ReadOnly and (FieldNo>0) and not (FDataSet.State in [dsSetKey, >> dsFilter]) then >> DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self); >> >> 829 FDataSet.SetFieldData(Self,Buffer, NativeFormat); >> -------------------------------------------------------------------------- >> >> 2. into procedure TField.Validate(Buffer: Pointer); >> >> 892 begin >> if FData S et.Statein[dsSetKey,dsFilter]thenExit893If >> assigned(OnValidate) Then >> >> -------------------------------------------------------------------------- >> >> 3. "after call" into procedure TDataSet.SetFieldData(Field: TField; >> Buffer: Pointer); >> begin >> if not (State in [dsCalcFields, dsFilter, dsNewValue]) then >> DataEvent(deFieldChange, Ptrint(Field)); >> end; >> >> -------------------------------------------------------------------------- >> >> And now all what we must do, is put into method SetFieldData in TDataSet >> descendants one line: >> >> Field.Validate(Buffer); >> and one line at end: >> >> inherited; //calls "field change" ... this is done by all TDataSet >> descendants in fcl-db as a last thing >> >> >> It is only draft, so some detils may be changed ... ;-) >> What do you think ? >> >> Laco. >> >> > > ------------------------------------------------------------------------ > > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

LacaK
to LacaK: here are diffs with changes, I hope they will be good for all TDataSet descendants (those…
>/ Michael,

/>>/ do you plan do something else with this "OnValidate" problem ? /

I thought I had done everything, or did I (again) forget something ?

There is IMHO unresolved original problem which is in fact, that some TDataSet descendants implement call to Field.Validate in descendant's SetFieldData (for example ZEOS in procedure TZAbstractRODataset.SetFieldData)

So if we leave call to Validate(Buffer) in TField.SetData ( http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/fcl-db/src/base/fields.inc?r1=17199&r2=17220 )

Then in case of these TDataSet descendants will Validate called twice. (once in TField.SetData and second in descendant's SetFieldData)

Please look at diff's which are attached in my email from 13.4.2011. (There are changes which we must/can do to fix it)

Thanks
-Laco.

Reply by email