关于PostgreSQL的本地化消息

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: PostgreSQL通过gettext实现对多语言消息的支持。消息的语言是英语还是中文可以通过postgresql.conf中的lc_messages控制。在启动PostgreSQL时,postmaster进程(你看到的进程名可能是postgres)会根据postgresql.conf中的lc_messages值设置进程locale(调用setlocale()),然后再fork出一堆其它进程。
PostgreSQL通过gettext实现对多语言消息的支持。消息的语言是英语还是中文可以通过postgresql.conf中的lc_messages控制。在启动PostgreSQL时,postmaster进程(你看到的进程名可能是postgres)会根据postgresql.conf中的lc_messages值设置进程locale(调用setlocale()),然后再fork出一堆其它进程。但在postmaster读取postgresql.conf之前的一个很短的启动阶段,进程的locale是由系统环境决定的。
贴一个图,可以看的更清楚一点。

PostgreSQL各个进程的启动过程与区域设置:


1. 错误消息的语言


根据上面的图,当postgresql.conf中的loacle参数省略时,消息语言受环境loacle影响。下面验证一下。

当前的环境loacle是zh_CN.utf8,但postgresql.conf中没有设置loacle。
  1. -bash-4.1$ grep lc_ postgresql.conf
  2. #lc_messages = 'zh_CN.utf8'            # locale for system error message
  3. #lc_monetary = 'zh_CN.utf8'            # locale for monetary formatting
  4. #lc_numeric = 'zh_CN.utf8'            # locale for number formatting
  5. #lc_time = 'zh_CN.utf8'                # locale for time formatting

  6. -bash-4.1$ locale
  7. LANG=en_US.UTF-8
  8. LC_CTYPE="zh_CN.utf8"
  9. LC_NUMERIC="zh_CN.utf8"
  10. LC_TIME="zh_CN.utf8"
  11. LC_COLLATE="zh_CN.utf8"
  12. LC_MONETARY="zh_CN.utf8"
  13. LC_MESSAGES="zh_CN.utf8"
  14. LC_PAPER="zh_CN.utf8"
  15. LC_NAME="zh_CN.utf8"
  16. LC_ADDRESS="zh_CN.utf8"
  17. LC_TELEPHONE="zh_CN.utf8"
  18. LC_MEASUREMENT="zh_CN.utf8"
  19. LC_IDENTIFICATION="zh_CN.utf8"
  20. LC_ALL=zh_CN.utf8
启动postgres服务

  1. -bash-4.1$ pg_ctl -D `pwd` start
  2. 正在启动服务器进程
  3. -bash-4.1$ 2014-09-19 20:18:11.582 CST >日志: redirecting log output to logging collector process
  4. 2014-09-19 20:18:11.582 CST >提示: Future log output will appear in directory "pg_log".
控制台输出的消息和环境locale一致,是中文。
再看下日志文件,也是中文的。
  1. -bash-4.1$ tail -f pg_log/postgresql-Fri.log
  2. 2014-09-19 20:18:11.584 CST >日志: 数据库上次关闭时间为 2014-09-19 20:17:42 CST
  3. 2014-09-19 20:18:11.588 CST >日志: 数据库系统准备接受连接
  4. 2014-09-19 20:18:11.588 CST >日志: 已启动autovacuum

用psql连接上去,发现lc_messages是空的,其他几个lc_*是C,并且获得的 服务端消息语言也是继承了服务端环境loacle(即中文消息)。

  1. -bash-4.1$ psql
  2. psql (9.3.4)
  3. 输入 "help" 来获取帮助信息.

  4. postgres=# show lc_messages;
  5.  lc_messages
  6. -------------
  7.  
  8. (1 行记录)

  9. postgres=# show lc_monetary;
  10.  lc_monetary
  11. -------------
  12.  C
  13. (1 行记录)

  14. postgres=# show lc_numeric;
  15.  lc_numeric
  16. ------------
  17.  C
  18. (1 行记录)

  19. postgres=# show lc_time;
  20.  lc_time
  21. ---------
  22.  C
  23. (1 行记录)

  24. postgres=# ss;
  25. 错误: 语法错误 在 "ss" 或附近的
  26. 第1行ss;
  27.      ^

设置消息为C,服务端过来的消息变成了英文。

  1. postgres=# set lc_messages="C";
  2. SET
  3. postgres=# ss2;
  4. ERROR: syntax error at or near "ss2"
  5. 第1行ss2;
  6.      ^

日志中的消息也变成了英文(前一条中文消息是上次的)。

  1. 2014-09-19 20:23:03.068 CST >错误: 语法错误 在 "ss" 或附近的 第 1 个字符处
  2. 2014-09-19 20:23:03.068 CST >语句: ss;
  3. 2014-09-19 20:33:30.811 CST >ERROR: syntax error at or near "ss2" at character 1
  4. 2014-09-19 20:33:30.812 CST >STATEMENT: ss2

但是用set只影响这个会话。开个新的会话,还是中文的消息。

  1. -bash-4.1$ psql
  2. psql (9.3.4)
  3. 输入 "help" 来获取帮助信息.

  4. postgres=# ss3;
  5. 错误: 语法错误 在 "ss3" 或附近的
  6. 第1行ss3;
  7.      ^

如果想全局修改消息语言,可以修改postgresql.conf后用pg_ctl reload动态加载。

  1. -bash-4.1$ vi postgresql.conf
  2. lc_messages = 'C'
  3. -bash-4.1$ pg_ctl -D `pwd` reload
  4. server signaled

服务端日志已经切换到英文了

  1. 2014-09-19 20:41:49.012 CST >日志: 接收到 SIGHUP, 重载配置文件
  2. 2014-09-19 20:41:49.013 CST >LOG: parameter "lc_messages" changed to "C"

查看之前一直打开着的会话,也已经切换到英文了。

  1. postgres=# ss4;
  2. ERROR: syntax error at or near "ss4"
  3. 第1行ss4;
  4.      ^
*)postgresql.conf中的有些参数reload后只对以后创建的postgres进程生效,但lc_messages不是这样,可以立即生效。


2. 错误消息的编码


总的来说消息的语言决定于postgresql.conf中的lc_messages,postgresql.conf未指定时取决于启动postgres的环境loacle。那么消息的编码呢?
gettext取得的消息的编码取决于LC_CTYPE,而不是LC_MESSAGES。所以,在下面的设置中,本地化消息的编码是GBK而不是UTF8。

  1. [chenhj@hanode1 ~]$ export LC_ALL=
  2. [chenhj@hanode1 ~]$ export LC_CTYPE=zh_CN.gbk
  3. [chenhj@hanode1 ~]$ export LC_MESSAGES=zh_CN.utf8
  4. [chenhj@hanode1 ~]$ ls xx
  5. ls: ?·¨·??x: ???????倂?

为了便于区分,我的终端软件编码一直设置为UTF8,所以当你看到了 乱码,就表示它不是UTF8编码,后面的测试也是一样
根据之前的图,postmaster和辅助进程的LC_TYPE应该取决于环境locale,postgres进程的LC_TYPE则取决于数据库的编码。下面也实测一下。

修改postgresql.conf中的lc_messages值为zh_CN.utf8,环境变量LC_CTYPE设为zh_CN.gb2312。

  1. -bash-4.1$ vi postgresql.conf
  2. lc_messages = 'zh_CN.utf8'
  3. -bash-4.1$ export LC_CTYPE="zh_CN.gb2312"
  4. -bash-4.1$ locale
  5. LANG=en_US.UTF-8
  6. LC_CTYPE=zh_CN.gb2312
  7. LC_NUMERIC="en_US.UTF-8"
  8. LC_TIME="en_US.UTF-8"
  9. LC_COLLATE="en_US.UTF-8"
  10. LC_MONETARY="en_US.UTF-8"
  11. LC_MESSAGES="en_US.UTF-8"
  12. LC_PAPER="en_US.UTF-8"
  13. LC_NAME="en_US.UTF-8"
  14. LC_ADDRESS="en_US.UTF-8"
  15. LC_TELEPHONE="en_US.UTF-8"
  16. LC_MEASUREMENT="en_US.UTF-8"
  17. LC_IDENTIFICATION="en_US.UTF-8"
  18. LC_ALL=

重启服务器,输出的消息中出现了个gb2312编码的字符(这部分消息是postmaster进程输出的)。

  1. -bash-4.1$ pg_ctl -D `pwd` restart
  2. waiting for server to shut down.... done
  3. server stopped
  4. server starting
  5. -bash-4.1$ 2014-09-19 21:09:25.882 CST >??: redirecting log output to logging collector process
  6. 2014-09-19 21:09:25.882 CST >??: Future log output will appear in directory "pg_log".

用psql连进来看下,消息是正常的( 这部分消息来自postgres进程)。

  1. -bash-4.1$ locale
  2. LANG=en_US.UTF-8
  3. LC_CTYPE="zh_CN.utf8"
  4. LC_NUMERIC="zh_CN.utf8"
  5. LC_TIME="zh_CN.utf8"
  6. LC_COLLATE="zh_CN.utf8"
  7. LC_MONETARY="zh_CN.utf8"
  8. LC_MESSAGES="zh_CN.utf8"
  9. LC_PAPER="zh_CN.utf8"
  10. LC_NAME="zh_CN.utf8"
  11. LC_ADDRESS="zh_CN.utf8"
  12. LC_TELEPHONE="zh_CN.utf8"
  13. LC_MEASUREMENT="zh_CN.utf8"
  14. LC_IDENTIFICATION="zh_CN.utf8"
  15. LC_ALL=zh_CN.utf8

  16. -bash-4.1$ psql
  17. psql (9.3.4)
  18. 输入 "help" 来获取帮助信息.

  19. postgres=# ss5;
  20. 错误: 语法错误 在 "ss5" 或附近的
  21. 第1行ss5;
  22.      ^

日志中的消息也是UTF8。而且即使像这样修改客户端的编码为gb2312。

  1. -bash-4.1$ export LC_ALL=zh_CN.gb2312
  2. -bash-4.1$ psql
  3. psql (9.3.4)
  4. ?? "help" 4?衰?х?.

  5. postgres=# ss6;
  6. ??: ?·¨?? ? "ss6" ?载
  7. ???ss6;
  8.      ^
服务端日志中消息还是UTF8。(前面3条消息是postmaster进程报的消息,为gb2312编码)

  1. 2014-09-19 21:09:25.884 CST >??: ?????ι??±?厪 2014-09-19 21:09:24 CST
  2. 2014-09-19 21:09:25.890 CST >??: ??????±??????
  3. 2014-09-19 21:09:25.891 CST >??: ????autovacuum
  4. 2014-09-19 21:14:34.095 CST >错误: 语法错误 在 "ss5" 或附近的 第 1 个字符处
  5. 2014-09-19 21:14:34.095 CST >语句: ss5;
  6. 2014-09-19 21:26:52.511 CST >错误: 语法错误 在 "ss6" 或附近的 第 1 个字符处
  7. 2014-09-19 21:26:52.511 CST >语句: ss6

创建一个gb2312编码的数据库,连上去。错误消息就是gb2312了。

  1. -bash-4.1$ export LC_ALL=zh_CN.utf8
  2. -bash-4.1$ createdb -T template0 -E EUC_CN --locale=C euccn
  3. -bash-4.1$ psql euccn
  4. psql (9.3.4)
  5. 输入 "help" 来获取帮助信息.

  6. euccn=# ss7;
  7. 错误: 语法错误 在 "ss7" 或附近的
  8. 第1行ss7;
  9.      ^
日志中的消息也是gb2312。

  1. 2014-09-19 21:38:42.203 CST >语句: CREATE DATABASE euccn ENCODING 'EUC_CN' LC_COLLATE 'C' LC_CTYPE 'C';
  2.     
  3. 2014-09-19 21:40:31.478 CST >??: ?·¨?? ? "ss7" ?载? 1 ?薷
  4. 2014-09-19 21:40:31.478 CST >??? ss7

3. 结论

输出本地语言消息时服务端日志文件中可能会混合不同编码的消息。为了避免这种事发生,需要注意以下两点
1)同一数据库集群(cluster)中的多个数据库使用同一种编码
2)启动数据库时的环境locale(LC_CTYPE)也使用相同的编码



相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
1月前
|
关系型数据库 MySQL
Mysql基础第三十天,全球化和本地化
Mysql基础第三十天,全球化和本地化
25 0
Mysql基础第三十天,全球化和本地化
|
4月前
|
Java 关系型数据库 MySQL
【从0配置JAVA项目相关环境1】jdk + VSCode运行java + mysql + Navicat + 数据库本地化 + 启动java项目
【从0配置JAVA项目相关环境1】jdk + VSCode运行java + mysql + Navicat + 数据库本地化 + 启动java项目
116 0
|
存储 关系型数据库 PostgreSQL
PostgreSQL 10.1 手册_部分 III. 服务器管理_第 23 章 本地化
第 23 章 本地化 目录 23.1. 区域支持 23.1.1. 概述 23.1.2. 行为 23.1.3. 问题 23.2. 排序规则支持 23.2.1. 概念 23.2.2. 管理排序规则 23.3. 字符集支持 23.3.1. 被支持的字符集 23.3.2. 设置字符集 23.3.3. 服务器和客户端之间的自动字符集转换 23.3.4. 进一步阅读 本章从管理员的角度描述可用的本地化特性。
1163 0
|
关系型数据库 Unix 数据库
PostgreSQL 10.1 手册_部分 III. 服务器管理_第 23 章 本地化_23.3. 字符集支持
23.3. 字符集支持 23.3.1. 被支持的字符集 23.3.2. 设置字符集 23.3.3. 服务器和客户端之间的自动字符集转换 23.3.4. 进一步阅读 PostgreSQL里面的字符集支持你能够以各种字符集存储文本,包括单字节字符集,比如 ISO 8859 系列,以及多字节字符集 ,比如EUC(扩展 Unix 编码 Extended Unix Code)、UTF-8 和 Mule 内部编码。
1190 0
|
SQL 关系型数据库 数据库
PostgreSQL 10.1 手册_部分 III. 服务器管理_第 23 章 本地化_23.2. 排序规则支持
23.2. 排序规则支持 23.2.1. 概念 23.2.2. 管理排序规则 排序规则特性允许指定每一列甚至每一个操作的数据的排序顺序和字符分类行为。这放松了数据库的LC_COLLATE和LC_CTYPE设置自创建以后就不能更改这一限制。
1133 0
|
关系型数据库 数据库 PostgreSQL
PostgreSQL 10.1 手册_部分 III. 服务器管理_第 23 章 本地化_23.1. 区域支持
23.1. 区域支持 23.1.1. 概述 23.1.2. 行为 23.1.3. 问题 区域支持指的是应用遵守文化偏好的问题,包括字母表、排序、数字格式等。PostgreSQL使用服务器操作系统提供的标准 ISO C 和POSIX的区域机制。
1527 0
|
Java 关系型数据库 数据库
PostgreSQL服务器管理:本地化
本章从管理员的角度描述可用的本地化特性。PostgreSQL支持两种本地化方法: 利用操作系统的区域(locale)特性,提供对区域相关的排序顺序、数字格式、 翻译过的信息和其它方面。 提供一些不同的字符集来支持存储所有种类语言的文本,并提供在客户端和服务器之间的字符集转换。
1673 0
|
2天前
|
SQL 存储 关系型数据库
MySQL Cluster集群安装及使用
MySQL Cluster集群安装及使用
|
17天前
|
关系型数据库 MySQL 数据库
mysql卸载、下载、安装(window版本)
mysql卸载、下载、安装(window版本)
|
6天前
|
关系型数据库 MySQL 数据库
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
《MySQL 简易速速上手小册》第1章:MySQL 基础和安装(2024 最新版)
29 4