web-dev-qa-db-ja.com

1バイトの「char」型はPostgreSQLでどのように機能しますか?

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

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

そしてさらに、

_"char"  1 byte  single-byte internal type
_

それで、それが1バイトである場合、ドメインは何で、どのようにそれを利用しますか?署名されていますか、署名されていませんか? @ Erwin Brandstetterによるこの投稿では、彼はそれをレイアウトしています が、私はまだ混乱しています。彼は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
    _
9
Evan Carroll

1. chr(10)

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

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

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

ascii()textパラメータを取り、"char"からtextへの暗黙のキャストはマルチバイトエンコードされた文字をUnicodeで生成し、関数は( ascii() ):

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

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

4. nullバイト

Nullバイトを格納できないことは、"char"ではなく、通常の文字タイプ(textcharvarchar)にのみ影響します。私はバギーの例に当てはまります。私はtextに飛び石としてキャストしているからです。 "char"integerの間で直接キャストする場合、制限は適用されません。 chr() のマニュアル

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

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

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

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

11

符号付き範囲へのシフトを行うために、支援に役立ついくつかの関数を作成できます。このリストは、関数notキャストを作成して、このプロセスで符号なし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)
_
0
Evan Carroll