Client encoding is specified in TZConnection.properties such as "codepage=big5". It is then parsed and converted by Create(), and saved as FClientCodePage in ZDbcPostgreSql.pas. Such design works but it has the following flaws:
(1) After connected to PostgreSQL, users can send "SET CLIENT_ENCODING TO 'sql_ascii'" directly to PostgreSQL and assume that zeoslib has switched accordingly. However, this is not the case - zeoslib is not aware of the changes made this way. More specifically, pg_CS_stat() in ZDbcPostgreSqlUtils.pas always take the outdated value of FClientCodePage as its argument.
(2) Similarly, users might resetting "codepage" in TZConnection.Properties after TZConnection is connected and have the wrong expectation on zeoslib.
The existing implementation requires users to reset TZConnection.Properties and disconnect and connect back in order to force the switch of codepage to really happen. The "disconnect -reset properties - connect" cycle is very inefficient, especially in the cases where the connection provides multiple client services.
As such, I recommend the following improvements:
(1) Remove codepage from TZConnection.Properties.
(2) Remove the following code
Code: Select all
{ Sets a client codepage. }
if FClientCodePage <> '' then
begin
SQL := PChar(Format('SET CLIENT_ENCODING TO ''%s''', [FClientCodePage]));
QueryHandle := FPlainDriver.ExecuteQuery(FHandle, SQL);
CheckPostgreSQLError(nil, FPlainDriver, FHandle, lcExecute, SQL,QueryHandle);
FPlainDriver.Clear(QueryHandle);
DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL);
end;
Code: Select all
procedure TZPostgreSQLConnection.Open;
Code: Select all
procedure SetClientEncoding(const ClientEncoding : string)
Code: Select all
FClientCodePage := Trim(Info.Values['codepage']);
FCharactersetCode := pg_CS_code(FClientCodePage);
// DriverManager.LogError(lcOther,'','Create',Integer(FCharactersetCode),'');
Code: Select all
constructor TZPostgreSQLConnection.Create
(3) Add public property "CodePage" in TZConnection. Any time this property is changed by users,
Code: Select all
procedure SetClientEncoding(const ClientEncoding : string)
(a) Resets
Code: Select all
FCharactersetCode
Code: Select all
pg_CS_stat()
(b) Sends SQL
Code: Select all
SET CLIENT_ENCODING TO '<codepage>'
Making the improvement should not be too difficult. In fact I just did yesterday, but I failed because I have limited skill of Pascal. Although I can code
Code: Select all
procedure SetClientEncoding(const ClientEncoding : string)
Code: Select all
CodePage
Hopefully there are people with better Delphi skills than myself will improve this design?
Regards,
CN