来自 Postgres 存储过程的意外 OUT 值

Unexpected OUT value from Postgres Stored Procedure

使用 Postgres10。

我遇到了一个问题,我正在调用一个存储过程并期望我的 OUT 参数有一个特定的值,但我没有得到它。我正在使用下面的调用代码调用 Items 存储过程。

问题 我希望我第一次调用 Item 存储过程来获取 rtn 值为 1 的插入,但我得到的是 4...这意味着 IF EXISTS 在 table 中找到具有相同名称但我的 table 是空的。

我预计在 INSERT 语句之后重新评估 IF EXISTS 语句并进入 rtn 设置为 4 的块时会发生一些奇怪的事情。这与 plpgsql 有关吗?当我放入 Raise 命令以测试某些点的值时,就好像存储过程的顺序并不总是从上到下。

SCHEMA/TABLE

CREATE TABLE aips.Item (
 ItemPk SERIAL PRIMARY KEY,
 Name VARCHAR(100) NOT NULL,
 CONSTRAINT UNI_Item_Name UNIQUE(Name)
);

存储过程

CREATE OR REPLACE FUNCTION aips.Item(
    INOUT p_ItemPk INT,
    INOUT p_Name VARCHAR(100),
    OUT rtn INT
) AS
$$
DECLARE rowcnt INT;
BEGIN
  -- Insert or Find Path
  IF p_ItemPk IS NULL THEN

    -- Check for Find
    IF EXISTS (SELECT * FROM aips.Item where Name = p_Name) THEN
        SELECT ItemPk, Name
        INTO p_ItemPk, p_Name
        FROM aips.Item
        WHERE Name = p_Name;

        rtn := 4;
        RETURN;
    END IF;

    -- Perform insert
    INSERT INTO aips.Item (Name)
    VALUES (p_Name)
    RETURNING ItemPk INTO p_ItemPk;
    GET DIAGNOSTICS rowcnt = ROW_COUNT;

    IF rowcnt = 1 THEN
      rtn := 1;
    ELSE
      rtn := 0;
      RAISE EXCEPTION 'Expecting to insert a single row and rows returned --> %', rowcnt;
    END IF;

  ELSE -- Update or No Operation Path

    -- Check for no changes
    IF EXISTS (SELECT ItemPk 
               FROM aips.Item 
               WHERE ItemPk = p_ItemPk
               AND Name = p_Name) THEN
        rtn := 5;
        RETURN;
    END IF;

    -- Perform Update
    UPDATE aips.Item 
    SET Name = p_Name
    WHERE ItemPk = p_ItemPk;
    GET DIAGNOSTICS rowcnt = ROW_COUNT;

    IF rowcnt = 1 THEN
      rtn := 2;
    ELSE
      rtn := 0;
      RAISE EXCEPTION 'Expecting to update a single row and rows returned --> %', rowcnt;
    END IF;
  END IF;

  RETURN;
END;
$$ LANGUAGE plpgsql;

呼叫

select (aips.Item(NULL, 'Test 1')).*;

问题是你调用函数的方式:

select (aips.Item(NULL, 'Test 1')).*; -- WRONG!

因为执行了三次,每个输出列一次。该函数应在 FROM 子句中调用:

select * from aips.Item(NULL, 'Test 1');