Postgres数据库还原时去除重音问题

3

我希望能够将一个特定的数据库以另一个名称还原到另一个服务器上。到目前为止,一切都很好。

我使用了以下命令:

pg_dump -U postgres -F c -O -b -f maindb.dump maindb

在生产服务器上转储主数据库。我使用以下命令:

 pg_restore --verbose -O -l -d restoredb maindb.dump

在我们的测试服务器上将数据库恢复到另一个数据库。它基本上恢复正常,但有一些错误,例如:

pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 3595; 1259 213452 INDEX idx_clientnomclient maindbuser
pg_restore: [archiver (db)] could not execute query: ERROR:  function unaccent(text) does not exist
LINE 1:  SELECT unaccent(lower($1)); 
                ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
QUERY:   SELECT unaccent(lower($1)); 
CONTEXT:  SQL function "cyunaccent" during inlining
Command was: CREATE INDEX idx_clientnomclient ON client USING btree (public.cyunaccent((lower((nomclient)::text))::character varying));

cyunaccent是公共模式中的一个函数,它会随着恢复而创建。

在恢复完成后,我可以使用相同的SQL完美地重新创建这些索引,没有任何错误。

我还尝试使用pg_restore的-i选项以执行单个事务进行恢复,但这并没有起到作用。

我做错了什么?


看起来问题的源头是缺失了某些函数。unaccent(text)是第一个出现问题的函数。你确定它已经从备份中重新创建了吗? - wilsotc
是的,它正在被重新创建。当pg_restore完成时,函数存在,并且我能够执行创建索引而没有错误。我将恢复操作执行到一个新创建的数据库中,在那个点(恢复之前),它并不存在。 - nicolasross
可能是以错误的顺序重新创建了它。 - wilsotc
Unaccent似乎是文本搜索功能的一部分。它是否安装在目标机器上?您以postgres用户身份运行恢复操作吗? - wildplasser
是的,因为目标机器上的其他数据库都有它。我最初尝试以DB所有者身份进行还原,但还原的某些部分出现了问题,比如创建扩展。所以最终我以postgres用户的身份完成了操作。@wilsotc 我相信这样做是可行的,因为之后可以重新创建索引。但这样做非常难以编写脚本... - nicolasross
1个回答

4

我刚刚发现了一个问题,并且我已经能够将它缩小到一个简单的测试案例。

CREATE SCHEMA intranet;
CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public;
SET search_path = public, pg_catalog;
CREATE FUNCTION cyunaccent(character varying) RETURNS character varying
    LANGUAGE sql IMMUTABLE
    AS $_$ SELECT unaccent(lower($1)); $_$;
SET search_path = intranet, pg_catalog;
CREATE TABLE intranet.client (
    codeclient character varying(10) NOT NULL,
    noclient character varying(7),
    nomclient character varying(200) COLLATE pg_catalog."fr_CA"
 );
ALTER TABLE ONLY client ADD CONSTRAINT client_pkey PRIMARY KEY (codeclient);
CREATE INDEX idx_clientnomclient ON client USING btree (public.cyunaccent((lower((nomclient)::text))::character varying));

这个测试用例是从以纯文本形式进行的pg_dump中提取的。

正如您所看到的,cyunaccent函数是在公共模式中创建的,因为它后来被其他模式中的其他表使用。

psql/pg_restore不会重新创建索引,因为它找不到该函数,尽管指定了模式名称以引用它。问题出在

SET search_path = intranet, pg_catalog;

调用。将其更改为

SET search_path = intranet, public, pg_catalog;

解决了问题。我已向PostgreSQL提交了一份关于此问题的错误报告,但尚未进入队列。


3
另外,将函数更改为:SELECT public. unaccent(lower($1)) 可以完全解决这个问题。因此,最终只是函数内缺少模式规范。 - nicolasross
你的错误报告得到了关注吗?我在2021年仍然遇到这个问题。 - isset
1
@isset 不是因为PG本身的错误,而是函数定义方式导致的问题。该函数现在被定义为:CREATE OR REPLACE FUNCTION public.cyunaccent(character varying) RETURNS character varying AS ' SELECT lower(public.unaccent($1)); ' LANGUAGE sql IMMUTABLE COST 100;在我们的数据库中,从而解决了这个问题。 - nicolasross
@nicolasross,关于需要显式设置模式规范的文档有些吗?在我的情况下,函数和pg_restore已经在正确的模式中,所以我不明白为什么我们需要显式设置它。 - Nicholas
没事了,我找到了:https://dev59.com/_Lzpa4cB1Zd3GeqPStdd#63518355 - Nicholas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接