OpenGauss 服务端GBK字符集和Postgresql对比分析
Postgresql server端不支持GBK字符集
psql创建数据库
create database gbk with encoding 'GBK';
代码调用
src/backend/commands/dbcommands.c
- 通过pg_valid_server_encoding验证编码是否有效
pg_valid_server_encoding 函数结构图
```mermaid
graph TD
A[pg_valid_server_encoding] --> B[pg_char_to_encoding]
B --> C[clean_encoding_name]
C --> D[二分查找 pg_encname_tbl]
A --> E[PG_VALID_BE_ENCODING 宏]
-
pg_encname_tbl 是一个数组,里面罗列了所有Postgresql支持的字符集
-
pg_char_to_encoding 通过验证,gbk在整体支持列表里,后面需验证是否支持 server 端字符集
-
需要使用PG_VALID_BE_ENCODING(enc) 判断 server 端是否支持 gbk 根据src/include/mb/pg_wchar.h 代码的定义,PG_GBK 只属于 client 支持的范围,server 端不支持。
/* followings are for client encoding only */
PG_SJIS, /* Shift JIS (Windows-932) */
PG_BIG5, /* Big5 (Windows-950) */
PG_GBK, /* GBK (Windows-936) */
PG_UHC, /* UHC (Windows-949) */
PG_GB18030, /* GB18030 */
PG_JOHAB, /* EUC for Korean JOHAB */
PG_SHIFT_JIS_2004, /* Shift-JIS-2004 */
_PG_LAST_ENCODING_ /* mark only */
所以 Postgresql server 端不支持 GBK 字符集。
create database gbk with encoding 'GBK';
ERROR: GBK is not a valid encoding name
opengauss 的server 端支持GBK字符集
从代码可以看出opengauss 做了修改支持了了GBK作为Server的字符集
src/include/mb/pg_wchar.h
// supports GBK for server encoding
PG_GBK, /* GBK (Windows-936) */
创建数据库语句
openGauss=# CREATE DATABASE mydb WITH ENCODING 'GBK' template = template0;
判断serveer端是否支持GBK
encoding = pg_valid_server_encoding(encoding_name)
判断字符集是否兼容
当前环境template0的字符集为UTF8
openGauss=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-----------+----------+---------+---------+-------------------------
postgres | opengauss | UTF8 | C.UTF-8 | C.UTF-8 |
template0 | opengauss | UTF8 | C.UTF-8 | C.UTF-8 | =c/opengauss +
| | | | | opengauss=CTc/opengauss
template1 | opengauss | UTF8 | C.UTF-8 | C.UTF-8 | =c/opengauss +
| | | | | opengauss=CTc/opengauss
(3 rows)
直接创建字符集会报兼容错误
openGauss=# CREATE DATABASE mydb WITH ENCODING 'GBK' template = template0;
ERROR: encoding "GBK" does not match locale "C.UTF-8"
DETAIL: The chosen LC_CTYPE setting requires encoding "UTF8".
指定locale 为GBK,创建成功
openGauss=# CREATE DATABASE mydb WITH ENCODING 'GBK' LC_COLLATE = 'zh_CN.gbk' LC_CTYPE = 'zh_CN.gbk';
CREATE DATABASE
openGauss=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+-----------+----------+-----------+-----------+-------------------------
mydb | opengauss | GBK | zh_CN.gbk | zh_CN.gbk |
postgres | opengauss | UTF8 | C.UTF-8 | C.UTF-8 |
template0 | opengauss | UTF8 | C.UTF-8 | C.UTF-8 | =c/opengauss +
| | | | | opengauss=CTc/opengauss
template1 | opengauss | UTF8 | C.UTF-8 | C.UTF-8 | =c/opengauss +
| | | | | opengauss=CTc/opengauss
字符集转换
当server端和client 端不一致的情况下,opengauss会对client的输入按照server的字符集进行转换。比如client是UTF8,server是GBK,插入数据时会经过utf8_to_gbk 函数处理。
mydb=# show client_encoding ;
client_encoding
-----------------
UTF8
(1 row)
mydb=# insert into t1 values(1,'一');
总结
在数据库领域,PostgreSQL作为一款强大且应用广泛的开源数据库,原本并不支持将GBK作为server端的字符集,这在一定程度上限制了其在部分对GBK字符集有特定需求场景下的应用,比如从Oracle的GBK字符集迁移到pg系国产数据库UTF8过程中,有时会遇到中文字符超出列的宽度问题 ,而在数据库国产化进程中,openGauss对这一限制进行了针对性修改,成功实现了对GBK作为server字符集的支持。尽管从功能革新的量级来看,这或许不算是一项具有颠覆性的重大改进,但它却精准地解决了实际应用中存在的痛点。 这种对细节的关注和完善,不仅提升了openGauss在字符集支持方面的灵活性与兼容性,也展现了国产化数据库在功能优化上的用心。