1

我有以下功能:

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在找不到资源时强制它抛出,那就没有必要了......

4

1 回答 1

3

您可以使用:

GET DIAGNOSTICS integer_var = ROW_COUNT;

..并让函数返回计数。手册中的详细信息。

例子:

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语句也锁定了该行。无需手动锁定FOR UPDATE

添加的OUT del_ct int声明了一个OUT可以像任何变量一样分配的参数,并在函数结束时自动返回。它还消除了对显式RETURNS声明的需要。

于 2013-08-12T18:37:58.750 回答