如何保证一个存储函数总是returns TRUE or FALSE?

How to ensure that a stored function always returns TRUE or FALSE?

使用以下存储函数我想验证用户数据:

CREATE OR REPLACE FUNCTION check_user(
        in_social integer,
        in_sid varchar(255),
        in_auth varchar(32))
        RETURNS boolean AS
$func$
        SELECT MD5('secret word' || in_social || in_sid) = in_auth;
$func$ LANGUAGE sql IMMUTABLE;

我将在另一个存储函数中循环遍历 JSON 对象数组时调用它 - 如果它 returns FALSE 中的任何一个,我将 RAISE EXCEPTION JSON 个对象(从而回滚整个事务)。

我没有在这里转储我的第二个存储函数的源代码,而是在下面准备了 3 个简单的测试函数 -

CREATE OR REPLACE FUNCTION test1() RETURNS void AS
$func$
BEGIN
        IF NOT check_user(42, 'user1', '56db1046fa7b664c9b3d05bf7413552a') THEN
                RAISE NOTICE 'invalid user';
        ELSE
                RAISE NOTICE 'valid user';
        END IF;
END
$func$ LANGUAGE plpgsql;

第一个函数按预期工作并打印 valid user.

CREATE OR REPLACE FUNCTION test2() RETURNS void AS
$func$
BEGIN
        IF NOT check_user(42, 'user2', '56db1046fa7b664c9b3d05bf7413552a') THEN
                RAISE NOTICE 'invalid user';
        ELSE
                RAISE NOTICE 'valid user';
        END IF;
END
$func$ LANGUAGE plpgsql;

第二个函数按预期工作并打印 invalid user.

CREATE OR REPLACE FUNCTION test3() RETURNS void AS
$func$
BEGIN
        IF NOT check_user(42, 'user1', NULL) THEN
                RAISE NOTICE 'invalid user';
        ELSE
                RAISE NOTICE 'valid user';
        END IF;
END
$func$ LANGUAGE plpgsql;

第三个函数 没有按预期工作 并打印 valid user.

发生这种情况是因为 check_user() returns NULL 而不是布尔值。

COALESCE 可以包含在 IF 语句中的 check_user() 调用...但是是否有更好的方法来解决这个问题?

我会在 check_user() 函数中添加合并,因此它总是 returns true 或 false。

    SELECT MD5('secret word' || in_social || in_sid) = coalesce(in_auth,'');

或者甚至下面的选项,以防其他值也可能为 NULL :

    SELECT MD5('secret word' || coalesce(in_social,-1)::varchar || coalesce(in_sid,'')) = coalesce(in_auth,'');

在那里“-1”一个永远不会分配给 in_social

的值

勾选is [not] distinct from

select md5('secret word' || in_social || in_sid) is not distinct from in_auth;

但请注意,如果双方都评估为 null,则比较将 return true:

For non-null inputs, IS DISTINCT FROM is the same as the <> operator. However, if both inputs are null it returns false, and if only one input is null it returns true. Similarly, IS NOT DISTINCT FROM is identical to = for non-null inputs, but it returns true when both inputs are null, and false when only one input is null. Thus, these constructs effectively act as though null were a normal data value, rather than "unknown".

更简单的是声明函数 strict 并将 returned 值与 is not true:

进行比较
if check_user(42, 'user1', null) is not true then raise notice 'invalid user';

STRICT indicates that the function always returns null whenever any of its arguments are null. If this parameter is specified, the function is not executed when there are null arguments; instead a null result is assumed automatically.

这样做的额外好处是可以避免执行函数的任何成本。

这是我可能会使用的,因为该函数与安全相关,因此我不想记住任何边缘情况(比如在声明为 [=12 时强制使用 IF check_user(...) IS NOT TRUE =]) 以后使用时 -

CREATE OR REPLACE FUNCTION check_user(
        in_social integer, 
        in_sid varchar(255), 
        in_auth varchar(32))
        RETURNS boolean AS
$func$
        SELECT CASE 
                WHEN in_social IS NULL THEN FALSE
                WHEN in_sid    IS NULL THEN FALSE
                WHEN in_auth   IS NULL THEN FALSE
                ELSE (MD5('secret word' || in_social || in_sid) = in_auth)
        END;

$func$ LANGUAGE sql IMMUTABLE;