--
-- packages/acs-kernel/sql/groups-body-create.sql
--
-- @author rhs@mit.edu
-- @creation-date 2000-08-22
-- @cvs-id $Id: groups-body-create.sql,v 1.38 2024/09/11 06:15:48 gustafn Exp $
--
--------------
-- TRIGGERS --
--------------
-- The insert trigger was dummied up in groups-create.sql, so we just need
-- to replace the trigger function, not create the trigger.
-- However, PG 7.3 introduces a new type "trigger" for the return type
-- needed for functions called by triggers. "create function" transmorgifies
-- the return type "trigger" to "trigger" so PG 7.2 dumps can be restored into
-- PG 7.3. But "create or replace" doesn't do it. We can't use "trigger"
-- because we currently are still supporting PG 7.2. Isn't life a pleasure?
-- I'm leaving the triggers we aren't overriding as "create or replace" because
-- this will be the right thing to do if the PG folks fix this problem or when
-- we drop support of PG 7.2 and no longer need to declare these as type "trigger"
drop trigger membership_rels_in_tr on membership_rels;
drop function membership_rels_in_tr ();
--
-- procedure membership_rels_in_tr/0
--
CREATE OR REPLACE FUNCTION membership_rels_in_tr(
) RETURNS trigger AS $$
DECLARE
v_object_id_one acs_rels.object_id_one%TYPE;
v_object_id_two acs_rels.object_id_two%TYPE;
v_rel_type acs_rels.rel_type%TYPE;
v_composable_p acs_rel_types.composable_p%TYPE;
v_error text;
map record;
BEGIN
-- First check if added this relation violated any relational constraints
v_error := rel_constraint__violation(new.rel_id);
if v_error is not null then
raise EXCEPTION '-20000: %', v_error;
end if;
select object_id_one, object_id_two, r.rel_type, composable_p
into v_object_id_one, v_object_id_two, v_rel_type, v_composable_p
from acs_rels r
join acs_rel_types t on (r.rel_type = t.rel_type)
where rel_id = new.rel_id;
-- Insert a row for me in the group_element_index.
insert into group_element_index
(group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type)
values
(v_object_id_one, v_object_id_two, new.rel_id, v_object_id_one,
v_rel_type, 'membership_rel');
if new.member_state = 'approved' then
perform party_approved_member__add(v_object_id_one, v_object_id_two, new.rel_id, v_rel_type);
end if;
-- If this rel_type composable...
if v_composable_p = 't' then
-- For all groups of which I am a component, insert a
-- row in the group_element_index.
for map in select distinct group_id
from group_component_map
where component_id = v_object_id_one
loop
insert into group_element_index
(group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type)
values
(map.group_id, v_object_id_two, new.rel_id, v_object_id_one,
v_rel_type, 'membership_rel');
if new.member_state = 'approved' then
perform party_approved_member__add(map.group_id, v_object_id_two, new.rel_id, v_rel_type);
end if;
end loop;
end if;
return new;
END;
$$ LANGUAGE plpgsql;
create trigger membership_rels_in_tr after insert on membership_rels
for each row execute procedure membership_rels_in_tr ();
--
-- procedure membership_rels_up_tr/0
--
CREATE OR REPLACE FUNCTION membership_rels_up_tr(
) RETURNS trigger AS $$
DECLARE
map record;
BEGIN
if new.member_state = old.member_state then
return new;
end if;
for map in select group_id, element_id, rel_type
from group_element_index
where rel_id = new.rel_id
loop
if new.member_state = 'approved' then
perform party_approved_member__add(map.group_id, map.element_id, new.rel_id, map.rel_type);
else
perform party_approved_member__remove(map.group_id, map.element_id, new.rel_id, map.rel_type);
end if;
end loop;
return new;
END;
$$ LANGUAGE plpgsql;
create trigger membership_rels_up_tr before update on membership_rels
for each row execute procedure membership_rels_up_tr ();
--
-- procedure membership_rels_del_tr/0
--
CREATE OR REPLACE FUNCTION membership_rels_del_tr(
) RETURNS trigger AS $$
DECLARE
v_error text;
map record;
BEGIN
-- First check if removing this relation would violate any relational constraints
v_error := rel_constraint__violation_if_removed(old.rel_id);
if v_error is not null then
raise EXCEPTION '-20000: %', v_error;
end if;
for map in select group_id, element_id, rel_type
from group_element_index
where rel_id = old.rel_id
loop
perform party_approved_member__remove(map.group_id, map.element_id, old.rel_id, map.rel_type);
end loop;
delete from group_element_index
where rel_id = old.rel_id;
return old;
END;
$$ LANGUAGE plpgsql;
create trigger membership_rels_del_tr before delete on membership_rels
for each row execute procedure membership_rels_del_tr ();
drop trigger composition_rels_in_tr on composition_rels;
drop function composition_rels_in_tr ();
--
-- procedure composition_rels_in_tr/0
--
CREATE OR REPLACE FUNCTION composition_rels_in_tr(
) RETURNS trigger AS $$
DECLARE
v_object_id_one acs_rels.object_id_one%TYPE;
v_object_id_two acs_rels.object_id_two%TYPE;
v_rel_type acs_rels.rel_type%TYPE;
v_error text;
map record;
BEGIN
-- First check if added this relation violated any relational constraints
v_error := rel_constraint__violation(new.rel_id);
if v_error is not null then
raise EXCEPTION '-20000: %', v_error;
end if;
select object_id_one, object_id_two, rel_type
into v_object_id_one, v_object_id_two, v_rel_type
from acs_rels
where rel_id = new.rel_id;
-- Insert a row for me in group_element_index
insert into group_element_index
(group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type)
values
(v_object_id_one, v_object_id_two, new.rel_id, v_object_id_one,
v_rel_type, 'composition_rel');
-- Add to the denormalized party_approved_member_map
perform party_approved_member__add(v_object_id_one, member_id, rel_id, rel_type)
from group_approved_member_map m
where group_id = v_object_id_two
and not exists (select 1
from group_element_map
where group_id = v_object_id_one
and element_id = m.member_id
and rel_id = m.rel_id);
-- Make my composable elements be elements of my new composite group
insert into group_element_index
(group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type)
select distinct
v_object_id_one, element_id, rel_id, container_id,
m.rel_type, ancestor_rel_type
from group_element_map m
join acs_rel_types t on (m.rel_type = t.rel_type)
where group_id = v_object_id_two
and t.composable_p = 't'
and not exists (select 1
from group_element_map
where group_id = v_object_id_one
and element_id = m.element_id
and rel_id = m.rel_id);
-- For all direct or indirect containers of my new composite group,
-- add me and add my elements
for map in select distinct group_id
from group_component_map
where component_id = v_object_id_one
LOOP
-- Add a row for me
insert into group_element_index
(group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type)
values
(map.group_id, v_object_id_two, new.rel_id, v_object_id_one,
v_rel_type, 'composition_rel');
-- Add to party_approved_member_map
perform party_approved_member__add(map.group_id, member_id, rel_id, m.rel_type)
from group_approved_member_map m
join acs_rel_types t on (m.rel_type = t.rel_type)
where group_id = v_object_id_two
and t.composable_p = 't'
and not exists (select 1
from group_element_map
where group_id = map.group_id
and element_id = m.member_id
and rel_id = m.rel_id);
-- Add rows for my composable elements
insert into group_element_index
(group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type)
select distinct
map.group_id, element_id, rel_id, container_id,
m.rel_type, ancestor_rel_type
from group_element_map m
join acs_rel_types t on (m.rel_type = t.rel_type)
where group_id = v_object_id_two
and t.composable_p = 't'
and not exists (select 1
from group_element_map
where group_id = map.group_id
and element_id = m.element_id
and rel_id = m.rel_id);
end loop;
return new;
END;
$$ LANGUAGE plpgsql;
create trigger composition_rels_in_tr after insert on composition_rels
for each row execute procedure composition_rels_in_tr ();
--
-- TO DO: See if this can be optimized now that the member and component
-- mapping tables have been combined
--
--
-- procedure composition_rels_del_tr/0
--
CREATE OR REPLACE FUNCTION composition_rels_del_tr(
) RETURNS trigger AS $$
DECLARE
v_object_id_one acs_rels.object_id_one%TYPE;
v_object_id_two acs_rels.object_id_two%TYPE;
n_rows integer;
v_error text;
map record;
BEGIN
-- First check if removing this relation would violate any relational constraints
v_error := rel_constraint__violation_if_removed(old.rel_id);
if v_error is not null then
raise EXCEPTION '-20000: %', v_error;
end if;
select object_id_one, object_id_two into v_object_id_one, v_object_id_two
from acs_rels
where rel_id = old.rel_id;
for map in select *
from group_component_map
where rel_id = old.rel_id
LOOP
delete from group_element_index
where rel_id = old.rel_id;
select count(*) into n_rows
from group_component_map
where group_id = map.group_id
and component_id = map.component_id;
if n_rows = 0 then
perform party_approved_member__remove(map.group_id, member_id, rel_id, rel_type)
from group_approved_member_map
where group_id = map.group_id
and container_id = map.component_id;
delete from group_element_index
where group_id = map.group_id
and container_id = map.component_id
and ancestor_rel_type = 'membership_rel';
end if;
end loop;
for map in select *
from group_component_map
where group_id in (select group_id
from group_component_map
where component_id = v_object_id_one
union
select v_object_id_one
from dual)
and component_id in (select component_id
from group_component_map
where group_id = v_object_id_two
union
select v_object_id_two
from dual)
and group_contains_p(group_id, component_id, rel_id) = 'f'
LOOP
delete from group_element_index
where group_id = map.group_id
and element_id = map.component_id
and rel_id = map.rel_id;
select count(*) into n_rows
from group_component_map
where group_id = map.group_id
and component_id = map.component_id;
if n_rows = 0 then
end if;
perform party_approved_member__remove(map.group_id, member_id, rel_id, rel_type)
from group_approved_member_map
where group_id = map.group_id
and container_id = map.component_id;
delete from group_element_index
where group_id = map.group_id
and container_id = map.component_id
and ancestor_rel_type = 'membership_rel';
end loop;
return old;
END;
$$ LANGUAGE plpgsql;
create trigger composition_rels_del_tr before delete on composition_rels
for each row execute procedure composition_rels_del_tr ();
--------------------
-- PACKAGE BODIES --
--------------------
-- create or replace package body composition_rel
-- function new
select define_function_args('composition_rel__new','rel_id;null,rel_type;composition_rel,object_id_one,object_id_two,creation_user;null,creation_ip;null');
--
-- procedure composition_rel__new/6
--
CREATE OR REPLACE FUNCTION composition_rel__new(
new__rel_id integer, -- default null
rel_type varchar, -- default 'composition_rel'
object_id_one integer,
object_id_two integer,
creation_user integer, -- default null
creation_ip varchar -- default null
) RETURNS integer AS $$
DECLARE
v_rel_id integer;
BEGIN
-- raise NOTICE 'composition_rel__new one % two %', object_id_one, object_id_two;
v_rel_id := acs_rel__new (
new__rel_id,
rel_type,
object_id_one,
object_id_two,
object_id_one,
creation_user,
creation_ip
);
insert into composition_rels
(rel_id)
values
(v_rel_id);
return v_rel_id;
END;
$$ LANGUAGE plpgsql;
-- function new
--
-- procedure composition_rel__new/2
--
CREATE OR REPLACE FUNCTION composition_rel__new(
object_id_one integer,
object_id_two integer
) RETURNS integer AS $$
--
-- composition_rel__new/2 maybe obsolete, when we define proper defaults for /6
--
DECLARE
BEGIN
return composition_rel__new(null,
'composition_rel',
object_id_one,
object_id_two,
null,
null);
END;
$$ LANGUAGE plpgsql;
-- procedure delete
-- added
select define_function_args('composition_rel__delete','rel_id');
--
-- procedure composition_rel__delete/1
--
CREATE OR REPLACE FUNCTION composition_rel__delete(
rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
PERFORM acs_rel__delete(rel_id);
return 0;
END;
$$ LANGUAGE plpgsql;
-- function check_path_exists_p
-- added
select define_function_args('composition_rel__check_path_exists_p','component_id,container_id');
--
-- procedure composition_rel__check_path_exists_p/2
--
CREATE OR REPLACE FUNCTION composition_rel__check_path_exists_p(
component_id integer,
container_id integer
) RETURNS boolean AS $$
DECLARE
row record;
BEGIN
if component_id = container_id then
return 't';
end if;
for row in select r.object_id_one as parent_id
from acs_rels r, composition_rels c
where r.rel_id = c.rel_id
and r.object_id_two = component_id
LOOP
if composition_rel__check_path_exists_p(row.parent_id, container_id) = 't' then
return 't';
end if;
end loop;
return 'f';
END;
$$ LANGUAGE plpgsql;
-- function check_index
-- added
select define_function_args('composition_rel__check_index','component_id,container_id');
--
-- procedure composition_rel__check_index/2
--
CREATE OR REPLACE FUNCTION composition_rel__check_index(
check_index__component_id integer,
check_index__container_id integer
) RETURNS boolean AS $$
DECLARE
result boolean;
n_rows integer;
dc record;
r1 record;
r2 record;
BEGIN
result := 't';
-- Loop through all the direct containers (DC) of COMPONENT_ID
-- that are also contained by CONTAINER_ID and verify that the
-- GROUP_COMPONENT_INDEX contains the (GROUP_ID, DC.REL_ID,
-- CONTAINER_ID) triple.
for dc in select r.rel_id, r.object_id_one as container_id
from acs_rels r, composition_rels c
where r.rel_id = c.rel_id
and r.object_id_two = check_index__component_id
LOOP
if composition_rel__check_path_exists_p(dc.container_id,
check_index__container_id) = 't' then
select case when count(*) = 0 then 0 else 1 end into n_rows
from group_component_index
where group_id = check_index__container_id
and component_id = check_index__component_id
and rel_id = dc.rel_id;
if n_rows = 0 then
result := 'f';
PERFORM acs_log__error('composition_rel.check_representation',
'Row missing from group_component_index for (' ||
'group_id = ' || check_index__container_id || ', ' ||
'component_id = ' || check_index__component_id || ', ' ||
'rel_id = ' || dc.rel_id || ')');
end if;
end if;
end loop;
-- Loop through all the containers of CONTAINER_ID.
for r1 in select r.object_id_one as container_id
from acs_rels r, composition_rels c
where r.rel_id = c.rel_id
and r.object_id_two = check_index__container_id
union
select check_index__container_id as container_id
from dual
LOOP
-- Loop through all the components of COMPONENT_ID and make a
-- recursive call.
for r2 in select r.object_id_two as component_id
from acs_rels r, composition_rels c
where r.rel_id = c.rel_id
and r.object_id_one = check_index__component_id
union
select check_index__component_id as component_id
from dual
LOOP
if (r1.container_id != check_index__container_id or
r2.component_id != check_index__component_id) and
composition_rel__check_index(r2.component_id, r1.container_id) = 'f' then
result := 'f';
end if;
end loop;
end loop;
return result;
END;
$$ LANGUAGE plpgsql;
-- function check_representation
-- added
select define_function_args('composition_rel__check_representation','rel_id');
--
-- procedure composition_rel__check_representation/1
--
CREATE OR REPLACE FUNCTION composition_rel__check_representation(
check_representation__rel_id integer
) RETURNS boolean AS $$
DECLARE
container_id groups.group_id%TYPE;
component_id groups.group_id%TYPE;
result boolean;
row record;
BEGIN
result := 't';
if acs_object__check_representation(check_representation__rel_id) = 'f' then
result := 'f';
end if;
select object_id_one, object_id_two
into container_id, component_id
from acs_rels
where rel_id = check_representation__rel_id;
-- First let us check that the index has all the rows it should.
if composition_rel__check_index(component_id, container_id) = 'f' then
result := 'f';
end if;
-- Now let us check that the index doesn't have any extraneous rows
-- relating to this relation.
for row in select *
from group_component_index
where rel_id = check_representation__rel_id
LOOP
if composition_rel__check_path_exists_p(row.component_id, row.group_id) = 'f' then
result := 'f';
PERFORM acs_log__error('composition_rel.check_representation',
'Extraneous row in group_component_index: ' ||
'group_id = ' || row.group_id || ', ' ||
'component_id = ' || row.component_id || ', ' ||
'rel_id = ' || row.rel_id || ', ' ||
'container_id = ' || row.container_id || '.');
end if;
end loop;
return result;
END;
$$ LANGUAGE plpgsql;
-- show errors
-- create or replace package body membership_rel
-- function new
-- old define_function_args('membership_rel__new','rel_id,rel_type;membership_rel,object_id_one,object_id_two,member_state;approved,creation_user,creation_ip')
-- new
select define_function_args('membership_rel__new','rel_id;null,rel_type;membership_rel,object_id_one,object_id_two,member_state;approved,creation_user;null,creation_ip;null');
--
-- procedure membership_rel__new/7
--
CREATE OR REPLACE FUNCTION membership_rel__new(
new__rel_id integer, -- default null
rel_type varchar, -- default 'membership_rel'
object_id_one integer,
object_id_two integer,
new__member_state varchar, -- default 'approved'
creation_user integer, -- default null
creation_ip varchar -- default null
) RETURNS integer AS $$
DECLARE
v_rel_id integer;
BEGIN
v_rel_id := acs_rel__new (
new__rel_id,
rel_type,
object_id_one,
object_id_two,
object_id_one,
creation_user,
creation_ip
);
insert into membership_rels
(rel_id, member_state)
values
(v_rel_id, new__member_state);
return v_rel_id;
END;
$$ LANGUAGE plpgsql;
-- function new
--
-- procedure membership_rel__new/2
--
CREATE OR REPLACE FUNCTION membership_rel__new(
object_id_one integer,
object_id_two integer
) RETURNS integer AS $$
--
-- membership_rel__new/2 maybe obsolete, when we define proper defaults for /7
--
DECLARE
BEGIN
return membership_rel__new(null,
'membership_rel',
object_id_one,
object_id_two,
'approved',
null,
null);
END;
$$ LANGUAGE plpgsql;
-- procedure ban
-- added
select define_function_args('membership_rel__ban','rel_id');
--
-- procedure membership_rel__ban/1
--
CREATE OR REPLACE FUNCTION membership_rel__ban(
ban__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'banned'
where rel_id = ban__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure approve
-- added
select define_function_args('membership_rel__approve','rel_id');
--
-- procedure membership_rel__approve/1
--
CREATE OR REPLACE FUNCTION membership_rel__approve(
approve__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'approved'
where rel_id = approve__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure reject
-- added
select define_function_args('membership_rel__reject','rel_id');
--
-- procedure membership_rel__reject/1
--
CREATE OR REPLACE FUNCTION membership_rel__reject(
reject__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'rejected'
where rel_id = reject__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure unapprove
-- added
select define_function_args('membership_rel__unapprove','rel_id');
--
-- procedure membership_rel__unapprove/1
--
CREATE OR REPLACE FUNCTION membership_rel__unapprove(
unapprove__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'needs approval'
where rel_id = unapprove__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure expire
-- added
select define_function_args('membership_rel__expire','rel_id');
--
-- procedure membership_rel__expire/1
--
CREATE OR REPLACE FUNCTION membership_rel__expire(
expire__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'expired'
where rel_id = expire__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure deleted
-- added
select define_function_args('membership_rel__deleted','rel_id');
--
-- procedure membership_rel__deleted/1
--
CREATE OR REPLACE FUNCTION membership_rel__deleted(
deleted__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'deleted'
where rel_id = deleted__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure delete
-- added
select define_function_args('membership_rel__delete','rel_id');
--
-- procedure membership_rel__delete/1
--
CREATE OR REPLACE FUNCTION membership_rel__delete(
rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
PERFORM acs_rel__delete(rel_id);
return 0;
END;
$$ LANGUAGE plpgsql;
-- procedure merge
-- added
select define_function_args('membership_rel__merge','rel_id');
--
-- procedure membership_rel__merge/1
--
CREATE OR REPLACE FUNCTION membership_rel__merge(
merge__rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
update membership_rels
set member_state = 'merged'
where rel_id = merge__rel_id;
return 0;
END;
$$ LANGUAGE plpgsql;
-- function check_index
-- added
select define_function_args('membership_rel__check_index','group_id,member_id,container_id');
--
-- procedure membership_rel__check_index/3
--
CREATE OR REPLACE FUNCTION membership_rel__check_index(
check_index__group_id integer,
check_index__member_id integer,
check_index__container_id integer
) RETURNS boolean AS $$
DECLARE
result boolean;
n_rows integer;
row record;
BEGIN
select count(*) into n_rows
from group_element_index
where group_id = check_index__group_id
and member_id = check_index__member_id
and container_id = check_index__container_id;
if n_rows = 0 then
result := 'f';
PERFORM acs_log__error('membership_rel.check_representation',
'Row missing from group_element_index: ' ||
'group_id = ' || check_index__group_id || ', ' ||
'member_id = ' || check_index__member_id || ', ' ||
'container_id = ' || check_index__container_id || '.');
end if;
for row in select r.object_id_one as container_id
from acs_rels r, composition_rels c
where r.rel_id = c.rel_id
and r.object_id_two = check_index__group_id
LOOP
if membership_rel__check_index(row.container_id, check_index__member_id, check_index__container_id) = 'f' then
result := 'f';
end if;
end loop;
return result;
END;
$$ LANGUAGE plpgsql;
-- function check_representation
-- added
select define_function_args('membership_rel__check_representation','rel_id');
--
-- procedure membership_rel__check_representation/1
--
CREATE OR REPLACE FUNCTION membership_rel__check_representation(
check_representation__rel_id integer
) RETURNS boolean AS $$
DECLARE
group_id groups.group_id%TYPE;
member_id parties.party_id%TYPE;
result boolean;
row record;
BEGIN
result := 't';
if acs_object__check_representation(check_representation__rel_id) = 'f' then
result := 'f';
end if;
select r.object_id_one, r.object_id_two
into group_id, member_id
from acs_rels r, membership_rels m
where r.rel_id = m.rel_id
and m.rel_id = check_representation__rel_id;
if membership_rel__check_index(group_id, member_id, group_id) = 'f' then
result := 'f';
end if;
for row in select *
from group_member_index
where rel_id = check_representation__rel_id
LOOP
if composition_rel__check_path_exists_p(row.container_id,
row.group_id) = 'f' then
result := 'f';
PERFORM acs_log__error('membership_rel.check_representation',
'Extra row in group_member_index: ' ||
'group_id = ' || row.group_id || ', ' ||
'member_id = ' || row.member_id || ', ' ||
'container_id = ' || row.container_id || '.');
end if;
end loop;
return result;
END;
$$ LANGUAGE plpgsql;
-- create or replace package body acs_group
-- function new
-- old define_function_args('acs_group__new','group_id,object_type;group,creation_date;now(),creation_user,creation_ip,email,url,group_name,join_policy,context_id')
-- new
select define_function_args('acs_group__new','group_id;null,object_type;group,creation_date;now(),creation_user;null,creation_ip;null,email;null,url;null,group_name,join_policy;null,context_id;null');
--
-- procedure acs_group__new/10
--
CREATE OR REPLACE FUNCTION acs_group__new(
new__group_id integer, -- default null
new__object_type varchar, -- default 'group'
new__creation_date timestamptz, -- default now() -- default 'now()'
new__creation_user integer, -- default null
new__creation_ip varchar, -- default null
new__email varchar, -- default null
new__url varchar, -- default null
new__group_name varchar,
new__join_policy varchar, -- default null
new__context_id integer -- default null
) RETURNS integer AS $$
DECLARE
v_group_id groups.group_id%TYPE;
v_group_type_exists_p integer;
v_join_policy groups.join_policy%TYPE;
BEGIN
v_group_id :=
party__new(new__group_id, new__object_type, new__creation_date,
new__creation_user, new__creation_ip, new__email,
new__url, new__context_id);
v_join_policy := new__join_policy;
-- if join policy was not specified, select the default based on group type
if v_join_policy is null or v_join_policy = '' then
select count(*) into v_group_type_exists_p
from group_types
where group_type = new__object_type;
if v_group_type_exists_p = 1 then
select default_join_policy into v_join_policy
from group_types
where group_type = new__object_type;
else
v_join_policy := 'open';
end if;
end if;
update acs_objects
set title = new__group_name
where object_id = v_group_id;
insert into groups
(group_id, group_name, join_policy)
values
(v_group_id, new__group_name, v_join_policy);
-- setup the permissible relationship types for this group
-- DRB: we have to call nextval() directly because the select may
-- return more than one row. The sequence hack will only compute
-- one nextval value causing the insert to fail ("may" in PG, which
-- is actually broken. It should ALWAYS return exactly one value for
-- the view. In PG it may or may not depending on the optimizer's
-- mood. PG group seems uninterested in acknowledging the fact that
-- this is a bug)
insert into group_rels
(group_rel_id, group_id, rel_type)
select nextval('t_acs_object_id_seq'), v_group_id, rels.rel_type
from
( select distinct g.rel_type
from group_type_rels g,
( select parent.object_type as parent_type
from acs_object_types child, acs_object_types parent
where child.object_type <> parent.object_type
and child.tree_sortkey between parent.tree_sortkey
and tree_right(parent.tree_sortkey)
and child.object_type = new__object_type
order by parent.tree_sortkey desc) types
where g.group_type = types.parent_type
and not exists
( select 1 from group_rels
where group_rels.group_id = v_group_id
and group_rels.rel_type = g.rel_type)
) rels;
return v_group_id;
END;
$$ LANGUAGE plpgsql;
-- function new
--
-- procedure acs_group__new/1
--
CREATE OR REPLACE FUNCTION acs_group__new(
gname varchar
) RETURNS integer AS $$
--
-- acs_group__new/1 maybe obsolete, when we define proper defaults for /10
--
DECLARE
BEGIN
return acs_group__new(null,
'group',
now(),
null,
null,
null,
null,
gname,
null,
null);
END;
$$ LANGUAGE plpgsql;
-- procedure delete
-- added
select define_function_args('acs_group__delete','group_id');
--
-- procedure acs_group__delete/1
--
CREATE OR REPLACE FUNCTION acs_group__delete(
delete__group_id integer
) RETURNS integer AS $$
DECLARE
row record;
BEGIN
-- Delete all the relations of any type to this group
for row in select r.rel_id, t.package_name
from acs_rels r, acs_object_types t
where r.rel_type = t.object_type
and (r.object_id_one = delete__group_id
or r.object_id_two = delete__group_id)
LOOP
execute 'select ' || row.package_name || '__delete(' || row.rel_id || ')';
end loop;
-- Delete all segments defined for this group
for row in select segment_id
from rel_segments
where group_id = delete__group_id
LOOP
PERFORM rel_segment__delete(row.segment_id);
end loop;
PERFORM party__delete(delete__group_id);
return 0;
END;
$$ LANGUAGE plpgsql;
-- function name
-- added
select define_function_args('acs_group__name','group_id');
--
-- procedure acs_group__name/1
--
CREATE OR REPLACE FUNCTION acs_group__name(
name__group_id integer
) RETURNS varchar AS $$
DECLARE
name__group_name varchar(200);
BEGIN
select group_name
into name__group_name
from groups
where group_id = name__group_id;
return name__group_name;
END;
$$ LANGUAGE plpgsql stable strict;
select define_function_args('acs_group__member_p','party_id,group_id,cascade_membership');
--
-- function acs_group__member_p/3
--
CREATE OR REPLACE FUNCTION acs_group__member_p(
p_party_id integer,
p_group_id integer,
p_cascade_membership boolean
) RETURNS boolean AS $$
SELECT CASE
WHEN p_cascade_membership = true then
--
-- Direct and indirect memberships
--
EXISTS (
select 1 from group_member_map
where group_id = p_group_id
and member_id = p_party_id
)
ELSE
--
-- Only direct memberships
--
EXISTS (
select 1 from acs_rels rels
where rels.rel_type = 'membership_rel'
and rels.object_id_one = p_group_id
and rels.object_id_two = p_party_id
)
END;
$$ LANGUAGE sql strict stable;
-- function check_representation
-- added
select define_function_args('acs_group__check_representation','group_id');
--
-- procedure acs_group__check_representation/1
--
CREATE OR REPLACE FUNCTION acs_group__check_representation(
group_id integer
) RETURNS boolean AS $$
DECLARE
res boolean;
comp record;
memb record;
BEGIN
if group_id is null then
--maybe we should just return 'f' instead?
raise exception 'acs_group__check_representation called with null group_id';
end if;
res := 't';
PERFORM acs_log__notice('acs_group.check_representation',
'Running check_representation on group ' || group_id);
if acs_object__check_representation(group_id) = 'f' then
res := 'f';
end if;
for comp in select c.rel_id
from acs_rels r, composition_rels c
where r.rel_id = c.rel_id
and r.object_id_one = group_id
LOOP
if composition_rel__check_representation(comp.rel_id) = 'f' then
res := 'f';
end if;
end loop;
for memb in select m.rel_id
from acs_rels r, membership_rels m
where r.rel_id = m.rel_id
and r.object_id_one = group_id
LOOP
if membership_rel__check_representation(memb.rel_id) = 'f' then
res := 'f';
end if;
end loop;
PERFORM acs_log__notice('acs_group.check_representation',
'Done running check_representation on group ' || group_id);
return res;
END;
$$ LANGUAGE plpgsql;
-- create or replace package body admin_rel
select define_function_args('admin_rel__new','rel_id;null,rel_type;admin_rel,object_id_one,object_id_two,member_state;approved,creation_user;null,creation_ip;null');
--
-- procedure admin_rel__new/7
--
CREATE OR REPLACE FUNCTION admin_rel__new(
p_rel_id integer, -- default null
p_rel_type varchar, -- default 'admin_rel'
p_object_id_one integer,
p_object_id_two integer,
p_member_state varchar, -- default 'approved'
p_creation_user integer, -- default null
p_creation_ip varchar -- default null
) RETURNS integer AS $$
DECLARE
v_rel_id integer;
BEGIN
v_rel_id := membership_rel__new (
p_rel_id, -- rel_id
p_rel_type, -- rel_type
p_object_id_one, -- object_id_one
p_object_id_two, -- object_id_two
p_member_state, -- member_state
p_creation_user, -- creation_usre
p_creation_ip -- creation_ip
);
insert into admin_rels
(rel_id)
values
(v_rel_id);
return v_rel_id;
END;
$$ LANGUAGE plpgsql;
--
-- procedure admin_rel__new/2
--
CREATE OR REPLACE FUNCTION admin_rel__new(
object_id_one integer,
object_id_two integer
) RETURNS integer AS $$
--
-- admin_rel__new/2 maybe obsolete, when we define proper defaults for /7
--
DECLARE
BEGIN
return membership_rel__new(
null, -- rel_id
'admin_rel', -- rel_type
object_id_one, -- object_id_one
object_id_two, -- object_id_two
'approved', -- member_state
null, -- creation_user
null -- creation_ip
);
END;
$$ LANGUAGE plpgsql;
select define_function_args('admin_rel__delete','rel_id');
--
-- procedure admin_rel__delete/1
--
CREATE OR REPLACE FUNCTION admin_rel__delete(
rel_id integer
) RETURNS integer AS $$
DECLARE
BEGIN
PERFORM membership_rel__delete(rel_id);
return 0;
END;
$$ LANGUAGE plpgsql;
--
-- Local variables:
-- mode: sql
-- indent-tabs-mode: nil
-- End: