Zeos + UTF8 + TWideStringField

The official tester's forum for ZeosLib 7.1. Ask for help, post proposals or solutions.
Post Reply
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1956
Joined: 17.01.2011, 14:17

Zeos + UTF8 + TWideStringField

Post by marsupilami »

Hello,

recently I started developing my first applications with Unicode Delphi (XE7) and wanted to use Unicode Databeses as well (Firebird / PostgreSQL). When selecting Fields and using UTF8 as the connection character set, Zeos will generate TWideStringFields for varchar(x)-columns. For some reason Zeos will set the Size property of these columns to 2 * x. But it really should be x. I observed this behaviour for Firebird as well as for PostgreSQL.
Unfortunately the Delphi Documentation is not very good at this point because if one clicks on the size property for TWideStringField this will lead to a page that says that the size Property does not matter at all which is wrong too.
I compared to the way TADOQuery works for these fields and TADOQuery also uses TWideStringField but with the size property set to x and not to 2 * x. Also the FPC documentation for TWideStringField says:
Size is made published by the TStringField class so it can be set in the IDE: it is the declared maximum size of the string (in characters) and is used to calculate the size of the dataset buffer.
because TWidceStringField inherits from TStringField.

I think that the culprit is the function GetFieldSize in ZDbcUtils.pas:

Code: Select all

function GetFieldSize(const SQLType: TZSQLType; ConSettings: PZConSettings;
  const Precision, CharWidth: Integer; DisplaySize: PInteger = nil;
    SizeInBytes: Boolean = False): Integer;
var
  TempPrecision: Integer;
begin
  if ( SQLType in [stString, stUnicodeString] ) and ( Precision <> 0 )then
  begin
    if SizeInBytes then
      TempPrecision := Precision div CharWidth
    else
      TempPrecision := Precision;

    if Assigned(DisplaySize) then
      DisplaySize^ := TempPrecision;

    if SQLType = stString then
      //the RowAccessor assumes SizeOf(Char)*Precision+SizeOf(Char)
      //the Field assumes Precision*SizeOf(Char)
      {$IFDEF UNICODE}
      if ConSettings^.ClientCodePage^.CharWidth >= 2 then //All others > 3 are UTF8
        Result := TempPrecision shl 1 //add more mem for a reserved thirt byte
      else //two and one byte AnsiChars are one WideChar
        Result := TempPrecision
      {$ELSE}
        if ( ConSettings^.CPType = cCP_UTF8 ) or (ConSettings^.CTRL_CP = zCP_UTF8) then
          Result := TempPrecision shl 2 // = *4
        else
          Result := TempPrecision * CharWidth
      {$ENDIF}
    else //stUnicodeString
      //UTF8 can pickup LittleEndian/BigEndian 4 Byte Chars
      //the RowAccessor assumes 2*Precision+2!
      //the Field assumes 2*Precision ??Does it?
      if CharWidth > 2 then
        Result := TempPrecision shl 1
      else
        Result := TempPrecision;
  end
  else
    Result := Precision;
end;
because it returns Result := TempPrecision shl 1 if the character width is more than 1 byte per character. For me it would be easy to change this behaviour here. But I am not sure what impact this would have on TZRowAccessor because of the comment above the code line that determines teh result?

Can anybody help me on this to know how the TZRowAccessor interacts with TWideStringFields and to find out what kind of impact changing this code would have on the RowAccessor?

Best regards,

Jan
Post Reply