一字節“char”類型在 PostgreSQL 中究竟是如何工作的?
我經常看到人們談論
"char"
。我從來沒有使用過它。它在文件中定義為,“char” 類型(注意引號)與 char(1) 的不同之處在於它只使用一個字節的儲存空間。它在系統目錄內部用作簡單的列舉類型。
並進一步,
"char" 1 byte single-byte internal type
那麼,如果它是一個字節,那麼域是什麼,你將如何使用它?它是簽名的還是未簽名的?在@Erwin Brandstetter 的這篇文章中,他闡述了這一點,但我仍然感到困惑。他正在使用
ascii()
andchr()
,並提供了這個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?但是為了稍微提高一點,在 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;
這很好用。我們可以使用
SELECT i::int FROM foo;
所以簡而言之,
- Erwin 的程式碼在 i 變為空的 10-11 之間做什麼?
- 為什麼128重複了這麼多次?
- 為什麼192重複了這麼多次?
- 當 Erwin 說你不能以這種方式編碼 0 時,我如何觸發無法儲存 0 (不允許空字元)
CREATE TABLE foo AS SELECT 0::int::"char" AS x; SELECT x::int FROM foo; x --- 0
1.
chr(10)
… 生成LINEFEED字元(又名轉義序列
\n
)並且 psql 顯示帶有換行符的字元(由 表示+
)。那裡一切都正確。2. & 3.
ascii()
產生 128 還是 192?從我犯的一個錯誤開始。我不小心假設在引用的答案
"char"
(現已修復)中涵蓋了無符號1 字節整數(0 到 255)的範圍,但它實際上是內部有符號1 字節整數(-128 到 127)的範圍。
ascii()
接受一個text
參數,隱式轉換 from"char"
totext
在 unicode 中產生一個多字節編碼的字元,並且函式返回(根據文件ascii()
):參數的第一個字元的 ASCII 碼。對於 UTF8,返回字元的 Unicode 程式碼點。對於其他多字節編碼,參數必須是 ASCII 字元。
所以我們得到了很多截斷的值。128 和 192 是多字節字元的前導字節的字節值。
4.空字節
無法儲存空字節僅影響正常字元類型(
text
,char
,varchar
),而不影響"char"
。它適用於我的越野車範例,因為我將其text
作為墊腳石。在直接之間"char"
進行轉換integer
時,該限制不適用。手冊chr()
:不允許使用 NULL (0) 字元,因為文本數據類型無法儲存此類字節。
“char”不是這樣,其中
0
映射到空字元串''
:SELECT ''::"char"::int -- 0 , 0::"char" = ''; -- t
請記住:
"char"
仍然是一種“內部”類型,用於簡單而廉價的列舉。不是為我們在這裡所做的事情而正式設計的,也不能移植到其他 RDBMS。Postgres 項目對此沒有任何保證。