No PostgreSQL, qual é a diferença entre collations C
e C.UTF-8
?
Ambos aparecem em linhas de pg_collation
. Talvez C.UTF-8
seja o mesmo que C
com a codificação UTF-8
independentemente ou qual seja a codificação real de um banco de dados?
No PostgreSQL, qual é a diferença entre collations C
e C.UTF-8
?
Ambos aparecem em linhas de pg_collation
. Talvez C.UTF-8
seja o mesmo que C
com a codificação UTF-8
independentemente ou qual seja a codificação real de um banco de dados?
A documentação do PostgreSQL deixa muito a desejar (só falando ? ).
Para começar, há apenas uma codificação para um banco de dados específico, portanto,
C
eC.UTF-8
em seu banco de dados UTF-8, ambos estão usando a codificação UTF-8.Para agrupamentos libc : normalmente os nomes de agrupamentos, por convenção , são realmente nomes de duas partes da seguinte estrutura:
{locale_name}.{encoding_name}
Um "locale" (ou seja, "cultura") é o conjunto de regras específicas do idioma para classificação (
LC_COLLATE
) e capitalização (LC_CTYPE
). Mesmo que às vezes haja sobreposição, isso realmente não tem nada a ver com a forma como esses dados são armazenados.Uma "codificação" é como os dados são armazenados (ou seja, qual seqüência de bytes equivale a qual caractere). Mesmo que às vezes haja sobreposição, isso realmente não tem nada a ver com as regras de classificação e capitalização de qualquer idioma específico que usa a codificação (algumas codificações podem ser usadas por vários idiomas que podem ter regras bastante diferentes em um ou ambos essas áreas).
Para ilustrar, considere armazenar dados coreanos:
ko_KR
é a localidade.EUC_KR
(Extended UNIX Code-KR)JOHAB
UHC
(Código Hangul Unificado / Windows949)UTF8
(codificação de 8 bits do Unicode)Considere também o seguinte, retirado da documentação " Collation Support: libc collations " (ênfase adicionada):
Ou seja, em um banco de dados que usa a codificação UTF-8
en_US
een_US.UTF8
são equivalentes. MAS, entre esse banco de dados e um banco de dados que usa aLATIN1
codificação, osen_US
agrupamentos não são equivalentes.Então, isso significa que
C
eC.UTF-8
são a mesma coisa?NÃO, isso seria muito fácil!!! A
C
ordenação é uma exceção ao comportamento indicado acima. OC
agrupamento é um conjunto simples de regras que está disponível independentemente da codificação do banco de dados, e o comportamento deve ser consistente entre as codificações (o que é possível apenas reconhecendo o alfabeto inglês dos EUA — "az" e "AZ" — como "letras" , e classificando por valor de byte, que deve ser o mesmo para as codificações disponíveis para você).O
C.UTF-8
agrupamento é, na verdade, um conjunto de regras ligeiramente aprimorado, em comparação com asC
regras básicas. Essa diferença pode ser vista empg_collation
uma vez que os valores para as colunascollcollate
ecollctype
são diferentes entre as linhas paraC
eC.UTF-8
.Eu montei um conjunto de consultas de teste para ilustrar algumas das semelhanças e diferenças entre esses dois agrupamentos, bem como em comparação com
en_GB
(e implicitamenteen_GB.utf8
). Comecei com as perguntas fornecidas na resposta de Daniel Vérité , aprimorei-as para ficar mais claro sobre o que está e o que não está sendo mostrado e adicionei algumas perguntas. Os resultados nos mostram que:C
eC.UTF-8
são, na verdade, conjuntos de regras diferentes, mesmo que apenas ligeiramente diferentes, com base em seus respectivos valores nas colunascollcollate
e em (consulta final)collctype
pg_collation
C.UTF-8
expande os caracteres que são considerados "letras"C.UTF-8
, ao contrárioC
(mas comoen_GB
), reconhece pontos de código Unicode inválidos (ou seja, U+0378) e os classifica para o topoC.UTF-8
, likeC
(mas diferenteen_GB
de ), classifica caracteres de letras não inglesas dos EUA por ponto de códigoucs_basic
parece ser equivalente aC
(o que é indicado na documentação)Você pode encontrar e executar as consultas em: db<>fiddle
Não. Considere, por exemplo, estas diferenças em um banco de dados UTF-8, no Debian 10 Linux:
(U+0378 não corresponde a nenhum caractere válido em Unicode).
Outro exemplo com um caractere Unicode válido (o lado esquerdo é 'THUMBS UP SIGN' U+1F44D ):
Quando
lc_collate
for "C" (ou "POSIX"), a comparação é feita internamente pelo PostgreSQL. Nesse caso, ele compara as representações de bytes das strings usandomemcmp
.Nos demais casos em que libc é o provedor (
collprovider='c'
empg_collation
), a comparação é feita pelastrcoll_l
biblioteca C, então o próprio PostgreSQL não é responsável pelo resultado e, como mostram os contra-exemplos acima, não há razão para acreditar que será idêntico.Isso é verdade pelo menos para agrupamentos apoiados por libc. A partir da versão 10 do Postgres, os agrupamentos ICU podem ser usados. Esses agrupamentos são consistentes em todos os sistemas operacionais.
Os detalhes sangrentos podem ser encontrados no código-fonte em backend/utils/adtvarlena.c , especialmente a
varstrmp_cmp
função.Na documentação do postgresql, https://www.postgresql.org/docs/11/collation.html :
Então, se meu entendimento estiver correto, C é ASCII, não UTF8.