淺探PostgreSQL的 char 類型

一般來說,在PostgreSQL中,char 類型是表示固定長度的字符串的類型。例如, char(n) 用來表示長度爲N個字符的字符串。不過,PostgreSQL 自身的一些細小缺陷,使得上面的論斷事實上並不是很嚴謹。何以見得?下面的這個探究char類型實驗,會揭開問題的面紗。

 

我們通過下面的SQL語句創建一張表:

create table tb_char

    quoted_char_col "char",

    char_col char,

    char1_col char(1),

    char2_col char(2)

);

可以看到表 tb_char 有四列,他們的類型依次是帶引號的 "char",不帶引號且未指定長度的char,char(1),char(2)。char(1)和char(2) 的含義明確,而另外兩種類型是什麼含義呢?

我們執行下列查詢,從pg_attribute中查看這幾列的屬性:

select attrelid,attname,atttypid,attlen,atttypmod from pg_attribute where attrelid = 'tb_char'::regclass::oid and attnum > 0

查詢結果如下:

attrelid |     attname     | atttypid | attlen | atttypmod

----------+-----------------+----------+--------+-----------

   391725 | quoted_char_col |       18 |      1 |        -1

   391725 | char_col        |     1042 |     -1 |         5

   391725 | char1_col       |     1042 |     -1 |         5

   391725 | char2_col       |     1042 |     -1 |         6

(4 rows)

 

從查詢結果中可以看出:

char_col 的類型char1_col 完全相同。因此,在創建表時,不帶引號且未指定長度

的char會被默認視爲char(1)。

 

而 quoted_char_col 的類型 "char" 有哪些性質呢?

 

我們通過如下查詢,從類型表pg_type中查看 oid 爲 18和1042的類型:

select oid,typname,typlen from pg_type where oid in (18,1042);

查詢結果如下:

oid  | typname | typlen

------+---------+--------

   18 | char    |      1

 1042 | bpchar  |     -1

(2 rows)

 

嗯? pg_type中,oid = 18 的類型的名稱是char,而它是建表語句中quoted_char_col字段的類型,帶引號的"char";而 oid =1042的類型的名稱是bpchar,而它是建表語句中char_col字段的類型,不帶引號的char這同樣的類型,在系統表pg_type 中和建表語句中的名稱竟然是不一致的。

 

我們再看查詢中的typlen的值, pg_type中typname爲char 的類型,typlen = 1;而pg_type中typname爲bpchar 的類型,typlen = -1。

PostgreSQL 官方文檔對這個字段的描述是:

對於一個固定尺寸的類型,typlen是該類型內部表示的字節數。對於一個變長類型,typlen爲負值。-1表示一個"varlena"類型(具有長度字),-2表示一個以空值結尾的C字符串。

也就是說,表 tb_char中quoted_char_col字段的類型,即pg_type 中的char建表語句中帶引號的”char,長度是1個字節;而tb_char中char_col,char1_col字段的類型,也就是在pg_type 中的bpchar,建表語句中帶不帶引號的char,長度則是取決於用戶設定。

 

那麼pg_type 中的char類型通常用在哪裏呢?

這個類型在實際項目中一般不會使用,也不推薦使用。它只在PostgreSQL 的系統表中使用。如pg_class. relkind,. pg_constraint.contype, pg_aggregate. aggkind等。

 

另外,pg_type 中的char類型還有一個特點,那就是當你爲具有這個類型的字段賦值時,若這個值的長度大於1個字符,程序會自動將其截取爲1個字符。而對類型是pg_type 中的bpchar類型,即建表語句中不帶引號的char 的字段做同樣的操作,則會報錯。

 

執行下面的插入語句:

insert into tb_char (quoted_char_col,char_col,char1_col,char2_col) values ('aa','a','a','aa');

執行下面的查詢語句:

select * from tb_char;

 

查看插入結果:

 quoted_char_col | char_col | char1_col | char2_col

-----------------+----------+-----------+-----------

 a               | a        | a         | aa

 

可以看出, 程序自動將向quoted_char_col字段插入的值截取爲了“a”。

 

執行下面的插入語句:

insert into tb_char (quoted_char_col,char_col,char1_col,char2_col) values ('a','aa','a','aa');

則會報錯:

ERROR:  value too long for type character(1)

因此,在處理這兩種類型時,我們需要謹慎。要明確正在處理的類型是哪個,如果需要轉換,轉換後的類型是哪一個,還要注意類型轉換後數據是否正確,以此保證程序的正確性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章