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

Roo*_*lem 6 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;
Run Code Online (Sandbox Code Playgroud)

2.导致异常的场景:

a)一个客户端不断地使用 tmp._my_testfunction() 像这样

SELECT tmp._my_testfunction()
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

c) 不断使用 tmp._my_testfunction() 的客户端立即抛出

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

我怎样才能防止这种情况发生?

Roo*_*lem 1

由于我们找不到其他方法来解决此问题,因此我们实现了一个解决方案,通过使用 LISTEN 和 NOTIFY 命令通知所有其他连接自行刷新。因此,所有客户端都在特定通道上监听告诉它们重新连接的命令。然后,该命令将在删除该类型的同一事务中发送。