PostgreSQLでは、1バイトの「char」型はどの程度正確に機能しますか?


9

私はよく人が話して"char"いるのを見ます。使ったことがない。それはドキュメントで次のように定義されています:

タイプ「char」(引用符に注意)は、1バイトのストレージのみを使用するという点でchar(1)とは異なります。これは、単純な列挙型としてシステムカタログで内部的に使用されます。

そしてさらに、

"char"  1 byte  single-byte internal type

それで、それが1バイトである場合、ドメインは何であり、どのようにそれを利用しますか?署名されていますか、署名されていませんか?@Erwin Brandstetterによるこの投稿では、彼はそれをレイアウトしていますが、私はまだ混乱しています。彼はand を使用してascii()おりchr()、これを提供しています

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

それは10から11の間で本当に奇妙なことをしています。

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

ここでも本当に奇妙です:

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

128の北にあるものがすべて128としてデコードされるのはなぜですか?しかし、bizzareを少し上げるために、192の後にスイッチがあり、それらは192としてデコードされます。

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

アーウィンさんのコメント

表示用ではない文字がいくつかあります。したがって、保存する前にエンコードし、表示する前にデコードします...

なぜそれをエンコードする必要があるのか​​はわかりません

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

それはうまくいきます。intを使用して戻すことができます

SELECT i::int FROM foo;

要するに、

  1. 私がnullになる10から11の間にアーウィンのコードは何をしていますか?
  2. なぜ128が何度も繰り返されるのですか?
  3. 192が何度も繰り返されるのはなぜですか?
  4. Erwinが0をこのようにエンコードできないと言ったときに、どのようにして0を格納できないようにするのですか(ヌル文字は許可されていません)

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

回答:


11

1。 chr(10)

... LINEFEED文字(別名エスケープシーケンス\n)を生成し、psqlは文字を改行付きで表示します(で示されます+)。すべてが正しい。

2.&3. ascii()は128または192を生成しますか?

それは私が犯した間違いから始まります。参照された回答の符号なし 1バイト整数(0から255)"char"の範囲をカバーすると想定して不用意に仮定しました(現在は修正されています)が、実際には内部的には符号付き 1バイト整数(-128から127)の範囲です。

ascii()textパラメータを受け取り、暗黙的なfrom "char"からtextのマルチバイトエンコードされた文字をUnicodeで生成し、関数が(ドキュメントの説明に従ってascii())を返します。

引数の最初の文字のASCIIコード。UTF8の場合、文字のUnicodeコードポイントを返します。その他のマルチバイトエンコーディングの場合、引数はASCII文字でなければなりません。

したがって、多くの切り捨てられた値を取得します。128および192は、マルチバイト文字の先頭バイトのバイト値です。

4. nullバイト

店舗ヌルバイトにできないことが唯一の定期的な文字の種類に影響を与える(textcharvarchar)、ではありません"char"。私textは飛び石としてキャストするので、私のバギーの例に当てはまります。"char"との間でinteger直接キャストする場合、制限は適用されません。マニュアルchr()

テキストデータタイプはそのようなバイトを格納できないため、NULL(0)文字は使用できません。

0空の文字列にマップされる「char」の場合はそうではありません''

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

覚えておいてください:"char"はまだ単純で安価な列挙を目的とした「内部」タイプです。ここでの作業用に公式に設計されたものではなく、他のRDBMSに移植できません。これに対するPostgresプロジェクトによる保証はありません。


\ rの表示の結果は、まだpsqlバグか変なものだと思います。それは行の終わりになり、次に行をスキップしますか?
エヴァンキャロル

4
@Evanいいえ、「行をスキップ」しません。空白行は前の行(複数行)の続きです。psqlで出力行の間に水平線を描くことができれば、これはより明白になりますが、視覚的な手がかりができないため、「+」です。
ジャックはtopanswers.xyzを

0

符号付き範囲へのシフトを行うために、支援に役立ついくつかの関数を作成できます。このリストはキャストではない関数を作成し、このプロセスが符号なし1バイト整数の範囲[0-255]から、文字が必要と[-128,127]する符号付き1バイト範囲に進むのに役立ちます。

READMEからの抜粋

これで、たとえば[0-255]、テーブルのの範囲に値を格納できます。

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

それらを変換する bit(8)

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

おそらく、下位2ビットをクリアしたい場合は、BITWISE-ANDを使用してそれを行うことができます。

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.