今天在一MogDB 数据库中创建 GBK 字符集的 database 的时候报:ERROR: encoding “GBK” does not match locale “en_US.UTF-8”。

1
2
3
MogDB=# create database mogdb ENCODING 'GBK';
ERROR: encoding "GBK" does not match locale "en_US.UTF-8"
DETAIL: The chosen LC_CTYPE setting requires encoding "UTF8".

这个创建 GBK 字符集的数据库,我前天还在另一个 MogDB 实例创建的,相同的语句,为啥这个实例就不行了呢。于是进行了一点研究,记录如下。

通过报错是说:字符集(编码)GBKlocale "en_US.UTF-8" 不匹配。LC_CTYPE 的设置,需要设置 UTF8 的编码。

检查 数据库的 LC_CTYPE 的参数:

1
2
3
4
5
6
MogDB=# show LC_CTYPE;
lc_ctype
-------------
en_US.UTF-8
(1 row)

可以看到 LC_CTYPE设置为 en_US.UTF-8

检查目前的database 信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MogDB=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Compatibility
-----------+-------+----------+-------------+-------------+--------------------+---------------
co | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/omm +| A
| | | | | omm=CTc/omm +|
| | | | | co_rp=CTc/omm +|
| | | | | co_rp=APm/omm |
f001 | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/omm +| A
| | | | | omm=CTc/omm +|
| | | | | u_f001=CTc/omm +|
| | | | | u_f001=APm/omm |
futf | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | A
postgres | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | A
template0 | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/omm +| A
| | | | | omm=CTc/omm |
template1 | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/omm +| A
| | | | | omm=CTc/omm |
testdb | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/omm +| A
| | | | | omm=CTc/omm +|
| | | | | testdblink=CTc/omm+|
| | | | | testdblink=APm/omm |

可以看到,目前的数据库的编码都是 utf8CollaeCtype 都是 en_US.UTF-8

然后我又找到之前的MogDB 实例,检查发现有以下几点不同:

LC_CTYPE 参数设置为 C

\l 查看数据库的属性的 CollateCtype 也都是 C,具体 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MogDB=# show LC_CTYPE;
lc_ctype
----------
C
(1 row)

MogDB=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Compatibility
-----------+-------+----------+---------+-------+-------------------+---------------
co | ogm | GBK | C | C | | A
postgres | ogm | UTF8 | C | C | | A
template0 | ogm | UTF8 | C | C | =c/ogm +| A
| | | | | ogm=CTc/ogm |
template1 | ogm | UTF8 | C | C | omm=CTc/ogm +| A
| | | | | =c/ogm +|
| | | | | ogm=CTc/ogm |

进一步发现这俩实例的创建是不同的。

不能创建 GBK 的MogDB 的实例是安装 官方文档的 手动安装章节进行安装的:https://docs.mogdb.io/zh/mogdb/v5.0/manual-installation

初始化数据库的时候使用的如下脚本:

1
gs_initdb --pgdata=/opt/mogdb/data --nodename=primary --pwpasswd=Enmo@123 --encoding=UTF-8 --locale=en_US.UTF-8

也就是指定了 --encoding=UTF-8 --locale=en_US.UTF-8,其实问题的关键是指定了 --locale=en_US.UTF-8,这就导致默认创建的数据库都是 locale en_US.UTF-8 ,而 与locale "en_US.UTF-8"匹配的编码( encoding) 是"UTF8",所以默认创建的编码只能是 UTF8

那数据库实例已经初始化完成了,怎么创建GBK的数据库呢,总不能重新初始化吧,这库都运行了一段时间了呢。

经过确认是不需要重新初始化的,可以通过以下命令进行手动指定

1
create database  hhgbk ENCODING='GBK' LC_COLLATE='zh_CN.gbk' LC_CTYPE='zh_CN.gbk';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
MogDB=# \l hhgbk
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Compatibility
-------+-------+----------+-----------+-----------+-------------------+---------------
hhgbk | omm | GBK | zh_CN.gbk | zh_CN.gbk | | A
(1 row)

MogDB=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Compatibility
-----------+-------+----------+-------------+-------------+--------------------+---------------
co | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/omm +| A
| | | | | omm=CTc/omm +|
| | | | | co_rp=CTc/omm +|
| | | | | co_rp=APm/omm |
f001 | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/omm +| A
| | | | | omm=CTc/omm +|
| | | | | u_f001=CTc/omm +|
| | | | | u_f001=APm/omm |
futf | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | A
hhgbk | omm | GBK | zh_CN.gbk | zh_CN.gbk | | A
postgres | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | A
template0 | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/omm +| A
| | | | | omm=CTc/omm |
template1 | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/omm +| A
| | | | | omm=CTc/omm |
testdb | omm | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/omm +| A
| | | | | omm=CTc/omm +|
| | | | | testdblink=CTc/omm+|
| | | | | testdblink=APm/omm |

这样就可以。可以看到 hhgbk 数据库是一股清流,是GBK的编码。

而另一个MogDB 实例是通过 ptk 工具进行安装的,通过查找 ptk 日志可以看到他 初始化实例的脚本如下:

1
gs_initdb --pgdata=/data/mogdb/data --nodename=primary --pwpasswd=Enmo@123 --encoding=UTF-8 --no-locale

也就是 ptk 工具是 加的 --no-locale 参数,而手动安装的是加了 --locale=en_US.UTF-8参数。

然后查看官方手册的 CREATE DATABASE

https://docs.mogdb.io/zh/mogdb/v5.0/CREATE-DATABASE

注意:如果创建兼容性为A的数据库,建议设置lc_collate =’C’,否则可能导致跟需要兼容的数据库中排序结果有差异。推荐创建兼容性为A的数据库使用以下命令:

1
>create database db1 DBCOMPATIBILITY='A' ENCODING='UTF8' LC_COLLATE='C' LC_CTYPE='C';

也就是A 模式下建议使用 设置lc_collate =’C’,而create database 默认就是A模式。

继续查看官方文档的gs_initdb https://docs.mogdb.io/zh/mogdb/v5.0/gs_initdb

参数 参数说明
–no-locale 和–locale=C等价。

也就是 --no-locale--locale=C等价。

另:

我也找了个云上提供服务器的 pg 数据库的配置,设置的也是 C。

1
2
3
4
5
6
7
8
9
10
11
f001=> \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-----------+-------------+----------+---------+-------+------------+-----------------+-----------------------------
f001 | default | UTF8 | C | C | | libc |
music2 | default | LATIN9 | C | C | | libc |
postgres | cloud_admin | UTF8 | C | C | | libc |
template0 | cloud_admin | UTF8 | C | C | | libc | =c/cloud_admin +
| | | | | | | cloud_admin=CTc/cloud_admin
template1 | cloud_admin | UTF8 | C | C | | libc | =c/cloud_admin +
| | | | | | | cloud_admin=CTc/cloud_admin

那这个 C 是什么意思呢?

C”是系统默认的locale,”POSIX”是”C”的别名。所以当我们新安装完一个系统时,默认的locale就是C或POSIX。

https://pubs.opengroup.org/onlinepubs/009695399/functions/setlocale.html

“POSIX”
[CX] [Option Start] Specifies the minimal environment for C-language translation called the POSIX locale. If setlocale() is not invoked, the POSIX locale is the default at entry to main(). [Option End]
“C”
Equivalent to “POSIX”.

参考:

https://docs.mogdb.io/zh/mogdb/v5.0/gs_initdb

https://docs.mogdb.io/zh/mogdb/v5.0/character-set-support

https://docs.mogdb.io/zh/mogdb/v5.0/manual-installation

https://docs.mogdb.io/zh/mogdb/v5.0/ptk-based-installation

原文作者: Hi.MogDB

原文链接: https://hi.mogdb.org/posts/54e5665e/

许可协议: 知识共享署名-非商业性使用 4.0 国际许可协议