Postgres drop类型XX000“缓存查找类型失败”

时间:2014-11-20 09:12:24

标签: postgresql

我目前正在开发一个PostgreSQL 9.2.x数据库,它包含许多客户端,表和函数。我们不断部署代码,有时甚至需要删除由于此部署而导致的类型或功能。

示例:

1.首先创建所需功能的脚本

CREATE TYPE tmp._myEnum AS ENUM ('OLD', 'NEW', 'BOTH'); 

CREATE OR REPLACE FUNCTION tmp._get_status()
RETURNS tmp._myEnum AS
$BODY$
BEGIN
    RETURN 'OLD'::tmp._myEnum;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 10;


CREATE OR REPLACE FUNCTION tmp._my_testfunction()
RETURNS VOID AS
$BODY$
BEGIN
    CASE tmp._get_status()
        WHEN 'OLD'::tmp._myEnum THEN 
            RAISE INFO 'myEnum is OLD';
        WHEN 'NEW'::tmp._myEnum THEN 
            RAISE INFO 'myEnum is NEW';
        WHEN 'BOTH'::tmp._myEnum THEN 
            RAISE INFO 'myEnum is BOTH';
        ELSE
            RAISE INFO 'myEnum has an unexpected value';
    END CASE;

    FOR i IN 1..10 LOOP
        RAISE INFO 'Step [%]',i;
    END LOOP;
    RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 10;

2.导致异常的场景:

a)一个客户端一直在使用tmp._my_testfunction(),如下所示

SELECT tmp._my_testfunction()

b)为了将更改部署到我在另一个会话中执行的复合类型

DROP FUNCTION IF EXISTS tmp._get_status();
DROP TYPE IF EXISTS tmp._myEnum;

CREATE TYPE tmp._myEnum AS ENUM ('OLD', 'NEW', 'BOTH','NOTHING'); 

CREATE OR REPLACE FUNCTION tmp._get_status()
RETURNS tmp._myEnum AS
$BODY$
BEGIN
    RETURN 'OLD'::tmp._myEnum;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER COST 10;

c)持续使用tmp._my_testfunction()的客户端imidiatly throws

ERROR:  cache lookup failed for type 386318
CONTEXT:  PL/pgSQL function tmp._my_testfunction() line 3 at CASE

我该如何防止这种情况?

1 个答案:

答案 0 :(得分:0)

这里的情况似乎是竞争条件。您的客户端调用tmp._my_test_function()并在通过解释函数的源代码进行设置时,删除函数和enum类型,然后重新创建它们。在内部,几乎所有对象都由oid引用(对于您的案例类型,值为386318),因此函数和客户端函数中的enum将解析为oid。如果解释器解析了函数,并且enum解析为oid,然后删除函数和enum并重新创建它们,则旧oid消失,您新创建的函数和enum获得不同的oid。函数的新调用将起作用,因为解释器为函数和oid找到新的enum

在这种情况下的解决方案是客户端函数上的REVOKE EXECUTE,进行更改,然后再次GRANT EXECUTE权限。在客户端,您必须通过重试函数调用来处理权限错误,直到成功为止。

通常,如果要避免重试函数调用的开销,可以在低流量时段和/或通过会话管理在生产服务器上部署新代码。