如何保证一个存储函数总是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
的值
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;
使用以下存储函数我想验证用户数据:
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
的值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;