[Lazarus] TDBEdit, TStringField Size, DataSize, DisplayWidth and MaxLength

LacaK lacak at zoznam.sk
Tue Oct 11 15:32:03 CEST 2016


> An IBX user came to me with a problem and the problem seems to be a 
> deep seated disconnect between multi-byte character sets, 
> TStringField.Size and TDBEdit.MaxLength. Something needs to give - but 
> I am not sure what should.
>
> Firstly documentation:
>
> If you go back to Delphi, TField.DataSize is the memory needed to hold 
> the Field's value. The DisplayWidth is the number of characters to be 
> displayed, and Size is, for datatype ftstring, "the maximum number of 
> characters in the string".
Right. TStringField.Size is size of characters, not bytes

> How literally this last definition should be taken, I'm not sure, as 
> it may well have been written assuming a single byte character set.
>
> On the other hand, the FPC documentation is consistent with Delphi for 
> DisplayWidth and DataSize, but more opaque for TField.Size where it is 
> the "logical size" - whatever that means, although TStringField is 
> more definitive by saying it is the maximum size (in characters) - 
> their brackets not mine.
>
> That seems to be consistent with TDBEdit.Maxlength which should be the 
> maximum number of characters that can appear in the control and, if 
> you look at the code, TDBEdit will source the default value from 
> FDatalink.Size (And also seems to ignore DisplayWidth).
TDBEdit.MaxLength must correspond to TStringField.Size

>
> The problem comes when you look at the code for TStringField.GetValue, 
> where it starts off as:
>
> function TStringField.GetValue(var AValue: string): Boolean;
>
> var Buf, TBuf : TStringFieldBuffer;
>     DynBuf, TDynBuf : Array of char;
>
> begin
>   if DataSize <= dsMaxStringSize then
>     begin
>     Result:=GetData(@Buf);
>     Buf[Size]:=#0;  //limit string to Size
>     If Result then
>       begin
> ...
Look at TRUNK, there is already changed code, which takes DataSize ;-)

>
> If nothing else, this is a "bug in waiting". TStringField.GetDataSize 
> always returns "Size+1", so "Buff[Size]:=#0; should work - but only as 
> long as the virtual method "GetDataSize" is not overridden (GetValue 
> is non-virtual) and Size is the byte length of the string!
in TRUNK is GetDataSize changed also, it takes into account Fields 
CharSet and for UTF8 returns 4*Size+1

>
> There is a built-in assumption here that "Size" is the byte length of 
> the string and not the character length.
this assumption came from old Delphi days, where it was so for SBCS

> If you have a multi-byte character set and set size to the number of 
> characters and DataSize to e.g. for UTF8 4*(no of characters)+1, then 
> you will get string corruption as a result of the above.

>
> IBX handles multi-byte character sets and does so by defining 
> TIBStringField as a subclass of TStringFIeld and setting size to the 
> byte length and the Default DisplayWidth to the character width. This 
> is compatible with TStringField as it works today. It also seems to be 
> compatible with TDBGrid, which uses Field.DisplayWidth. However, it 
> does result in TDBEdit accepting too many characters.
>
> What should be done?
>
> It's a problem. Ideally, the TStringField code should be aligned with 
> the documentation. However, that could break existing code and would 
> need to handled carefully. TStringFIeld also needs fixing i.e. to 
> Buf[DataSize-1]:=#0 in order to make this a reality.
Size must be character size (used for visual components if they handle 
characters)
DataSize must be byte size (used for record buffers to store character data)

>
> Alternatively, the documentation could be amended to reflect the 
> implementation. This means that TDBEdit (and maybe more) have to be 
> updated - but why doesn't TDBEdit respect the DisplayWidth property 
> anyway?
>
> Perhaps, it is also about time that TStringField got a characterWidth 
> property to hold the maximum number of bytes for each character. That 
> would at least allow the DataSize to be automatically computed from 
> the character width.
There is new TFieldDef.CharSize which says how many bytes is one character

>
> If I had to write a bug report today, I would write it to avoid 
> changes to IBX - but then is that the right answer?
Please look at changes in TRUNK.
May be that not all is perfect, but you will see there direction ...

-Laco.



More information about the Lazarus mailing list