Postgresql 选择并使用一列 请考虑下面的存储过程。此函数接收一个整数作为其第一个参数,指示必须针对当前用户检查哪个privilegeid。特权存储在“特权”表中,由id和名称varchar组成
每个权限属于存储在用户\角色中的一个或多个角色。每个用户被分配到一个或多个角色。此函数检索分配给当前_用户的所有角色,并根据给定的priviligeid检查它们(如前所述)Postgresql 选择并使用一列 请考虑下面的存储过程。此函数接收一个整数作为其第一个参数,指示必须针对当前用户检查哪个privilegeid。特权存储在“特权”表中,由id和名称varchar组成,postgresql,stored-procedures,plpgsql,Postgresql,Stored Procedures,Plpgsql,每个权限属于存储在用户\角色中的一个或多个角色。每个用户被分配到一个或多个角色。此函数检索分配给当前_用户的所有角色,并根据给定的priviligeid检查它们(如前所述) CREATE OR REPLACE FUNCTION "public"."has_privilege" (in int4) RETURNS bool AS $BODY$ DECLARE asked_privilegeid ALIAS FOR $1; userid int; role_row users
CREATE OR REPLACE FUNCTION "public"."has_privilege" (in int4) RETURNS bool AS
$BODY$
DECLARE
asked_privilegeid ALIAS FOR $1;
userid int;
role_row users_roles%rowtype;
privilege_row privileges%rowtype;
BEGIN
EXECUTE 'SELECT userid FROM users WHERE username=$1' INTO userid USING current_user;
FOR role_row IN SELECT * FROM users_roles
WHERE userid=userid
LOOP
IF role_row.roleid = 1 THEN
return TRUE;
END IF;
FOR privilege_row IN SELECT * FROM privileges WHERE roleid=role_row.roleid LOOP
IF privilege_row.privilegeid = asked_privilegeid THEN
return TRUE;
END IF;
END LOOP;
END LOOP;
return FALSE;
END
$BODY$
LANGUAGE 'plpgsql'
然而,这段代码并不是一个有效的方法,因为它可能会考虑检索用户的所有rowValue\u角色和权限。我试图按照以下方式编写过程,但似乎不起作用:
CREATE OR REPLACE FUNCTION "public"."has_privilege" (in int4) RETURNS bool AS
$BODY$
DECLARE
asked_privilegeid ALIAS FOR $1;
privilegeid int;
userid int;
roleid int;
//role_row users_roles%rowtype;
//privilege_row privileges%rowtype;
BEGIN
EXECUTE 'SELECT userid FROM users WHERE username=$1' INTO userid USING current_user;
FOR roleid IN SELECT roleid FROM users_roles
WHERE userid=userid
LOOP
IF roleid = 1 THEN
return TRUE;
END IF;
FOR privilegeid IN SELECT privilegeid FROM privileges WHERE roleid=roleid LOOP
IF privilegeid = asked_privilegeid THEN
return TRUE;
END IF;
END LOOP;
END LOOP;
return FALSE;
END
$BODY$
LANGUAGE 'plpgsql'
我做错了什么?提前谢谢
编辑:缩进没有按预期完成。以下是pastebin链接:
问题出在行上
WHERE userid=userid
表中的列和变量不明确。同样的问题
FROM privileges WHERE roleid=roleid
不要使用同时也是要引用的列名的变量名
您还可以将过程主体重写为直接SQL语句,这可能会更快
CREATE OR REPLACE FUNCTION "public"."has_privilege" (in int4) RETURNS bool AS
$BODY$
DECLARE
asked_privilegeid ALIAS FOR $1;
BEGIN
RETURN EXISTS (
SELECT *
FROM users u
INNER JOIN users_roles r on r.userid=u.userid
LEFT JOIN privileges p on p.roleid=r.roleid
AND p.privilegeid = asked_privilegeid
AND r.roleid <> 1 // don't need to process this join if we already have our answer
WHERE u.username = $1
AND (r.roleid=1 OR p.privilegeid is not null))
END
$BODY$
LANGUAGE 'plpgsql'
问题在于争吵
WHERE userid=userid
表中的列和变量不明确。同样的问题
FROM privileges WHERE roleid=roleid
不要使用同时也是要引用的列名的变量名
您还可以将过程主体重写为直接SQL语句,这可能会更快
CREATE OR REPLACE FUNCTION "public"."has_privilege" (in int4) RETURNS bool AS
$BODY$
DECLARE
asked_privilegeid ALIAS FOR $1;
BEGIN
RETURN EXISTS (
SELECT *
FROM users u
INNER JOIN users_roles r on r.userid=u.userid
LEFT JOIN privileges p on p.roleid=r.roleid
AND p.privilegeid = asked_privilegeid
AND r.roleid <> 1 // don't need to process this join if we already have our answer
WHERE u.username = $1
AND (r.roleid=1 OR p.privilegeid is not null))
END
$BODY$
LANGUAGE 'plpgsql'
在postgre中声明变量时,最好使用下划线b4变量名“\u userid”。使其与列名不同
在postgre中声明变量时,最好使用下划线b4变量名“\u userid”。为了使它与列名不同,我认为只需一条SELECT语句就可以解决这个问题: SELECT count(*) FROM privileges p JOIN roles r ON r.privilegeid = p.privilegeid JOIN user_roles ur ON ur.roleid = r.roleid JOIN users u ON u.userid = ur.userid AND u.username = session_user WHERE p.privilegeid = asked_privilegeid 未经测试
如果计数为零,则不会分配特权,否则会分配。我认为只需一个SELECT语句即可解决此问题: SELECT count(*) FROM privileges p JOIN roles r ON r.privilegeid = p.privilegeid JOIN user_roles ur ON ur.roleid = r.roleid JOIN users u ON u.userid = ur.userid AND u.username = session_user WHERE p.privilegeid = asked_privilegeid 未经测试
如果计数为零,则不分配特权,否则为。还有roleid=1的特例,我猜是admin=all access。过程中也跳过了角色,因为它不是必需的。还有roleid=1的特例,我猜是admin/all access。在这个过程中,角色也被跳过,因为它不是必需的,因为我绝不是一个SQL专家,我仍在试图理解您的代码。我想知道来自u部分的用户。这不应该引起错误吗?@Mzialla-对不起!只是提供一个替代方案,如果不起作用,就坚持原来的固定方案。您可以尝试在过程之外的查询,轻松地将RETURN更改为SELECT。对于找到的任何行,EXISTS返回true。它将用户加入到用户角色中,还可以选择加入正确加入的权限。如果r.role_id为1,它甚至不会尝试加入特权,并且最后的and条件将返回true。如果roleid不是一个,它将继续搜索与所请求的_privilegeid匹配的角色的权限。如果成功,最后的OR将返回true。无需道歉,我非常感谢您的努力!谢谢你的解释!因为我绝不是SQL专家,所以我仍在努力理解您的代码。我想知道来自u部分的用户。这不应该引起错误吗?@Mzialla-对不起!只是提供一个替代方案,如果不起作用,就坚持原来的固定方案。您可以尝试在过程之外的查询,轻松地将RETURN更改为SELECT。对于找到的任何行,EXISTS返回true。它将用户加入到用户角色中,还可以选择加入正确加入的权限。如果r.role_id为1,它甚至不会尝试加入特权,并且最后的and条件将返回true。如果roleid不是一个,它将继续搜索与所请求的_privilegeid匹配的角色的权限。如果成功,最后的OR将返回true。无需道歉,我非常感谢您的努力!谢谢你的解释!感谢您对session_用户的评论!感谢您对session_用户的评论!