PostgreSQLでは、照合順序C
とC.UTF-8
の違いは何ですか?
どちらもpg_collation
の行に表示されます。 C.UTF-8
がC
と同じで、UTF-8
をエンコードした場合、またはデータベースの実際のエンコードが何であるかは、おそらく同じですか?
PostgreSQLのドキュメントには、たくさんが残されています(ただ言うだけです)。
まず、特定のデータベースのエンコーディングは1つだけなので、UTF-8データベースのC
とC.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 collations 」のドキュメントからの次の点も考慮してください(強調を追加):
たとえば、オペレーティングシステムは
de_DE.utf8
という名前のロケールを提供する場合があります。initdb
は、de_DE.utf8
をエンコードするためにUTF8
という名前の照合を作成します。また、.utf8
タグを名前から削除して照合を作成します。そのため、de_DE
という名前の照合順序を使用することもできます。これにより、記述が簡単になり、名前がエンコードに依存しなくなります......
特定のデータベース内では、そのデータベースのエンコーディングを使用する照合のみが対象です。
pg_collation
の他のエントリは無視されます。したがって、de_DE
などの除去された照合名は、グローバルに一意でなくても、特定のデータベース内で一意と見なすことができます。別のデータベースエンコーディングに変更する場合、変更する必要のあるものが1つ少なくなるため、ストリップされた照合名を使用することをお勧めします。 ただし、default
、C
、およびPOSIX
の照合順序は、データベースのエンコーディングに関係なく使用できます。
つまり、UTF-8エンコーディングを使用するデータベースでは、en_US
とen_US.UTF8
は同等です。しかし、そのデータベースとLATIN1
エンコーディングを使用するデータベースの間では、en_US
照合順序はと同等ではありません。
では、これはC
とC.UTF-8
が同じであることを意味しますか?
いいえ、それは簡単すぎるでしょう!!!C
照合は、上記の動作の例外です。 C
照合順序は、データベースのエンコーディングに関係なく使用できる単純なルールのセットであり、動作はエンコーディング全体で一貫している必要があります(これは、米国英語のアルファベット「az」と「AZ」のみを認識することによって可能になります) "—"文字 "として、およびバイト値によるソート。これは、使用可能なエンコーディングで同じでなければなりません)。
C.UTF-8
照合は、基本のC
ルールと比較して、実際にはわずかに拡張された一連のルールです。 collcollate
列とcollctype
列の値はC
とpg_collation
の行の間で異なるため、この違いは実際にC.UTF-8
で確認できます。
en_GB
(および暗黙的にen_GB.utf8
)と比較して、これらの2つの照合の類似点と相違点の一部を示すために、一連のテストクエリをまとめました。私は DanielVérité's 回答で提供されるクエリから始め、表示されているものと表示されていないものについてより明確になるように拡張し、いくつかのクエリを追加しました。結果は次のことを示しています。
C.UTF-8
(最終クエリ)のC
列とcollcollate
列のそれぞれの値に基づいて、わずかに異なる場合でも、collctype
とpg_collation
は実際には異なるルールのセットですC.UTF-8
は、「文字」と見なされる文字を展開しますC.UTF-8
は、C
(en_GB
と同様)とは異なり、無効なUnicodeコードポイント(U + 0378など)を認識し、上に向かってソートしますC.UTF-8
は、C
のように(ただし、en_GB
とは異なり)、米国英語以外の文字をコードポイントでソートします。ucs_basic
はC
(ドキュメントに記載されている)と同等のようです。次のクエリを検索して実行できます。 db <> fiddle
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
関数にあります。
Postgresqlのドキュメントから https://www.postgresql.org/docs/11/collation.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です。