Zeos + UTF8 + TWideStringField
Posted: 03.02.2015, 12:43
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:
I think that the culprit is the function GetFieldSize in ZDbcUtils.pas:
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
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:
because TWidceStringField inherits from TStringField.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.
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;
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