web-dev-qa-db-ja.com

PostgreSQL:照合 'C'と 'C.UTF-8'の違い

PostgreSQLでは、照合順序CC.UTF-8の違いは何ですか?

どちらもpg_collationの行に表示されます。 C.UTF-8Cと同じで、UTF-8をエンコードした場合、またはデータベースの実際のエンコードが何であるかは、おそらく同じですか?

2
rookie099

PostgreSQLのドキュメントには、たくさんが残されています(ただ言うだけです)。

まず、特定のデータベースのエンコーディングは1つだけなので、UTF-8データベースのCC.UTF-8はどちらもUTF-8エンコーディングを使用しています。

libc照合の場合:通常、照合順序名は、慣例により、次の構造の真の2部構成の名前です。

{locale_name}.{encoding_name}

「ロケール」(つまり「文化」)は、並べ替え(LC_COLLATE)と大文字化(LC_CTYPE)に関する言語固有のルールのセットです。オーバーラップがある場合もありますが、これは実際にはこのデータの格納方法とは関係ありません。

「エンコーディング」とは、データの格納方法です(つまり、どのバイトシーケンスがどの文字に対応するか)。オーバーラップする場合もありますが、これは実際には、エンコーディングを使用する特定の言語のソートおよび大文字の規則とは何の関係もありません(一部のエンコーディングは、一方または両方でまったく異なる規則を持つ複数の言語で使用できます)それらの領域)。

説明のために、韓国語のデータの保存を検討してください。

  • ko_KRはロケールです。
  • このロケールで機能する可能なエンコーディングは次のとおりです。
    • EUC_KR(拡張UNIX Code-KR)
    • JOHAB
    • UHC(統一ハングルコード/ Windows949)
    • UTF8(Unicodeの8ビットエンコーディング)

また、「 照合サポート:libc collat​​ions 」のドキュメントからの次の点も考慮してください(強調を追加):

たとえば、オペレーティングシステムはde_DE.utf8という名前のロケールを提供する場合があります。 initdbは、de_DE.utf8をエンコードするためにUTF8という名前の照合を作成します。また、.utf8タグを名前から削除して照合を作成します。そのため、de_DEという名前の照合順序を使用することもできます。これにより、記述が簡単になり、名前がエンコードに依存しなくなります...

...

特定のデータベース内では、そのデータベースのエンコーディングを使用する照合のみが対象です。 pg_collationの他のエントリは無視されます。したがって、de_DEなどの除去された照合名は、グローバルに一意でなくても、特定のデータベース内で一意と見なすことができます。別のデータベースエンコーディングに変更する場合、変更する必要のあるものが1つ少なくなるため、ストリップされた照合名を使用することをお勧めします。 ただし、defaultC、およびPOSIXの照合順序は、データベースのエンコーディングに関係なく使用できます。

つまり、UTF-8エンコーディングを使用するデータベースでは、en_USen_US.UTF8は同等です。しかし、そのデータベースとLATIN1エンコーディングを使用するデータベースの間では、en_US照合順序はと同等ではありません

では、これはCC.UTF-8が同じであることを意味しますか?

いいえ、それは簡単すぎるでしょう!!!C照合は、上記の動作の例外です。 C照合順序は、データベースのエンコーディングに関係なく使用できる単純なルールのセットであり、動作はエンコーディング全体で一貫している必要があります(これは、米国英語のアルファベット「az」と「AZ」のみを認識することによって可能になります) "—"文字 "として、およびバイト値によるソート。これは、使用可能なエンコーディングで同じでなければなりません)。

C.UTF-8照合は、基本のCルールと比較して、実際にはわずかに拡張された一連のルールです。 collcollate列とcollctype列の値はCpg_collationの行の間で異なるため、この違いは実際にC.UTF-8で確認できます。

en_GB(および暗黙的にen_GB.utf8)と比較して、これらの2つの照合の類似点と相違点の一部を示すために、一連のテストクエリをまとめました。私は DanielVérité's 回答で提供されるクエリから始め、表示されているものと表示されていないものについてより明確になるように拡張し、いくつかのクエリを追加しました。結果は次のことを示しています。

  1. C.UTF-8(最終クエリ)のC列とcollcollate列のそれぞれの値に基づいて、わずかに異なる場合でも、collctypepg_collationは実際には異なるルールのセットです
  2. C.UTF-8は、「文字」と見なされる文字を展開します
  3. C.UTF-8は、Cen_GBと同様)とは異なり、無効なUnicodeコードポイント(U + 0378など)を認識し、上に向かってソートします
  4. C.UTF-8は、Cのように(ただし、en_GBとは異なり)、米国英語以外の文字をコードポイントでソートします。
  5. ucs_basicC(ドキュメントに記載されている)と同等のようです。

次のクエリを検索して実行できます。 db <> fiddle

4
Solomon Rutzky

C.UTF-8がUTF-8をエンコードしたCと同じである可能性はありますか

いいえ。たとえば、Debian 10 Linuxでは、UTF-8データベースにおける次の違いを考慮してください。

postgres=# select upper('é' collate "C"), upper('é' collate "C.UTF-8");
 upper | upper 
-------+-------
 é     | É
(1 row)

postgres=# select ('A' < E'\u0378' collate "C"),
                  ('A' < E'\u0378' collate "C.UTF-8");
 ?column? | ?column? 
----------+----------
 t        | f
(1 row)

(U + 0378はUnicodeの有効な文字に対応していません)。

有効なUnicode文字を使用した別の例(左側は 'THUMBS UP SIGN' U + 1F44D です):

=> select '????' < 'A' collate "C";
 ?column? 
----------
 f
(1 row)

=> select '????' < 'A' collate "C.UTF-8";
 ?column? 
----------
 t
(1 row)

lc_collateが "C"(または "POSIX")の場合、比較はPostgreSQLによって内部的に行われます。その場合、memcmpを使用して文字列のバイト表現を比較します。

Libcがプロバイダー(collprovider='c'pg_collation)である他の場合、比較はCライブラリの strcoll_l によって行われるため、PostgreSQL自体は結果に責任があり、上記の反例で示されているように、同じであると信じる理由はありません。

これは、少なくともlibcがサポートする照合に当てはまります。 Postgresバージョン10以降、ICU照合が使用される場合があります。これらの照合はオペレーティングシステム全体で一貫しています。

悲惨な詳細は backend/utils/adtvarlena.c のソースコード、特にvarstrmp_cmp関数にあります。

4
Daniel Vérité

Postgresqlのドキュメントから https://www.postgresql.org/docs/11/collat​​ion.html

23.2.2.1。標準照合

すべてのプラットフォームで、default、C、およびPOSIXという名前の照合が使用可能です。オペレーティングシステムのサポートによっては、追加の照合が使用できる場合があります。デフォルトの照合では、データベースの作成時に指定されたLC_COLLATEおよびLC_CTYPE値が選択されます。 CとPOSIXの照合順序はどちらも「従来のC」の動作を指定し、ASCII文字「A」から「Z」のみが文字として扱われ、文字コードのバイト値によって厳密にソートされます。 。

さらに、SQL標準照合名ucs_basicをUTF8のエンコードに使用できます。これはCに相当し、Unicodeコードポイントで並べ替えます。

したがって、私の理解が正しければ、CはUTF8ではなくASCIIです。

1