无法在 PostgreSQL 11.5 中创建 COMMIT 过程

Dam*_*yer 3 postgresql plpgsql

我正在尝试学习 PostgreSQL 存储过程。具体在 PSQL 中创建以下过程。

CREATE OR REPLACE PROCEDURE BUILD_AND_POPULATE(INOUT cresults refcursor) 
    LANGUAGE PLPGSQL 
    AS $$
    BEGIN
        BEGIN; -- I've tried removing this but the behaviour is the same
        cresults:= 'cur';
        DROP TABLE IF EXISTS procsampledata;
        CREATE TABLE procsampledata as select x,1 as c2,2 as c3, md5(random()::text) from generate_series(1,10) x;  
        COMMIT;
        OPEN cresults FOR SELECT * FROM procsampledata;  
    END;
$$;
Run Code Online (Sandbox Code Playgroud)

然后我像这样执行它,但收到一个错误:

postgres=# call build_and_populate(null);
ERROR:  invalid transaction termination
CONTEXT:  PL/pgSQL function build_and_populate(refcursor) line 6 at COMMIT
Run Code Online (Sandbox Code Playgroud)

我试过将 AUTOCOMMIT 设置为打开和关闭。

这是我的 Postgres 版本

 PostgreSQL 11.5 on x86_64-pc-linux-musl, compiled by gcc (Alpine 8.3.0) 8.3.0, 64-bit
Run Code Online (Sandbox Code Playgroud)

谁能看到我做错了什么?谢谢!

Lau*_*lbe 5

BEGIN;
Run Code Online (Sandbox Code Playgroud)

是错误的,会导致错误。您不能在过程中启动事务,因为已经有一个活动事务。

您可以结束一个事务,这意味着立即开始一个新事务。

如果没有BEGIN;,您的程序就可以正常工作。

问题一定出在你调用它的方式上。正如文档所说:

事务控制只能在CALLDO来自顶层的调用或嵌套的 CALL 或 DO 调用中进行,而没有任何其他干预命令。例如,如果调用堆栈是CALL proc1()CALL proc2()CALL proc3(),那么第二个和第三个过程可以执行事务控制动作。但是如果调用栈是CALL proc1()SELECT func2()CALL proc3(),那么最后一个过程不能做事务控制,因为SELECT中间。

SELECT您的调用堆栈中可能有一个。

另一种可能性是您BEGIN 调用存储过程之前显式启动了一个事务。

这也不起作用,这是一个未记录的实现限制,将来可能会修复。请参阅此线程以供参考。

  • 谢谢劳伦斯。我认为你可能正在做某事。我重新删除了 BEGIN; 语句,并注释掉过程中的 select 语句,看看它们是否影响它。他们没有任何区别。我认为我的调用堆栈中没有 SELECT ,因为据我所知,我没有调用堆栈。我创建程序,调用BEGIN;然后打电话。我注意到一件事,只有在我执行 BEGIN 时它才会失败;在呼叫之前。是这个问题吗?如果是这样,那么这是否意味着无法从过程中返回游标,因为(在我的理解中)它们无法在交易后继续存在 (2认同)