Thread: How to cascade information like the user roles ?
Hi, I need something like the user-roles of PG to store options of my users. I guess i need a table with roles, options and one that stores the refernces from roles to options. roles (role_id, role_name) option (option_id, option_name) role_has_option (role_fk, option_fk) so far is easy. Now I can let role1 have option1 and option2 ... But I'd further like to let role2 inherit role1's options and also have option3. role_inherits_role (parent_role_fk, child_role_fk) 1, 2 What SELECT would deliver all options for role2 inkluding the inherited ones? like role_id, option_id 2, 1 2, 2 2, 3
Hi,
I need something like the user-roles of PG to store options of my users.
I guess i need a table with roles, options and one that stores the refernces from roles to options.
roles (role_id, role_name)
option (option_id, option_name)
role_has_option (role_fk, option_fk)
so far is easy. Now I can let role1 have option1 and option2 ...
But I'd further like to let role2 inherit role1's options and also have option3.
role_inherits_role (parent_role_fk, child_role_fk)
1, 2
What SELECT would deliver all options for role2 inkluding the inherited ones?
like
role_id, option_id
2, 1
2, 2
2, 3
select role_fk as role_id, option_fk as option_id from role_has_option where role_fk = 2
union
select inh.child_role_fk, opt.option_fk from role_has_option opt join role_inherits_role inh on inh.parent_role_fk = opt.role_fk where inh.child_role_fk = 2
?
--
Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql
--
Filip Rembiałkowski
JID,mailto:filip.rembialkowski@gmail.com
http://filip.rembialkowski.net/
Filip Rembiałkowski schrieb: > > > 2010/1/19 Andreas <maps.on@gmx.net <mailto:maps.on@gmx.net>> > > Hi, > > I need something like the user-roles of PG to store options of my > users. > I guess i need a table with roles, options and one that stores the > refernces from roles to options. > > roles (role_id, role_name) > option (option_id, option_name) > role_has_option (role_fk, option_fk) > > so far is easy. Now I can let role1 have option1 and option2 ... > > But I'd further like to let role2 inherit role1's options and also > have option3. > role_inherits_role (parent_role_fk, child_role_fk) > 1, 2 > > What SELECT would deliver all options for role2 inkluding the > inherited ones? > like > role_id, option_id > 2, 1 > 2, 2 > 2, 3 > > > > select role_fk as role_id, option_fk as option_id from role_has_option > where role_fk = 2 > union > select inh.child_role_fk, opt.option_fk from role_has_option opt join > role_inherits_role inh on inh.parent_role_fk = opt.role_fk where > inh.child_role_fk = 2 Thanks. I am looking for a more general solution that expands even multiple steps of inheritance like a more complex example: role_1 --> option_1 + option_2 role_2 --> option_3 and inherits role_1 role_3 --> option_2 + option_4 role_4 --> option_5 and inherits role_2 and role_3 I need a general solution that gives all options for any given role including every inherited options over a unlimited hierarchy of parents. Sounds complex, I know, but this is what PG does with its user-roles. So I'd do in this example a SELECT ... WHERE role_id = 4 and get 4, 5 directly 4, 3 from role_2 4, 1 from role_1 over role_2 4, 2 from role_1 over role_2 4, 2 from role_3 (inherited double occurance) 4, 4 from role_4
I tried my hands on it, and attached is an implementation of such a recursive function. It returns the expected results.
Hope it helps.
Best regards,
Filip Rembiałkowski schrieb:Thanks.
2010/1/19 Andreas <maps.on@gmx.net <mailto:maps.on@gmx.net>>
Hi,
I need something like the user-roles of PG to store options of my
users.
I guess i need a table with roles, options and one that stores the
refernces from roles to options.
roles (role_id, role_name)
option (option_id, option_name)
role_has_option (role_fk, option_fk)
so far is easy. Now I can let role1 have option1 and option2 ...
But I'd further like to let role2 inherit role1's options and also
have option3.
role_inherits_role (parent_role_fk, child_role_fk)
1, 2
What SELECT would deliver all options for role2 inkluding the
inherited ones?
like
role_id, option_id
2, 1
2, 2
2, 3
select role_fk as role_id, option_fk as option_id from role_has_option where role_fk = 2
union
select inh.child_role_fk, opt.option_fk from role_has_option opt join role_inherits_role inh on inh.parent_role_fk = opt.role_fk where inh.child_role_fk = 2
I am looking for a more general solution that expands even multiple steps of inheritance like a more complex example:
role_1 --> option_1 + option_2
role_2 --> option_3 and inherits role_1
role_3 --> option_2 + option_4
role_4 --> option_5 and inherits role_2 and role_3
I need a general solution that gives all options for any given role including every inherited options over a unlimited hierarchy of parents.
Sounds complex, I know, but this is what PG does with its user-roles.
So I'd do in this example a SELECT ... WHERE role_id = 4
and get
4, 5 directly
4, 3 from role_2
4, 1 from role_1 over role_2
4, 2 from role_1 over role_2
4, 2 from role_3 (inherited double occurance)
4, 4 from role_4
--
Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql
--
gurjeet.singh
@ EnterpriseDB - The Enterprise Postgres Company
http://www.enterprisedb.com
singh.gurjeet@{ gmail | yahoo }.com
Twitter/Skype: singh_gurjeet
Mail sent from my BlackLaptop device
Attachment
postgres=# with recursive roles(role_id) as
(select 4
union all
select parent_role_id
from app_role_inherits as i,
roles as r
where i.role_id = r.role_id)
select /* r.role_id, */ m.option_id
from roles as r,
app_role_option_map m
where m.role_id = r.role_id;
option_id
-----------
1
2
3
2
4
5
(6 rows)
Best regards,
You need a recursive lookup, and I guess 8.4's WITH RECURSIVE construct can help here. But if you are on an older version of Postgres, you will have to write recursive functions to do it.
I tried my hands on it, and attached is an implementation of such a recursive function. It returns the expected results.
Hope it helps.
Best regards,--2010/1/19 Andreas <maps.on@gmx.net>Filip Rembiałkowski schrieb:Thanks.
2010/1/19 Andreas <maps.on@gmx.net <mailto:maps.on@gmx.net>>
Hi,
I need something like the user-roles of PG to store options of my
users.
I guess i need a table with roles, options and one that stores the
refernces from roles to options.
roles (role_id, role_name)
option (option_id, option_name)
role_has_option (role_fk, option_fk)
so far is easy. Now I can let role1 have option1 and option2 ...
But I'd further like to let role2 inherit role1's options and also
have option3.
role_inherits_role (parent_role_fk, child_role_fk)
1, 2
What SELECT would deliver all options for role2 inkluding the
inherited ones?
like
role_id, option_id
2, 1
2, 2
2, 3
select role_fk as role_id, option_fk as option_id from role_has_option where role_fk = 2
union
select inh.child_role_fk, opt.option_fk from role_has_option opt join role_inherits_role inh on inh.parent_role_fk = opt.role_fk where inh.child_role_fk = 2
I am looking for a more general solution that expands even multiple steps of inheritance like a more complex example:
role_1 --> option_1 + option_2
role_2 --> option_3 and inherits role_1
role_3 --> option_2 + option_4
role_4 --> option_5 and inherits role_2 and role_3
I need a general solution that gives all options for any given role including every inherited options over a unlimited hierarchy of parents.
Sounds complex, I know, but this is what PG does with its user-roles.
So I'd do in this example a SELECT ... WHERE role_id = 4
and get
4, 5 directly
4, 3 from role_2
4, 1 from role_1 over role_2
4, 2 from role_1 over role_2
4, 2 from role_3 (inherited double occurance)
4, 4 from role_4
--
Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql
gurjeet.singh
@ EnterpriseDB - The Enterprise Postgres Company
http://www.enterprisedb.com
singh.gurjeet@{ gmail | yahoo }.com
Twitter/Skype: singh_gurjeet
Mail sent from my BlackLaptop device
--
gurjeet.singh
@ EnterpriseDB - The Enterprise Postgres Company
http://www.enterprisedb.com
singh.gurjeet@{ gmail | yahoo }.com
Twitter/Skype: singh_gurjeet
Mail sent from my BlackLaptop device
Thanks a whole lot and some :) It's great that you actually did a working script. I find it tremendosly easier to learn with a working example than with some links to other documentation which makes or does not make sense. I've got a 8.4 server so both ways work nicely. Is there a way to prevent inheritance loops instead of denying parent_id > child_id ? Parallel inheritance has to work, though. 1 <-- 2 and 3 <-- 4 I found the function running into a stack overflow when I intetionally created a loop to check what'll happen. At least this is a predefined limit in max_stack_depth. The with recursive thingy just kept going which generally tends to be worse, I guess. Regards :)
Thanks a whole lot and some :)
It's great that you actually did a working script.
I find it tremendosly easier to learn with a working example than with some links to other documentation which makes or does not make sense.
I've got a 8.4 server so both ways work nicely.
Is there a way to prevent inheritance loops instead of denying parent_id > child_id ?
I'd suggest creating an ON INSERT+UPDATE trigger on app_role_inherits and checking and disallowing loops there. If possible use a non-recursive method to detect loop.
Parallel inheritance has to work, though. 1 <-- 2 and 3 <-- 4
I didn't get this sentence!
I found the function running into a stack overflow when I intetionally created a loop to check what'll happen. At least this is a predefined limit in max_stack_depth.
The with recursive thingy just kept going which generally tends to be worse, I guess.
The WITH RECURSIVE is actually implemented non-recursively internally; see: http://www.postgresql.org/docs/current/static/queries-with.html . So if you have loops in there, there's nothing stopping the query from running forever, except probably running out of disk for the intermediate table.
So either prevent loops in the data being queried, or put a WHERE clause there that would prevent the query running forever.
Best regards,
gurjeet.singh
@ EnterpriseDB - The Enterprise Postgres Company
http://www.enterprisedb.com
singh.gurjeet@{ gmail | yahoo }.com
Twitter/Skype: singh_gurjeet
Mail sent from my BlackLaptop device
I am trying to create a update trigger on a table that basically will only fire when a specific column is updated. I am using version 8.4.3.
My plan of attack was to always fire on any row update, and pass in the OLD and NEW column that I want to check.
CREATE TRIGGER check_lockout
AFTER UPDATE ON acct_table
FOR EACH ROW
EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
This fails with :
[postgres@linux1505 ~]$ cat check_lockout_trig.sql | psql testdb
ERROR: syntax error at or near "OLD"
LINE 4: EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
What am I doing wrong? Or is there a better way to go about this?
Nevermind all, I figured it out ….
Thanks Dmitriy …
From: Dmitriy Igrishin [mailto:dmitigr@gmail.com]
Sent: Thursday, May 06, 2010 3:25 PM
To: Plugge, Joe R.
Subject: Re: [SQL] Column Specific Update Trigger Routine
Hey Plugge,
You dont need to pass OLD.* or NEW.* to the trigger function.
These structures available from within trigger function.
Note, that in PostgreSQL 9 you will able to create trigger
which call function only when some column of the table
affected.
Regards,
Dmitriy
2010/5/7 Plugge, Joe R. <JRPlugge@west.com>
I am trying to create a update trigger on a table that basically will only fire when a specific column is updated. I am using version 8.4.3.
My plan of attack was to always fire on any row update, and pass in the OLD and NEW column that I want to check.
CREATE TRIGGER check_lockout
AFTER UPDATE ON acct_table
FOR EACH ROW
EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
This fails with :
[postgres@linux1505 ~]$ cat check_lockout_trig.sql | psql testdb
ERROR: syntax error at or near "OLD"
LINE 4: EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
What am I doing wrong? Or is there a better way to go about this?
You don't call the trigger procedure with the old and new as parametersI am trying to create a update trigger on a table that basically will only fire when a specific column is updated. I am using version 8.4.3.
My plan of attack was to always fire on any row update, and pass in the OLD and NEW column that I want to check.
CREATE TRIGGER check_lockout
AFTER UPDATE ON acct_table
FOR EACH ROW
EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
This fails with :
[postgres@linux1505 ~]$ cat check_lockout_trig.sql | psql testdb
ERROR: syntax error at or near "OLD"
LINE 4: EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
What am I doing wrong? Or is there a better way to go about this?
new and old are automatically created for the function acct_unlock()
CREATE TRIGGER check_lockout
AFTER UPDATE ON acct_table
FOR EACH ROW EXECUTE PROCEDURE acct_unlock();
Next the trigger function would look something like this
create or replace function acct_unlock()
returns trigger as
$$
if (OLD.userid <> NEW.password)
do something
end if;
$$
keep in mind the acct_unlock must be returns trigger
Then return either NEW or the OLD record
OLD if not changing the record or NEW if the updated values are to be stored in the table.
All legitimate Magwerks Corporation quotations are sent in a .PDF file attachment with a unique ID number generated by our proprietary quotation system. Quotations received via any other form of communication will not be honored.
CONFIDENTIALITY NOTICE: This e-mail, including attachments, may contain legally privileged, confidential or other information proprietary to Magwerks Corporation and is intended solely for the use of the individual to whom it addresses. If the reader of this e-mail is not the intended recipient or authorized agent, the reader is hereby notified that any unauthorized viewing, dissemination, distribution or copying of this e-mail is strictly prohibited. If you have received this e-mail in error, please notify the sender by replying to this message and destroy all occurrences of this e-mail immediately.
Thank you.
This is what I have and it seems to work:
CREATE OR REPLACE FUNCTION holly_unlock() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF OLD.password != NEW.password
THEN
UPDATE hms_mtusers_rw set loginfailedcount = 0 WHERE userid = OLD.userid and ownerid = OLD.ownerid;
RETURN NEW;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$$;
Thanks !!
From: Justin Graf [mailto:justin@magwerks.com]
Sent: Thursday, May 06, 2010 3:59 PM
To: Plugge, Joe R.; pgsql-sql@postgresql.org
Subject: Re: [SQL] Column Specific Update Trigger Routine
On 5/6/2010 4:12 PM, Plugge, Joe R. wrote:
I am trying to create a update trigger on a table that basically will only fire when a specific column is updated. I am using version 8.4.3.
My plan of attack was to always fire on any row update, and pass in the OLD and NEW column that I want to check.
CREATE TRIGGER check_lockout
AFTER UPDATE ON acct_table
FOR EACH ROW
EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
This fails with :
[postgres@linux1505 ~]$ cat check_lockout_trig.sql | psql testdb
ERROR: syntax error at or near "OLD"
LINE 4: EXECUTE PROCEDURE acct_unlock(OLD.userid,OLD.ownerid,OLD.password,NEW.password);
What am I doing wrong? Or is there a better way to go about this?
You don't call the trigger procedure with the old and new as parameters
new and old are automatically created for the function acct_unlock()
CREATE TRIGGER check_lockout
AFTER UPDATE ON acct_table
FOR EACH ROW
EXECUTE PROCEDURE acct_unlock();
Next the trigger function would look something like this
create or replace function acct_unlock()
returns trigger as
$$
if (OLD.userid <> NEW.password)
do something
end if;
$$
keep in mind the acct_unlock must be returns trigger
Then return either NEW or the OLD record
OLD if not changing the record or NEW if the updated values are to be stored in the table.
All legitimate Magwerks Corporation quotations are sent in a .PDF file attachment with a unique ID number generated by our proprietary quotation system. Quotations received via any other form of communication will not be honored.
CONFIDENTIALITY NOTICE: This e-mail, including attachments, may contain legally privileged, confidential or other information proprietary to Magwerks Corporation and is intended solely for the use of the individual to whom it addresses. If the reader of this e-mail is not the intended recipient or authorized agent, the reader is hereby notified that any unauthorized viewing, dissemination, distribution or copying of this e-mail is strictly prohibited. If you have received this e-mail in error, please notify the sender by replying to this message and destroy all occurrences of this e-mail immediately.
Thank you.
"Plugge, Joe R." <JRPlugge@west.com> writes: > This is what I have and it seems to work: > IF OLD.password != NEW.password It'd be better to write "IF OLD.password IS DISTINCT FROM NEW.password". The way with != will not do what you want if one value is null and the other isn't. It's possible this doesn't matter in this particular case (if password can't ever be null in this table), but being careful about nulls is a good habit to cultivate. regards, tom lane