Dans PostgreSQL, quelle est la différence entre les classements C
et C.UTF-8
?
Les deux apparaissent dans des rangées de pg_collation
. Est-il possible que C.UTF-8
est identique à C
avec l'encodage UTF-8
indépendamment ou quel est l'encodage réel d'une base de données?
La documentation PostgreSQL laisse beaucoup à désirer (juste dire in).
Pour commencer, il n'y a qu'un seul encodage pour une base de données particulière, donc C
et C.UTF-8
dans votre base de données UTF-8 utilisent tous les deux le codage UTF-8.
Pour libc classements: généralement les noms de classement, par convention, sont vraiment des noms en deux parties de la structure suivante:
{locale_name}.{encoding_name}
Une "locale" (c'est-à-dire une "culture") est l'ensemble de règles spécifiques au langage pour le tri (LC_COLLATE
) et la capitalisation (LC_CTYPE
). Même s'il y a parfois chevauchement, cela n'a vraiment rien à voir avec la façon dont ces données sont stockées.
Un "codage" est la façon dont les données sont stockées (c'est-à-dire quelle séquence d'octets équivaut à quel caractère). Même s'il y a parfois chevauchement, cela n'a vraiment rien à voir avec les règles de tri et de mise en majuscules d'une langue particulière qui utilise l'encodage (certains encodages peuvent être utilisés par plusieurs langues qui peuvent avoir des règles très différentes dans l'un ou les deux). ces zones).
Pour illustrer, envisagez de stocker des données coréennes:
ko_KR
est la locale.EUC_KR
(Code UNIX étendu-KR)JOHAB
UHC
(Code Hangul Unifié/Windows949)UTF8
(Codage 8 bits d'Unicode)Tenez également compte des éléments suivants, extraits de la documentation " Collation Support: libc collations " (non souligné dans l'original):
Par exemple, le système d'exploitation peut fournir un environnement local nommé
de_DE.utf8
.initdb
créerait alors un classement nomméde_DE.utf8
pour l'encodageUTF8
... Il créera également un classement avec le.utf8
tag rayé du nom. Vous pouvez donc également utiliser le classement sous le nomde_DE
, ce qui est moins lourd à écrire et rend le nom moins dépendant de l'encodage ......
Dans une base de données particulière, seuls les classements qui utilisent l'encodage de cette base de données sont intéressants. Autres entrées dans
pg_collation
sont ignorés. Ainsi, un nom de classement supprimé tel quede_DE
peut être considéré comme unique dans une base de données donnée même s'il ne le serait pas à l'échelle mondiale. L'utilisation des noms de classement supprimés est recommandée, car cela fera une chose de moins à modifier si vous décidez de passer à un autre encodage de base de données. Notez cependant que les classementsdefault
,C
etPOSIX
peuvent être utilisés quel que soit l'encodage de la base de données.
Ce qui signifie, dans une base de données qui utilise le codage UTF-8, en_US
et en_US.UTF8
sont équivalents. MAIS, entre cette base de données et une base de données qui utilise le LATIN1
encodage, le en_US
les classements sont pas équivalents.
Donc, cela signifie-t-il que C
et C.UTF-8
sont identiques?
NON, ce serait trop facile !!! Le classement C
est une exception au comportement indiqué ci-dessus. Le classement C
est un ensemble simple de règles disponibles quel que soit le codage de la base de données, et le comportement doit être cohérent entre les codages (ce qui est rendu possible en reconnaissant uniquement l'alphabet anglais américain - "az" et "AZ "- sous forme de" lettres ", et tri par valeur d'octet, qui devrait être le même pour les encodages disponibles).
Le C.UTF-8
le classement est en fait un ensemble de règles légèrement amélioré, par rapport aux règles de base C
. Cette différence est en fait visible dans pg_collation
car les valeurs des colonnes collcollate
et collctype
sont différentes entre les lignes pour C
et C.UTF-8
.
J'ai rassemblé un ensemble de requêtes de test pour illustrer certaines des similitudes et des différences entre ces deux classements, ainsi que par rapport à en_GB
(et implicitement en_GB.utf8
). J'ai commencé avec les requêtes fournies dans la réponse de Daniel Vérité , je les ai améliorées pour, espérons-le, être plus claires sur ce qui est et ce qui n'est pas affiché, et j'ai ajouté quelques requêtes. Les résultats nous montrent que:
C
et C.UTF-8
sont en réalité des ensembles de règles différents, même s'ils ne sont que légèrement différents, en fonction de leurs valeurs respectives dans les colonnes collcollate
et collctype
dans pg_collation
(dernière requête)C.UTF-8
agrandit les caractères considérés comme des "lettres"C.UTF-8
, contrairement à C
(mais comme en_GB
), reconnaît les points de code Unicode non valides (c'est-à-dire U + 0378) et les trie vers le hautC.UTF-8
, comme C
(mais contrairement à en_GB
), trie les caractères non américains en anglais par point de codeucs_basic
semble être équivalent à C
(qui est indiqué dans la documentation)Vous pouvez rechercher et exécuter les requêtes sur: db <> fiddle
Est-ce peut-être le cas que C.UTF-8 est le même que C avec le codage UTF-8
Considérez par exemple ces différences dans une base de données UTF-8, sur Debian 10 Linux:
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 ne correspond à aucun caractère valide dans Unicode).
Un autre exemple avec un caractère Unicode valide (le côté gauche est 'THUMBS UP SIGN' U + 1F44D ):
=> select '????' < 'A' collate "C";
?column?
----------
f
(1 row)
=> select '????' < 'A' collate "C.UTF-8";
?column?
----------
t
(1 row)
Quand lc_collate
est "C" (ou "POSIX"), la comparaison est effectuée en interne par PostgreSQL. Dans ce cas, il compare les représentations d'octets des chaînes en utilisant memcmp
.
Dans les autres cas où libc est le fournisseur (collprovider='c'
dans pg_collation
), la comparaison se fait par strcoll_l
de la bibliothèque C, donc PostgreSQL lui-même n'est pas responsable du résultat et, comme le montrent les contre-exemples ci-dessus, il n'y a aucune raison de croire qu'il sera identique.
C'est vrai au moins pour les classements soutenus par libc. À partir de Postgres version 10, les classements ICU peuvent être utilisés. Ces classements sont cohérents sur tous les systèmes d'exploitation.
Les détails sanglants peuvent être trouvés dans le code source dans backend/utils/adtvarlena.c , en particulier le varstrmp_cmp
une fonction.
De la documentation postgresql, https://www.postgresql.org/docs/11/collation.html :
23.2.2.1. Classements standard
Sur toutes les plateformes, les classements nommés par défaut, C et POSIX sont disponibles. Des classements supplémentaires peuvent être disponibles en fonction de la prise en charge du système d'exploitation. Le classement par défaut sélectionne les valeurs LC_COLLATE et LC_CTYPE spécifiées au moment de la création de la base de données. Les classements C et POSIX spécifient tous deux un comportement "C traditionnel", dans lequel seules les lettres ASCII "A" à "Z" sont traitées comme des lettres et le tri est strictement effectué par des valeurs d'octets de code de caractère .
En outre, le nom de classement standard SQL ucs_basic est disponible pour le codage UTF8. Il est équivalent à C et trie par point de code Unicode.
Donc, si ma compréhension est correcte, C est ASCII, pas UTF8.