计算受plpgsql函数影响的行

时间:2013-08-12 17:51:35

标签: php postgresql pdo count plpgsql

我有以下功能:

CREATE FUNCTION user_delete(IN id INT4)
  RETURNS VOID
AS
  $BODY$
  BEGIN
    SELECT * FROM "user" WHERE user_id = id FOR UPDATE;
    DELETE FROM user_role WHERE user_id = id;
    DELETE FROM user_permission WHERE user_id = id;
    DELETE FROM permission_cache WHERE user_id = id;
    DELETE FROM access WHERE user_id = id;
    DELETE FROM "user" WHERE user_id = id;
  END;
  $BODY$
LANGUAGE plpgsql VOLATILE;

我在PHP PDO中使用它:

$stmt = $pdo->prepare('SELECT * FROM user_delete(?)');
$stmt->execute(array($user['id']));

结果现在包含

array(
    array('user_delete' => '')
)

$stmt->rowCount();

总是一个。

是否有可能解决这个问题:函数返回什么(因为它是无效的),并且由rowCount返回受影响行的计数?

解决方案:

PHP:

public function delete($id)
{
    try {
        $this->__call('user_delete', array($id));
    } catch (\PDOException $e) {
        if ($e->getCode() === 'UE404')
            throw new NotFoundException();
        else
            throw $e;
    }
}

SQL:

CREATE FUNCTION user_delete(IN id INT4)
  RETURNS VOID
AS
  $BODY$
  BEGIN
    DELETE FROM user_role WHERE user_id = id;
    DELETE FROM user_permission WHERE user_id = id;
    DELETE FROM permission_cache WHERE user_id = id;
    DELETE FROM access WHERE user_id = id;
    DELETE FROM "user" WHERE user_id = id;
    IF NOT FOUND THEN
      RAISE SQLSTATE 'UE404' USING MESSAGE = 'not found for delete';
    END IF;
  END;
  $BODY$
LANGUAGE plpgsql VOLATILE;

我可以使用setof void返回类型获得返回零长度的结果,但是如果我在找不到资源时强制它抛出PDOException,则没有必要...

1 个答案:

答案 0 :(得分:1)

您可以使用:

GET DIAGNOSTICS integer_var = ROW_COUNT;

..让函数返回计数。 Details in the manual.

示例:

CREATE OR REPLACE FUNCTION user_delete(id int, OUT del_ct int) AS
$func$
DECLARE
   i int;  -- helper var
BEGIN
   DELETE FROM user_role WHERE user_id = $1;
   GET DIAGNOSTICS del_ct = ROW_COUNT;  -- init

   DELETE FROM user_permission WHERE user_id = $1;
   GET DIAGNOSTICS i = ROW_COUNT;  del_ct := del_ct + i;

   DELETE FROM permission_cache WHERE user_id = $1;
   GET DIAGNOSTICS i = ROW_COUNT;  del_ct := del_ct + i;

   DELETE FROM access WHERE user_id = $1;
   GET DIAGNOSTICS i = ROW_COUNT;  del_ct := del_ct + i;

   DELETE FROM "user" WHERE user_id = $1;
   GET DIAGNOSTICS i = ROW_COUNT;  del_ct := del_ct + i;
END
$func$  LANGUAGE plpgsql;

你有这个作为第一个声明:

SELECT * FROM "user" WHERE user_id = $1 FOR UPDATE;

语法无效 - 在plpgsql函数中,您需要将PERFORM用于没有目标的SELECT语句:

PERFORM * FROM "user" WHERE user_id = $1 FOR UPDATE;

但随后的DELETE语句也会锁定行。无需manual locking with FOR UPDATE开始。

添加的OUT del_ct int声明OUT参数,可以像任何变量一样分配,并在函数结束时自动返回。它也不需要明确的RETURNS声明。