本文正在参加「金石计划」
PostgreSQL导入备份错误: 用于编码 "UTF8" 的 "pg_catalog.ja_JP.utf8" 排序规则不存在
使用 PostgreSQL 导入备份时,碰到了一个奇葩问题,折腾了好长时间才解决,在这里记录一下。
备份是从云上的 Linux 服务器导出的,使用的是网页版的 pgAdmin 。
错误
错误信息:
pg_restore: エラー: could not execute query: ERROR: エンコーディング"UTF8"の照合順序"pg_catalog.ja_JP.utf8"は存在しません
对日外包,所以提示一堆日语。
英语版的错误信息应该如果下:
collation "pg_catalog.ja_JP.utf8" for encoding "UTF8" does not exist
中文版可能如下:
用于编码 "UTF8" 的 "pg_catalog.ja_JP.utf8" 排序规则不存在
出现错误的过程及原因
从 Linux 服务器导出的备份中的建表 SQL 如下:
CREATE TABLE public.test (
id character varying(16) NOT NULL,
name character varying COLLATE pg_catalog."ja_JP.utf8",
ins_dt timestamp(6) without time zone DEFAULT now() NOT NULL,
upd_dt timestamp(6) without time zone DEFAULT now() NOT NULL
);
在 Windows 和 Mac 中导入都出现了上面的错误。
导入用的语句:
$ psql -U postgres -f backup.sql
原因是操作系统不支持建表 SQL 中的区域语言 pg_catalog."ja_JP.utf8"。
需要修改成操作系统支持的区域语言。
可能不做对日外包项目的,遇到该问题的可能性不大。
Windows 上的解决方法
-
查看本地数据库的 Collation 。
一开始用
SHOW LC_COLLATE;和
SELECT name, setting, context FROM pg_settings WHERE name LIKE 'lc%';来确认 Collation 。
查询出来的结果都是
Japanese_Japan.utf8。但是按照网上的方式把 建表 SQL 中的
ja_JP.utf8改成Japanese_Japan.utf8后,依然还是同样的错误。然后又找到了另外一种查看 Collation 的方式。
SELECT * from pg_collation WHERE collname LIKE '%ja%';因为是 日语系统,所以加了一个条件。
查询结果是
ja-x-icu和ja_JP-x-icu,我也不知道两者的区别。 -
修改数据库备份里的建表语句。
改为
ja-x-icu和ja_JP-x-icu的其中之一,我这里改成了ja-x-icu,另一个没有试。CREATE TABLE public.test ( id character varying(16) NOT NULL, name character varying COLLATE pg_catalog."ja-x-icu", ins_dt timestamp(6) without time zone DEFAULT now() NOT NULL, upd_dt timestamp(6) without time zone DEFAULT now() NOT NULL ); -
再次导入。
运行
psql命令再次导入备份, 就能正常创建表了。
只能算是一个折中的解决方法吧。
Mac 上的解决方法
Mac 上可以运行 locale 命令确认当前的语言。
```
$ locale
LANG="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_CTYPE="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_ALL=
```
locale -a 可以查看所有的语言。
奇葩的是,Mac 上支持的日语是 ja_JP.UTF-8 , 而不是上面导入的 SQL 中的 ja_JP.utf8 。相差一个 - 。
所以导入时照样提示最上面的错误信息。
解决方法和 Windows 一样,把备份 SQL 中的 ja_JP.utf8 改成 ja_JP.UTF-8 再次导入。
```sql
CREATE TABLE public.test (
id character varying(16) NOT NULL,
name character varying COLLATE pg_catalog."ja_JP.UTF-8",
ins_dt timestamp(6) without time zone DEFAULT now() NOT NULL,
upd_dt timestamp(6) without time zone DEFAULT now() NOT NULL
);
```
后记
Linux 、Windows 、 Mac 对 locale (语言区域)的支持都不一样,所以从其中某个系统的 PostgreSQL 数据库中备份出来的数据有可能不能直接导入另一个系统的 PostgreSQL 数据库中。
因为解决这个问题花了太多时间,所以在这里记录一下。
本文正在参加「金石计划」