9

postgresupper/lower関数がトルコ語文字セットの選択文字を処理していないようです。

select upper('Aaı'), lower('Aaİ') from mytable;

戻り値 :

AAı, aaİ

それ以外の :

AAI, aai

通常の英語の文字は正しく変換されますが、トルコ語の I (小文字または大文字) は変換されないことに注意してください。

Postgres バージョン:9.2 32 bit

データベースのエンコード (これらのいずれでも同じ結果):UTF-8, WIN1254, C

クライアントのエンコーディング:

 UTF-8, WIN1254, C

OS:Windows 7 enterprise edition 64bit

SQL 関数は、UTF-8 でエンコードされたデータベースの ı と İ に対して次の同じバイトを返しますlowerupper

\xc4b1    
\xc4b0   

そして、WIN1254 (トルコ語) でエンコードされたデータベースでは次のようになります。

\xfd      
\xdd     

私の調査が間違っていることを願っています。

4

4 に答える 4

10

あなたの問題100% Windows です。 (より正確に言うと、PostgreSQL が構築された Microsoft Visual Studio です。)

記録のために、SQLはほとんどすべての適切なパラメーター ( -encoded、データベースのロケール 1055 トルコ語) を使用して( via経由で) UPPERWindows を呼び出すことになります。LCMapStringWtowupperstr_toupperUTF-8Turkish_Turkey

しかし

Visual Studio Runtime( ) はdwMapFlagsにビットをtowupper設定しませ。(設定でうまくいくことを確認できます。) これは Microsoft ではバグとは見なされていません。これは設計によるものであり、おそらく「修正」されることはありません(ああ、レガシーの喜びです)。LCMAP_LINGUISTIC_CASINGLCMapStringW

これには 3 つの方法があります。

  • @Sorrow のラッパー ソリューションを実装します (または、独自のネイティブ関数置換 (DLL) を記述します)。
  • たとえば、チュルク語ロケールで正しい動作を示すUbuntuでPostgreSQLインスタンスを実行します(@Sorrowは、それが彼のために機能することを確認しました)。これはおそらく最も簡単でクリーンな方法です。
  • PostgreSQLディレクトリにパッチを適用した 32 ビットMSVCR100.DLLをドロップしますbin(ただしUPPERLOWER動作することもありますが、照合などの他の処理は引き続き失敗する可能性があります。これも Windows レベルです。YMMV.)

完全を期すために(そしてノスタルジックな楽しみのために)のみ、Windows システムにパッチを適用する手順を次に示します (ただし、この PostgreSQL インスタンスをゆりかごから墓場まで管理しない限り、後継者に多くの悲しみをもたらす可能性があることを忘れないでください。新しいテスト システムまたはバックアップ システムを最初から展開する場合、あなたまたはあなたの後継者は、パッチを再度適用することを覚えておく必要があります。たとえば、PostgreSQL 10 にアップグレードするとしMSVCR120.DLLますMSVCR100.DLL。新しい DLL にパッチを適用して運試しをすることもできます。) テスト システムで

  • HxDを使用して開くC:\WINDOWS\SYSTEM32\MSVCR100.DLL
  • すぐに DLL を同じ名前で PostgreSQLbinディレクトリに保存します (エクスプローラーまたはコマンド ラインを使用してファイルをコピーしようとしないでください。64 ビット バージョンがコピーされる可能性があります)。
  • ファイルを HxD で開いたままにして、Search > Replaceに移動し、 Datatype: Hexvaluesを選択してから、
    • 検索する......4E 14 33 DB 3B CB 0F 84 41 12 00 00 B8 00 01 00 00
    • と置換する...4E 14 33 DB 3B CB 0F 84 41 12 00 00 B8 00 01 00 01
    • …それからもう一度…
    • 検索する......FC 51 6A 01 8D 4D 08 51 68 00 02 00 00 50 E8 E2
    • と置換する...FC 51 6A 01 8D 4D 08 51 68 00 02 00 01 50 E8 E2
  • bin...そして PostgreSQLディレクトリに 再保存し、PostgreSQLを再起動してクエリを再実行します。
    • クエリがまだ機能しない場合 (データベースが とTurkish_Turkeyの両方LC_CTYPEでUTF-8 エンコードされていることを確認してください) 32 ビット Dependency WalkerLC_COLLATEで開きpostgres.exe、PostgreSQLディレクトリからロードされることを示していることを確認してください。MSVCR100.DLLbin
    • すべての機能が正常に機能する場合は、パッチを適用した DLL を本番の PostgreSQLbinディレクトリにコピーして再起動します。

ただし、データを Ubuntu システムから、またはパッチが適用された Windows システムからパッチが適用されていない Windows システムに移動すると、再び問題が発生し、Windows インスタンスが重複を導入した場合、このデータを Ubuntu にインポートできなくなる可能性があることを忘れないでください。citextフィールドまたはUPPER/ベースのLOWER関数インデックス内。

于 2012-11-04T10:03:49.350 に答える
4

あなたの問題はWindowsに関連しているようです。これは、Ubuntu (Postgres 8.4.14)、UTF-8 でエンコードされたデータベースでどのように見えるかです。

test=# select upper('Aaı'), lower('Aaİ');
 upper | lower
-------+-------
 AAI   | aai
(1 row)

Windows を使用する必要がある場合は、変換を行うストアド プロシージャを作成することをお勧めします。組み込みのreplace:を使用しreplace('abcdefabcdef', 'cd', 'XX')ますabXXefabXXef。もっと最適な解決策があるかもしれませんが、このアプローチが正しいとは言いません。

于 2012-11-01T06:58:44.710 に答える
1

これは確かに PostgreSQL のバグです (現在の git ツリーでもまだ修正されていません)。証明: https://github.com/postgres/postgres/blob/master/src/port/pgstrcasecmp.c

PostgreSQL の開発者は、トルコ語の文字について具体的に言及しています。

SQL99 では Unicode 対応の大文字と小文字の正規化が指定されていますが、これに対するインフラストラクチャはまだありません。代わりに tolower() を使用して、ロケールを認識した翻訳を提供します。ただし、これが正しくないロケールもあります (たとえば、トルコ語では 'i' と 'I' でおかしな動作をする場合があります)。 現在の妥協点は、上位ビットが設定された文字には tolower() を使用し、7 ビット文字には ASCII のみの小文字化を使用することです。

pg_upper()このファイルに実装されているのは非常に単純化されています (そのコンパニオンとしてpg_tolower()):

unsigned char
pg_toupper(unsigned char ch)
{
    if (ch >= 'a' && ch <= 'z')
            ch += 'A' - 'a';
    else if (IS_HIGHBIT_SET(ch) && islower(ch))
            ch = toupper(ch);
    return ch;
}

ご覧のとおり、このコードはそのパラメーターを Unicode コード ポイントとして処理せず、現在選択されているロケールがたまたま (トルコ語の非 Unicode ロケールなど) 私たちが気にかけているものであり、OS が提供するものでない限り、100% 正しく動作することはできません。非ユニコードtoupper()は正しく機能しています。

これは本当に悲しいことです。これが今後の PostgreSQL リリースで解決されることを願っています...

于 2012-11-01T07:44:26.067 に答える