PostgreSQL导入备份错误: 用于编码 "UTF8" 的 "pg_catalog.ja_JP.utf8" 排序规则不存在

1,981 阅读1分钟

本文正在参加「金石计划」


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 上的解决方法

  1. 查看本地数据库的 Collation 。

    一开始用

    SHOW LC_COLLATE;
    

    SELECT name, setting, context FROM pg_settings WHERE name LIKE 'lc%';
    

    来确认 Collation 。

    查询出来的结果都是 Japanese_Japan.utf8

    image.png

    但是按照网上的方式把 建表 SQL 中的 ja_JP.utf8 改成 Japanese_Japan.utf8 后,依然还是同样的错误。

    然后又找到了另外一种查看 Collation 的方式。

    SELECT * from pg_collation
    WHERE collname LIKE '%ja%';
    

    因为是 日语系统,所以加了一个条件。

    查询结果是 ja-x-icuja_JP-x-icu ,我也不知道两者的区别。

    image.png

  2. 修改数据库备份里的建表语句。

    改为 ja-x-icuja_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
    );
    
  3. 再次导入。

    运行 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 数据库中。

因为解决这个问题花了太多时间,所以在这里记录一下。


本文正在参加「金石计划」