Zeos で Firebird のシステムテーブル (RDB$) を操作する場合には、ClientCharSet を 'NONE' にしなければならない事があります。
例えば RDB$FUNCTIONS テーブルは以下のようになっています。
No. 名前 型 文字コード 1 RDB$FUNCTION_NAME (RDB$FUNCTION_NAME) CHAR(31) CHARACTER SET UNICODE_FSS 2 RDB$FUNCTION_TYPE (RDB$FUNCTION_TYPE) SMALLINT 3 RDB$QUERY_NAME (RDB$FIELD_NAME) CHAR(31) CHARACTER SET UNICODE_FSS 4 RDB$DESCRIPTION (RDB$DESCRIPTION) BLOB CHARACTER SET UNICODE_FSS 5 RDB$MODULE_NAME (RDB$FILE_NAME) VARCHAR(255) 6 RDB$ENTRYPOINT (RDB$EXTERNAL_NAME) CHAR(31) 7 RDB$RETURN_ARGUMENT (RDB$FIELD_POSITION) SMALLINT 8 RDB$SYSTEM_FLAG (RDB$SYSTEM_FLAG) SMALLINT
普通、システムテーブルのフィールドは UNICODE_FSS の VARCHAR で構成されていますが、RDB$ENTRYPOINT は 型が CHAR() で、RDB$MODULE_NAME と RDB$ENTRYPOINT の文字コードは何故か NONE です。
これの何がマズいかを ClientCharSet = UTF8 の場合で考えてみます。RDB$FUNCTION_NAME 等は文字コードが UNICODE_FSS なので、読みだした時には UNICODE_FSS -> UTF8 変換が行われて正常に値を読みだせます。問題は NONE です。NONE フィールドは ClientCharSet = UTF8 なので無理矢理 UTF-8 で読みだされます。
この時、NONE フィールドの 1 文字構成バイトは 1 なのですが、UTF8 は 4 なので、CHAR(31) のフィールドは 31 / 4 = 7 となり、7文字で切り詰められてしまいます。
おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos
おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos
おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos, おのれ Zeos
この件を回避するには、システムテーブルを操作する場合には ClientCharSet を 'NONE' に変更します。Zeos は ClientCharSet = NONE の場合、内部的な文字コード変換を行いません。そしてシステムテーブルの操作が終わったら ClientCharSet を元に戻しておきます。
この件に関してですが BLOB で読み込んだり AsBytes で読んでも結果は変わりません。フィールドにアクセスした時点で内部的な文字コード変換は終わっているからです。CAST() も考えてみましたが、確か文字コード変換のために使う事はできなかったと思います (少なくとも Firebird の全バージョンで使える方法はなかったように記憶しています)。NONE を AsBytes で読んだ時は生データ (バイナリ) を返して欲しいのですが…。
システムテーブルの (少なくとも CHAR 型の) NONE だけは ClientCharSet をデフォルトとみなして変換してはいけないのです。普通のテーブルのデータは変換しても問題ないと思いますけれど。
|