[Lazarus] TDBEdit, TStringField Size, DataSize, DisplayWidth and MaxLength
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;
> if DataSize <= dsMaxStringSize then
> Buf[Size]:=#0; //limit string to Size
> If Result then
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
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
> 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 ...
More information about the Lazarus