1

使用以下存储功能,我想验证用户数据:

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 对象数组时调用它 -RAISE EXCEPTION如果它返回FALSE任何 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()返回NULL而不是布尔值。

COALESCE可以在-statement中围绕check_user()调用...但是是否有更好的方法来解决这个问题?IF

4

3 回答 3

1

我会在 check_user() 函数中添加合并,所以它总是返回 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 的值

于 2016-03-02T09:41:18.440 回答
1

支票[not] 不同于

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

但请注意,如果双方都对null比较进行评估,则会返回true

对于非空输入,IS DISTINCT FROM 与 <> 运算符相同。但是,如果两个输入都为 null,则返回 false,如果只有一个输入为 null,则返回 true。同样,对于非空输入,IS NOT DISTINCT FROM 与 = 相同,但当两个输入都为空时返回 true,当只有一个输入为空时返回 false。因此,这些构造实际上就像 null 是一个正常的数据值一样,而不是“未知”。

更简单的是只声明函数strict并将返回值与is not true

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

STRICT 表示只要函数的任何参数为空,该函数总是返回空。如果指定了这个参数,当有空参数时函数不执行;而是自动假定为空结果。

这具有避免执行功能的任何成本的额外好处。

于 2016-03-02T14:29:34.787 回答
0

这是我可能会使用的,因为该功能与安全相关,因此我不想在将来使用它时记住任何边缘情况(例如在将其IF check_user(...) IS NOT TRUE声明为时强制使用) -STRICT

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;
于 2016-03-02T18:35:28.900 回答