0

我使用 Patroni 创建了一个具有 3 个节点的 PostgreSQL 集群。

我正在使用 Ubuntu 18.04、Postgresql-10 和 Timescaledb 1.4.2。

postgresql.conf我包含的文件中shared_preload_libraries = 'timescaledb'

使用命令扩展postresqltimescaledb

CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; 

它给出了错误

错误:函数 1 的缓存查找失败

4

1 回答 1

1

所以,总结一下我们关于 Slack 的讨论,这就是问题所在。我在这里总结一下,因为它对遇到类似问题的其他人很有用。

TD;博士。您在这台机器上的所有扩展都遇到了问题,不仅是 TimescaleDB,而且问题结果与创建扩展正在执行的新 C 函数有关。

当定义函数时,PostgreSQL 会在LANGUAGE(在这种情况下C)之后的部分,并在pg_languages. 代码CreateFunction在文件中functioncmds.c

在您的情况下,pg_languages包含:

SELECT * FROM pg_languages;
lanname  | lanowner | lanispl | lanpltrusted | lanplcallfoid | laninline | lanvalidator | lanacl
----------+----------+---------+--------------+---------------+-----------+--------------+--------
internal |       10 | f       | f            |             0 |         0 |         2246 |
sql      |       10 | f       | t            |             0 |         0 |         2248 |
plpgsql  |       10 | t       | t            |         13005 |     13006 |        13007 |
c        |       10 | f       | f            |             0 |         0 |            1 |
(4 rows)

从上表中可以看出,语言验证器(我们的罪魁祸首)的 OID 为 1。

一旦完成,PostgreSQL 将使用要定义的函数调用验证器,并允许验证器检查函数是否正确定义。这是在ProcedureCreate文件中完成的pg_proc.c

它通过在表中查找函数的 OID 来进行pg_proc,在您的情况下,该 OID 包含:

SELECT oid, proname FROM pg_proc WHERE oid = 1;
oid | proname
-----+---------
(0 rows)

因此,没有找到语言验证器的过程,它在此处生成错误(这是在里面fmgr_info_cxt_securityfmgr.c

    /* Otherwise we need the pg_proc entry */
    procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
    if (!HeapTupleIsValid(procedureTuple))
        elog(ERROR, "cache lookup failed for function %u", functionId);
    procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);

可以通过查找要使用的正确语言验证器来解决此问题。所有内置验证器都已命名fmgr_<lang>_validator,因此我们可以使用以下方法找到它们:

SELECT oid, proname FROM pg_proc WHERE proname LIKE '%fmgr%validator%';
 oid  |         proname         
------+-------------------------
 2246 | fmgr_internal_validator
 2247 | fmgr_c_validator
 2248 | fmgr_sql_validator
(3 rows)

因此,此查询将更新lanvalidator列以使用正确的验证器。

UPDATE pg_languages
   SET lanvalidator = (SELECT oid FROM pg_proc WHERE proname = 'fmgr_c_validator')
 WHERE lanname = 'c'

请注意,这解释了为什么会出现错误,但不能解释为什么pg_languages包含错误的 OIDlanvalidator列。我们假设它可能发生在故障转移期间,因为您发生了一些促销活动,但最终,这只是纯粹的猜测。

于 2019-10-31T07:52:08.533 回答