数据库的路上

OpenGauss 服务端GBK字符集和Postgresql对比分析

Postgresql server端不支持GBK字符集

psql创建数据库

create database gbk with encoding 'GBK';

代码调用

src/backend/commands/dbcommands.c

  1. 通过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)

image-20250425183028892

判断字符集是否兼容

当前环境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,'一');

image-20250426134930886

总结

在数据库领域,PostgreSQL作为一款强大且应用广泛的开源数据库,原本并不支持将GBK作为server端的字符集,这在一定程度上限制了其在部分对GBK字符集有特定需求场景下的应用,比如从Oracle的GBK字符集迁移到pg系国产数据库UTF8过程中,有时会遇到中文字符超出列的宽度问题 ,而在数据库国产化进程中,openGauss对这一限制进行了针对性修改,成功实现了对GBK作为server字符集的支持。尽管从功能革新的量级来看,这或许不算是一项具有颠覆性的重大改进,但它却精准地解决了实际应用中存在的痛点。 这种对细节的关注和完善,不仅提升了openGauss在字符集支持方面的灵活性与兼容性,也展现了国产化数据库在功能优化上的用心。