使用以下存储的函数,我想验证用户数据:
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对象数组时调用它 - 如果它为任何JSON对象返回RAISE EXCEPTION
,它将FALSE
(从而回滚整个事务)。
我没有在这里转储我的第二个存储函数的源代码,而是在下面准备了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;
第3个功能无法按预期工作并打印valid user
。
这是因为check_user()
返回NULL
而不是布尔值。
COALESCE
可以围绕check_user()
语句中的IF
调用进行处理......但是有没有更好的方法可以解决这个问题?
答案 0 :(得分:1)
我会在check_user()函数中添加coalesce,因此它总是返回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的值
答案 1 :(得分:1)
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,而当只有一个输入为null时返回false。因此,这些结构有效地表现为null是正常数据值,而不是“未知”。
更简单的是只声明函数strict
并将返回值与is not true
进行比较:
if check_user(42, 'user1', null) is not true then raise notice 'invalid user';
STRICT表示只要其任何参数为null,该函数始终返回null。如果指定了此参数,则在存在null参数时不执行该函数;而是自动假设空结果。
这具有避免执行该功能的任何成本的额外好处。
答案 2 :(得分:0)
以下是我可能会使用的内容,因为该功能与安全相关,因此我不想记住任何边缘情况(例如在将IF check_user(...) IS NOT TRUE
声明为{{1}时强制使用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;