Page 1 of 1

Switching client encoding

Posted: 04.11.2011, 08:39
by cnliou
Hi!

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;
from

Code: Select all

procedure TZPostgreSQLConnection.Open;
and use it as a base to create a new procedure

Code: Select all

procedure SetClientEncoding(const ClientEncoding : string)
Also remove:

Code: Select all

 FClientCodePage := Trim(Info.Values['codepage']);
  FCharactersetCode := pg_CS_code(FClientCodePage);
//  DriverManager.LogError(lcOther,'','Create',Integer(FCharactersetCode),'');
from

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)
is called accordingly, which does two tasks:

(a) Resets

Code: Select all

FCharactersetCode
for

Code: Select all

pg_CS_stat()
.

(b) Sends SQL

Code: Select all

SET CLIENT_ENCODING TO '<codepage>'
to PostgreSQL.

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)
in ZDbcPostgreSql.pas but I do not know how to export this procedure and the property

Code: Select all

CodePage
to TZConnection component.

Hopefully there are people with better Delphi skills than myself will improve this design?

Regards,
CN

Posted: 08.11.2011, 15:11
by cnliou
I have fixed the issue and uploaded the patch to:

http://zeos.firmos.at/viewtopic.php?p=13813#13813

Hopefully the patch will be accepted and manually patched by some good soul :)

Posted: 08.11.2011, 22:23
by mdaems
cnliou,
What about getting SVN commit rights? All I need is your sourceforge user name ;) But adding cnliou to the project members works, so I suppose that's not difficult to guess. But would you appreciate and use it?

Mark