web-dev-qa-db-fra.com

Comment fonctionne exactement le type d'un octet «Char» fonctionne-t-il dans PostgreSQL?

Je vois souvent des gens parler de "char". Je ne l'ai jamais utilisé. Il est défini dans les docs comme étant,

Le type "Char" (notez les devis) est différent du char (1) en ce qu'il utilise qu'un octet de stockage. Il est utilisé intérieurement dans les catalogues système comme type de dénombrement simpliste.

Et plus loin,

"char"  1 byte  single-byte internal type

Donc, si c'est un octet, quel est le domaine et comment en feriez-vous l'utiliser? Est-ce signé ou non signé? Dans ce post par @ @ erwin Brandsetter, il la pose , mais je suis toujours confus. Il utilise ascii() et chr(), et fournit ceci

SELECT i
     , chr(i)::"char"        AS i_encoded
     , ascii(chr(i)::"char") AS i_decoded
FROM   generate_series(1,256) i;

Cela fait quelque chose de vraiment bizarre entre 10 et 11.

  i  | i_encoded | i_decoded 
-----+-----------+-----------
...
   8 | \x08      |         8
   9 |           |         9
  10 |          +|        10
     |           |           -- WTF is going on here.
  11 | \x0B      |        11
  12 | \x0C      |        12
...

Il devient aussi vraiment bizarre ici:

 126 | ~         |       126
 127 | \x7F      |       127
 128 |           |       128
 129 |           |       128
 130 |           |       128
 131 |           |       128

Pourquoi tout est-il au nord de 128 étant décodé comme 128? Mais pour prendre un peu le Bizzare, après 192, il y a un commutateur et ils sont décodés comme 192 ..

 190 |           |       128
 191 |           |       128
 192 |           |       192
 193 |           |       192
 194 |           |       192
 195 |           |       192
 196 |           |       192
 197 |           |       192

Erwin dit

Plusieurs caractères ne sont pas destinés à l'affichage. Alors encoder avant de stocker et de décoder avant d'afficher ...

Je ne suis pas sûr de savoir pourquoi nous devrions-nous encoder du tout si nous faisons exactement ce que ces questions posent

CREATE TABLE foo AS
SELECT i::"char"
FROM   generate_series(-128,127) i;

Cela fonctionne bien. Nous pouvons obtenir l'intégralité de l'intégralité en utilisant

SELECT i::int FROM foo;

Donc en bref,

  1. Quel est le code d'Erwin entre 10-11 où je vais null?
  2. Pourquoi 128 est-il répété tant de fois?
  3. Pourquoi 192 est-il répété tant de fois?
  4. Comment puis-je déclencher l'incapacité à stocker 0, lorsque erwin dit , vous ne pouvez pas encoder 0 de cette façon (caractère null non autorisé)

    CREATE TABLE foo AS SELECT 0::int::"char" AS x;
    SELECT x::int FROM foo;
     x 
    ---
    0
    
9
Evan Carroll

1. chr(10)

... produise le [~ # ~] lignesfeed [~ # ~]] caractère (AKA Séquence d'échappée \n) et PSQL affiche le caractère avec une nouvelle ligne (indiquée par +). Tout correct là-bas.

2. & 3. ascii() produit 128 ou 192?

Cela commence par une erreur que j'ai faite. Je suppose négligemment "char" Couvrirait la plage d'un non signé entier de 1 octet (0 à 255) dans le référencé Réponse (maintenant fixe), mais c'est en fait la plage de signée entier de 1 octet (-128 à 127) en interne.

ascii() prend un paramètre text, la coute implicite de "char" à text génère un caractère codé multibyte dans Unicode et la fonction renvoie (- par documentation sur ascii() ):

Code ASCII du premier caractère de l'argument. Pour UTF8, renvoie le point de code Unicode du personnage. Pour d'autres codages multibytes, l'argument doit être un ASCII caractère.

Nous obtenons donc beaucoup de valeurs tronquées. 128 et 192 sont des valeurs d'octet pour l'octet de premier plan des caractères multibytes.

4. L'octet nul

L'incapacité de stocker NULL octets n'affecte que les types de caractères réguliers (text, char, varchar), pas "char". Cela s'applique à mon exemple de buggy, car je mets à text comme pierre de descente. Tout en casissant entre "char" Et integer directement, la limitation ne s'applique pas. le manuel sur chr() :

Le caractère NULL (0) n'est pas autorisé car les types de données de texte ne peuvent pas stocker de tels octets.

Pas ainsi pour "Char", où 0 Est mappé sur la chaîne vide '':

SELECT ''::"char"::int  -- 0
     , 0::"char" = '';  -- t

N'oubliez pas: "char" Est toujours un type "interne" destiné à une énumération simple et bon marché. Pas officiellement conçu pour ce que nous faisons ici, et non portable à d'autres SGBDM. Il n'y a pas de garantie par le projet Postgres pour cela.

11

Pour effectuer le déplacement vers la plage signée, vous pouvez créer des fonctions pour aider à aider. Cette liste créera des fonctions pas jette pour aider à aider à ce processus d'aller de une plage d'un octet non signé de [0-255] à un a signé une plage d'octets que le caractère nécessite [-128,127].

Exemple

Un extrait du Readme

Maintenant, vous pouvez faire par exemple stocker les valeurs dans la plage de [0-255] sur la table.

CREATE TABLE t(x) AS VALUES
  (to_uchar(255)),
  (to_uchar(0));

Convertissez-les en bit(8)

SELECT to_bit8(x) FROM t;
 to_bit8  
----------
 11111111
 00000000
(2 rows)

Peut-être que vous voulez effacer les deux bits d'ordre inférieur, vous pouvez le faire avec le bitwise-et,

UPDATE t
  SET x = to_uchar( to_bit8(x) & (x'fc')::bit(8) );

SELECT to_bit8(x) FROM t;
 to_bit8  
----------
 11111100
 00000000
(2 rows)
0
Evan Carroll