--
-- /packages/acs-kernel/sql/upgrade/upgrade-4.0.1-4.0.2.sql
--
-- Upgrades ACS Kernel 4.0.1 to ACS Kernel 4.0.2
--
-- @author Multiple
-- @creation-date Wed Nov 1 10:32:08 2000
-- @cvs-id $Id: upgrade-4.0.1-4.1b.sql,v 1.5 2024/09/11 06:15:47 gustafn Exp $
-- security upgrade (richardl@arsdigita.com)
alter table sec_sessions drop primary key cascade;
alter table sec_session_properties add (last_hit integer);
drop table sec_sessions;
drop package sec;
alter sequence sec_id_seq increment by 100;
-- fixing two bugs in the package body.
-- version.new now uses the v_version_id it constructs.
-- The sortable_version_name procedure now fails gracefully.
create or replace package body apm_package_version
as
function new (
version_id in apm_package_versions.version_id%TYPE
default null,
package_key in apm_package_versions.package_key%TYPE,
version_name in apm_package_versions.version_name%TYPE
default null,
version_uri in apm_package_versions.version_uri%TYPE,
summary in apm_package_versions.summary%TYPE,
description_format in apm_package_versions.description_format%TYPE,
description in apm_package_versions.description%TYPE,
release_date in apm_package_versions.release_date%TYPE,
vendor in apm_package_versions.vendor%TYPE,
vendor_uri in apm_package_versions.vendor_uri%TYPE,
installed_p in apm_package_versions.installed_p%TYPE
default 'f',
data_model_loaded_p in apm_package_versions.data_model_loaded_p%TYPE
default 'f'
) return apm_package_versions.version_id%TYPE
is
v_version_id apm_package_versions.version_id%TYPE;
begin
if version_id is null then
select acs_object_id_seq.nextval
into v_version_id
from dual;
else
v_version_id := version_id;
end if;
v_version_id := acs_object.new(
object_id => v_version_id,
object_type => 'apm_package_version'
);
insert into apm_package_versions
(version_id, package_key, version_name, version_uri, summary, description_format, description,
release_date, vendor, vendor_uri, installed_p, data_model_loaded_p)
values
(v_version_id, package_key, version_name, version_uri,
summary, description_format, description,
release_date, vendor, vendor_uri,
installed_p, data_model_loaded_p);
return v_version_id;
end new;
procedure delete (
version_id in apm_packages.package_id%TYPE
)
is
begin
delete from apm_package_owners
where version_id = apm_package_version.delete.version_id;
delete from apm_package_files
where version_id = apm_package_version.delete.version_id;
delete from apm_package_dependencies
where version_id = apm_package_version.delete.version_id;
delete from apm_package_versions
where version_id = apm_package_version.delete.version_id;
acs_object.delete(apm_package_version.delete.version_id);
end delete;
procedure enable (
version_id in apm_package_versions.version_id%TYPE
)
is
begin
update apm_package_versions set enabled_p = 't'
where version_id = enable.version_id;
end enable;
procedure disable (
version_id in apm_package_versions.version_id%TYPE
)
is
begin
update apm_package_versions
set enabled_p = 'f'
where version_id = disable.version_id;
end disable;
function copy(
version_id in apm_package_versions.version_id%TYPE,
new_version_id in apm_package_versions.version_id%TYPE default null,
new_version_name in apm_package_versions.version_name%TYPE,
new_version_uri in apm_package_versions.version_uri%TYPE
) return apm_package_versions.version_id%TYPE
is
v_version_id integer;
begin
v_version_id := acs_object.new(
object_id => new_version_id,
object_type => 'apm_package_version'
);
insert into apm_package_versions(version_id, package_key, version_name,
version_uri, summary, description_format, description,
release_date, vendor, vendor_uri)
select v_version_id, package_key, copy.new_version_name,
copy.new_version_uri, summary, description_format, description,
release_date, vendor, vendor_uri
from apm_package_versions
where version_id = copy.version_id;
insert into apm_package_dependencies(dependency_id, version_id, dependency_type, service_uri, service_version)
select acs_object_id_seq.nextval, v_version_id, dependency_type, service_uri, service_version
from apm_package_dependencies
where version_id = copy.version_id;
insert into apm_package_files(file_id, version_id, path, file_type)
select acs_object_id_seq.nextval, v_version_id, path, file_type
from apm_package_files
where version_id = copy.version_id;
insert into apm_package_owners(version_id, owner_uri, owner_name, sort_key)
select v_version_id, owner_uri, owner_name, sort_key
from apm_package_owners
where version_id = copy.version_id;
return v_version_id;
end copy;
function edit (
new_version_id in apm_package_versions.version_id%TYPE
default null,
version_id in apm_package_versions.version_id%TYPE,
version_name in apm_package_versions.version_name%TYPE
default null,
version_uri in apm_package_versions.version_uri%TYPE,
summary in apm_package_versions.summary%TYPE,
description_format in apm_package_versions.description_format%TYPE,
description in apm_package_versions.description%TYPE,
release_date in apm_package_versions.release_date%TYPE,
vendor in apm_package_versions.vendor%TYPE,
vendor_uri in apm_package_versions.vendor_uri%TYPE,
installed_p in apm_package_versions.installed_p%TYPE
default 'f',
data_model_loaded_p in apm_package_versions.data_model_loaded_p%TYPE
default 'f'
) return apm_package_versions.version_id%TYPE
is
v_version_id apm_package_versions.version_id%TYPE;
version_unchanged_p integer;
begin
-- Determine if version has changed.
select decode(count(*),0,0,1) into version_unchanged_p
from apm_package_versions
where version_id = edit.version_id
and version_name = edit.version_name;
if version_unchanged_p <> 1 then
v_version_id := copy(
version_id => edit.version_id,
new_version_id => edit.new_version_id,
new_version_name => edit.version_name,
new_version_uri => edit.version_uri
);
else
v_version_id := edit.version_id;
end if;
update apm_package_versions
set version_uri = edit.version_uri,
summary = edit.summary,
description_format = edit.description_format,
description = edit.description,
release_date = trunc(sysdate),
vendor = edit.vendor,
vendor_uri = edit.vendor_uri,
installed_p = edit.installed_p,
data_model_loaded_p = edit.data_model_loaded_p
where version_id = v_version_id;
return v_version_id;
end edit;
function add_file(
file_id in apm_package_files.file_id%TYPE
default null,
version_id in apm_package_versions.version_id%TYPE,
path in apm_package_files.path%TYPE,
file_type in apm_package_file_types.file_type_key%TYPE
) return apm_package_files.file_id%TYPE
is
v_file_id apm_package_files.file_id%TYPE;
v_file_exists_p integer;
begin
select file_id into v_file_id from apm_package_files
where version_id = add_file.version_id
and path = add_file.path;
return v_file_id;
exception
when NO_DATA_FOUND
then
if file_id is null then
select acs_object_id_seq.nextval into v_file_id from dual;
else
v_file_id := file_id;
end if;
insert into apm_package_files
(file_id, version_id, path, file_type)
values
(v_file_id, add_file.version_id, add_file.path, add_file.file_type);
return v_file_id;
end add_file;
-- Remove a file from the indicated version.
procedure remove_file(
version_id in apm_package_versions.version_id%TYPE,
path in apm_package_files.path%TYPE
)
is
begin
delete from apm_package_files
where version_id = remove_file.version_id
and path = remove_file.path;
end remove_file;
-- Add an interface provided by this version.
function add_interface(
interface_id in apm_package_dependencies.dependency_id%TYPE
default null,
version_id in apm_package_versions.version_id%TYPE,
interface_uri in apm_package_dependencies.service_uri%TYPE,
interface_version in apm_package_dependencies.service_version%TYPE
) return apm_package_dependencies.dependency_id%TYPE
is
v_dep_id apm_package_dependencies.dependency_id%TYPE;
begin
if add_interface.interface_id is null then
select acs_object_id_seq.nextval into v_dep_id from dual;
else
v_dep_id := add_interface.interface_id;
end if;
insert into apm_package_dependencies
(dependency_id, version_id, dependency_type, service_uri, service_version)
values
(v_dep_id, add_interface.version_id, 'provides', add_interface.interface_uri,
add_interface.interface_version);
return v_dep_id;
end add_interface;
procedure remove_interface(
interface_id in apm_package_dependencies.dependency_id%TYPE
)
is
begin
delete from apm_package_dependencies
where dependency_id = remove_interface.interface_id;
end remove_interface;
procedure remove_interface(
interface_uri in apm_package_dependencies.service_uri%TYPE,
interface_version in apm_package_dependencies.service_version%TYPE,
version_id in apm_package_versions.version_id%TYPE
)
is
v_dep_id apm_package_dependencies.dependency_id%TYPE;
begin
select dependency_id into v_dep_id from apm_package_dependencies
where service_uri = remove_interface.interface_uri
and interface_version = remove_interface.interface_version;
remove_interface(v_dep_id);
end remove_interface;
-- Add a requirement for this version. A requirement is some interface that this
-- version depends on.
function add_dependency(
dependency_id in apm_package_dependencies.dependency_id%TYPE
default null,
version_id in apm_package_versions.version_id%TYPE,
dependency_uri in apm_package_dependencies.service_uri%TYPE,
dependency_version in apm_package_dependencies.service_version%TYPE
) return apm_package_dependencies.dependency_id%TYPE
is
v_dep_id apm_package_dependencies.dependency_id%TYPE;
begin
if add_dependency.dependency_id is null then
select acs_object_id_seq.nextval into v_dep_id from dual;
else
v_dep_id := add_dependency.dependency_id;
end if;
insert into apm_package_dependencies
(dependency_id, version_id, dependency_type, service_uri, service_version)
values
(v_dep_id, add_dependency.version_id, 'requires', add_dependency.dependency_uri,
add_dependency.dependency_version);
return v_dep_id;
end add_dependency;
procedure remove_dependency(
dependency_id in apm_package_dependencies.dependency_id%TYPE
)
is
begin
delete from apm_package_dependencies
where dependency_id = remove_dependency.dependency_id;
end remove_dependency;
procedure remove_dependency(
dependency_uri in apm_package_dependencies.service_uri%TYPE,
dependency_version in apm_package_dependencies.service_version%TYPE,
version_id in apm_package_versions.version_id%TYPE
)
is
v_dep_id apm_package_dependencies.dependency_id%TYPE;
begin
select dependency_id into v_dep_id from apm_package_dependencies
where service_uri = remove_dependency.dependency_uri
and service_version = remove_dependency.dependency_version;
remove_dependency(v_dep_id);
end remove_dependency;
function sortable_version_name (
version_name in apm_package_versions.version_name%TYPE
) return varchar2
is
a_start integer;
a_end integer;
a_order varchar2(1000);
a_char char(1);
a_seen_letter char(1) := 'f';
begin
a_start := 1;
loop
a_end := a_start;
-- keep incrementing a_end until we run into a non-number
while substr(version_name, a_end, 1) >= '0' and substr(version_name, a_end, 1) <= '9' loop
a_end := a_end + 1;
end loop;
if a_end = a_start then
return -1;
-- raise_application_error(-20000, 'Expected number at position ' || a_start);
end if;
if a_end - a_start > 4 then
return -1;
-- raise_application_error(-20000, 'Numbers within versions can only be up to 4 digits long');
end if;
-- zero-pad and append the number
a_order := a_order || substr('0000', 1, 4 - (a_end - a_start)) ||
substr(version_name, a_start, a_end - a_start) || '.';
if a_end > length(version_name) then
-- end of string - we're outta here
if a_seen_letter = 'f' then
-- append the "final" suffix if there haven't been any letters
-- so far (i.e., not development/alpha/beta)
a_order := a_order || ' 3F.';
end if;
return a_order;
end if;
-- what's the next character? if a period, just skip it
a_char := substr(version_name, a_end, 1);
if a_char = '.' then
null;
else
-- if the next character was a letter, append the appropriate characters
if a_char = 'd' then
a_order := a_order || ' 0D.';
elsif a_char = 'a' then
a_order := a_order || ' 1A.';
elsif a_char = 'b' then
a_order := a_order || ' 2B.';
end if;
-- can't have something like 3.3a1b2 - just one letter allowed!
if a_seen_letter = 't' then
return -1;
-- raise_application_error(-20000, 'Not allowed to have two letters in version name '''
-- || version_name || '''');
end if;
a_seen_letter := 't';
-- end of string - we're done!
if a_end = length(version_name) then
return a_order;
end if;
end if;
a_start := a_end + 1;
end loop;
end sortable_version_name;
function version_name_greater(
version_name_one in apm_package_versions.version_name%TYPE,
version_name_two in apm_package_versions.version_name%TYPE
) return integer is
a_order_a varchar2(1000);
a_order_b varchar2(1000);
begin
a_order_a := sortable_version_name(version_name_one);
a_order_b := sortable_version_name(version_name_two);
if a_order_a < a_order_b then
return -1;
elsif a_order_a > a_order_b then
return 1;
end if;
return 0;
end version_name_greater;
function upgrade_p(
path in apm_package_files.path%TYPE,
initial_version_name in apm_package_versions.version_name%TYPE,
final_version_name in apm_package_versions.version_name%TYPE
) return integer
is
v_pos1 integer;
v_pos2 integer;
v_path apm_package_files.path%TYPE;
v_version_from apm_package_versions.version_name%TYPE;
v_version_to apm_package_versions.version_name%TYPE;
begin
-- Set v_path to the tail of the path (the file name).
v_path := substr(upgrade_p.path, instr(upgrade_p.path, '/', -1) + 1);
-- Remove the extension, if it's .sql.
v_pos1 := instr(v_path, '.', -1);
if v_pos1 > 0 and substr(v_path, v_pos1) = '.sql' then
v_path := substr(v_path, 1, v_pos1 - 1);
end if;
-- Figure out the from/to version numbers for the individual file.
v_pos1 := instr(v_path, '-', -1, 2);
v_pos2 := instr(v_path, '-', -1);
if v_pos1 = 0 or v_pos2 = 0 then
-- There aren't two hyphens in the file name. Bail.
return 0;
end if;
v_version_from := substr(v_path, v_pos1 + 1, v_pos2 - v_pos1 - 1);
v_version_to := substr(v_path, v_pos2 + 1);
if version_name_greater(upgrade_p.initial_version_name, v_version_from) <= 0 and
version_name_greater(upgrade_p.final_version_name, v_version_to) >= 0 then
return 1;
end if;
return 0;
exception when others then
-- Invalid version number.
return 0;
end upgrade_p;
procedure upgrade(
version_id in apm_package_versions.version_id%TYPE
)
is
begin
update apm_package_versions
set enabled_p = 'f',
installed_p = 'f'
where package_key = (select package_key from apm_package_versions
where version_id = upgrade.version_id);
update apm_package_versions
set enabled_p = 't',
installed_p = 't'
where version_id = upgrade.version_id;
end upgrade;
end apm_package_version;
/
show errors
--------------------------------------
-- RELATIONAL SEGMENTATION UPGRADE
-- oumi@arsdigita.com
-- 1/5/2001
--------------------------------------
-- PATCH GROUPS SYSTEM based on changes to groups-create.sql
-- combine group_member_index and group_component_index into
-- group_element_index.
create table group_element_index (
group_id not null
constraint group_element_index_grp_id_fk
references groups (group_id),
element_id not null
constraint group_element_index_elem_id_fk
references parties (party_id),
rel_id not null
constraint group_element_index_rel_id_fk
references acs_rels (rel_id),
container_id not null
constraint group_element_index_cont_id_fk
references groups (group_id),
rel_type not null
constraint group_elem_index_rel_type_fk
references acs_rel_types (rel_type),
ancestor_rel_type varchar2(100) not null
constraint grp_el_idx_ancstr_rel_type_ck
check (ancestor_rel_type in ('composition_rel','membership_rel')),
constraint group_element_index_pk
primary key (element_id, group_id, rel_id)
) organization index;
comment on table group_element_index is '
This table is for internal use by the parties system. It as an auxiliary
table, a denormalization of data, that is used to improve performance.
Do not query on this table or insert into it. Query on group_element_map
instead. And insert by using the API''s for membership_rel, composition_rel,
or some sub-type of those relationship types.
';
-- populate with data from group_member_map and group_component_map
insert into group_element_index
(group_id, element_id, rel_id, container_id, rel_type, ancestor_rel_type)
select gmm.group_id, gmm.member_id, gmm.rel_id, gmm.container_id,
acs_rels.rel_type, 'membership_rel' as ancestor_rel_type
from group_member_map gmm,
acs_rels
where gmm.rel_id = acs_rels.rel_id;
insert into group_element_index
(group_id, element_id, rel_id, container_id, rel_type, ancestor_rel_type)
select gcm.group_id, gcm.component_id, gcm.rel_id, gcm.container_id,
acs_rels.rel_type, 'composition_rel' as ancestor_rel_type
from group_component_map gcm,
acs_rels
where gcm.rel_id = acs_rels.rel_id;
create index group_elem_idx_group_idx on group_element_index (group_id);
create index group_elem_idx_element_idx on group_element_index (element_id);
create index group_elem_idx_rel_id_idx on group_element_index (rel_id);
create index group_elem_idx_container_idx on group_element_index (container_id);
create index group_elem_idx_rel_type_idx on group_element_index (rel_type);
-- create wrapper view for the above table.
create or replace view group_element_map
as select group_id, element_id, rel_id, container_id,
rel_type, ancestor_rel_type
from group_element_index;
-- Re-write the group_member_map and group_component_map views
-- as wrappers around group_element_index.
create or replace view group_component_map
as select group_id, element_id as component_id, rel_id, container_id, rel_type
from group_element_map
where ancestor_rel_type='composition_rel';
create or replace view group_member_map
as select group_id, element_id as member_id, rel_id, container_id, rel_type
from group_element_map
where ancestor_rel_type='membership_rel';
-- replace function that queried directly on group_component_index
create or replace function group_contains_p (group_id integer, component_id integer, rel_id integer default null) return char
is
begin
if group_id = component_id then
return 't';
else
if rel_id is null then
for map in (select *
from group_component_map
where component_id = group_contains_p.component_id
and group_id = container_id) loop
if group_contains_p(group_id, map.group_id) = 't' then
return 't';
end if;
end loop;
else
for map in (select *
from group_component_map
where component_id = group_contains_p.component_id
and rel_id = group_contains_p.rel_id
and group_id = container_id) loop
if group_contains_p(group_id, map.group_id) = 't' then
return 't';
end if;
end loop;
end if;
return 'f';
end if;
end;
/
show errors
-- If we're really confident, then we can drop the group_member_index
-- and group_component_index.
drop table group_component_index;
drop table group_member_index;
-- Just in case someone is still querying the group_component_index and
-- group_member_index directly, lets make them views.
create or replace view group_component_index as select * from group_component_map;
create or replace view group_member_index as select * from group_member_map;
----------------------------
-- CREATE REL SEGMENTS
-- oumi@arsdigita.com
-- 1/5/2001
-- Corresponding ACS File: ../rel-segments-create.sql
----------------------------
--
-- packages/acs-kernel/sql/rel-segments-create.sql
--
-- @author Oumi Mehrotra oumi@arsdigita.com
-- @creation-date 2000-11-22
-- @cvs-id $Id: upgrade-4.0.1-4.1b.sql,v 1.5 2024/09/11 06:15:47 gustafn Exp $
-- Copyright (C) 1999-2000 ArsDigita Corporation
-- This is free software distributed under the terms of the GNU Public
-- License. Full text of the license is available from the GNU Project:
-- http://www.fsf.org/copyleft/gpl.html
-- WARNING!
-- Relational segments is a new and experimental concept. The API may
-- change in the future, particularly the functions marked "EXPERIMENTAL".
--
begin
--
-- Relational Segment: a dynamically derived set of parties, defined
-- in terms of a particular type of membership or
-- composition to a particular group.
--
acs_object_type.create_type (
supertype => 'party',
object_type => 'rel_segment',
pretty_name => 'Relational Party Segment',
pretty_plural => 'Relational Party Segments',
table_name => 'rel_segments',
id_column => 'segment_id',
package_name => 'rel_segment',
type_extension_table => 'rel_segment',
name_method => 'rel_segment.name'
);
end;
/
show errors
-- Note that we do not use on delete cascade on the group_id or
-- rel_type column because rel_segments are acs_objects. On delete
-- cascade only deletes the corresponding row in this table, not all
-- the rows up the type hierarchy. Thus, rel segments must be deleted
-- using rel_segment.delete before dropping a relationship type.
create table rel_segments (
segment_id not null
constraint rel_segments_segment_id_fk
references parties (party_id)
constraint rel_segments_pk primary key,
segment_name varchar2(230) not null,
group_id not null
constraint rel_segments_group_id_fk
references groups (group_id),
rel_type not null
constraint rel_segments_rel_type_fk
references acs_rel_types (rel_type),
constraint rel_segments_grp_rel_type_uq unique(group_id, rel_type)
);
-- rel_type has a foreign key reference - create an index
create index rel_segments_rel_type_idx on rel_segments(rel_type);
comment on table rel_segments is '
Defines relational segments. Each relational segment is a pair of
group_id
/ rel_type
, or, in english, the
parties that have a relation of type rel_type to group_id.
';
comment on column rel_segments.segment_name is '
The user-entered name of the relational segment.
';
comment on column rel_segments.group_id is '
The group for which this segment was created.
';
comment on column rel_segments.rel_type is '
The relationship type used to define elements in this segment.
';
-- create pl/sql package rel_segment
create or replace package rel_segment
is
function new (
--/** Creates a new relational segment
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
--*/
segment_id in rel_segments.segment_id%TYPE default null,
object_type in acs_objects.object_type%TYPE
default 'rel_segment',
creation_date in acs_objects.creation_date%TYPE
default sysdate,
creation_user in acs_objects.creation_user%TYPE
default null,
creation_ip in acs_objects.creation_ip%TYPE default null,
email in parties.email%TYPE default null,
url in parties.url%TYPE default null,
segment_name in rel_segments.segment_name%TYPE,
group_id in rel_segments.group_id%TYPE,
rel_type in rel_segments.rel_type%TYPE,
context_id in acs_objects.context_id%TYPE default null
) return rel_segments.segment_id%TYPE;
procedure delete (
--/** Deletes a relational segment
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
--*/
segment_id in rel_segments.segment_id%TYPE
);
function name (
segment_id in rel_segments.segment_id%TYPE
) return rel_segments.segment_name%TYPE;
function get (
--/** EXPERIMENTAL / UNSTABLE -- use at your own risk
-- Get the id of a segment given a group_id and rel_type.
-- This depends on the uniqueness of group_id,rel_type. We
-- might remove the unique constraint in the future, in which
-- case we would also probably remove this function.
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
--*/
group_id in rel_segments.group_id%TYPE,
rel_type in rel_segments.rel_type%TYPE
) return rel_segments.segment_id%TYPE;
function get_or_new (
--/** EXPERIMENTAL / UNSTABLE -- use at your own risk
--
-- This function simplifies the use of segments a little by letting
-- you not have to worry about creating and initializing segments.
-- If the segment you're interested in exists, this function
-- returns its segment_id.
-- If the segment you're interested in doesn't exist, this function
-- does a pretty minimal amount of initialization for the segment
-- and returns a new segment_id.
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
--*/
group_id in rel_segments.group_id%TYPE,
rel_type in rel_segments.rel_type%TYPE,
segment_name in rel_segments.segment_name%TYPE
default null
) return rel_segments.segment_id%TYPE;
end rel_segment;
/
show errors
-----------
-- Views --
-----------
create or replace view rel_segment_party_map
as select rs.segment_id, gem.element_id as party_id, gem.rel_id, gem.rel_type,
gem.group_id, gem.container_id, gem.ancestor_rel_type
from rel_segments rs,
(select ancestor_type, object_type
from acs_object_type_supertype_map
union
select object_type, object_type
from acs_object_types) otsm,
group_element_map gem
where rs.rel_type = otsm.ancestor_type
and otsm.object_type = gem.rel_type
and gem.group_id = rs.group_id;
create or replace view rel_segment_distinct_party_map
as select distinct segment_id, party_id, ancestor_rel_type
from rel_segment_party_map;
create or replace view rel_segment_member_map
as select segment_id, party_id as member_id, rel_id, rel_type,
group_id, container_id
from rel_segment_party_map
where ancestor_rel_type = 'membership_rel';
create or replace view rel_seg_approved_member_map
as select rspm.segment_id, rspm.party_id as member_id, rspm.rel_id,
rspm.rel_type, rspm.group_id, rspm.container_id
from rel_segment_party_map rspm, membership_rels mr
where rspm.rel_id = mr.rel_id
and mr.member_state = 'approved';
create or replace view rel_seg_distinct_member_map
as select distinct segment_id, member_id
from rel_seg_approved_member_map;
-- party_member_map can be used to expand any party into its members.
-- Every party is considered to be a member of itself.
-- By the way, aren't the party_member_map and party_approved_member_map
-- views equivalent?? (TO DO: RESOLVE THIS QUESTION)
create or replace view party_member_map
as select segment_id as party_id, member_id
from rel_seg_distinct_member_map
union
select group_id as party_id, member_id
from group_distinct_member_map
union
select party_id, party_id as member_id
from parties;
create or replace view party_approved_member_map
as select distinct segment_id as party_id, member_id
from rel_seg_approved_member_map
union
select distinct group_id as party_id, member_id
from group_approved_member_map
union
select party_id, party_id as member_id
from parties;
-- party_element_map tells us all the parties that "belong to" a party,
-- whether through somet type of membership, composition, or identity.
create or replace view party_element_map
as select distinct group_id as party_id, element_id
from group_element_map
union
select distinct segment_id as party_id, party_id as element_id
from rel_segment_party_map
union
select party_id, party_id as element_id
from parties;
----------------------------
-- RELATIONAL CONSTRAINTS --
-- oumi@arsdigita.com
-- 1/5/2001
-- Corresponding ACS File: ../rel-constraints-create
----------------------------
--
-- /packages/acs-kernel/sql/rel-constraints-create.sql
--
-- Add support for relational constraints based on relational segmentation.
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 2000-11-22
-- @cvs-id $Id: upgrade-4.0.1-4.1b.sql,v 1.5 2024/09/11 06:15:47 gustafn Exp $
-- Copyright (C) 1999-2000 ArsDigita Corporation
-- This is free software distributed under the terms of the GNU Public
-- License. Full text of the license is available from the GNU Project:
-- http://www.fsf.org/copyleft/gpl.html
-- WARNING!
-- Relational constraints is a new and experimental concept. The API may
-- change in the future, particularly the functions marked "EXPERIMENTAL".
--
begin
acs_object_type.create_type(
object_type => 'rel_constraint',
pretty_name => 'Relational Constraint',
pretty_plural => 'Relational Constraints',
supertype => 'acs_object',
table_name => 'rel_constraints',
id_column => 'constraint_id',
package_name => 'rel_constraint'
);
end;
/
show errors
create table rel_constraints (
constraint_id integer
constraint rel_constraints_pk
primary key
constraint rc_constraint_id_fk
references acs_objects(object_id),
constraint_name varchar(100) not null,
rel_segment not null
constraint rc_rel_segment_fk
references rel_segments (segment_id),
rel_side char(3) default 'two' not null
constraint rc_rel_side_ck
check (rel_side in
('one', 'two')),
required_rel_segment not null
constraint rc_required_rel_segment
references rel_segments (segment_id),
constraint rel_constraints_uq
unique (rel_segment, rel_side, required_rel_segment)
);
-- required_rel_segment has a foreign key reference - create an index
create index rel_constraint_req_rel_seg_idx on rel_constraints(required_rel_segment)
comment on table rel_constraints is '
Defines relational constraints. The relational constraints system is
intended to support applications in modelling and applying
constraint rules on inter-party relatinships based on relational
party segmentation.
';
comment on column rel_constraints.constraint_name is '
The user-defined name of this constraint.
';
comment on column rel_constraints.rel_segment is '
The segment for which the constraint is defined.
';
comment on column rel_constraints.rel_side is '
The side of the relation the constraint applies to.
';
comment on column rel_constraints.required_rel_segment is '
The segment in which elements must be in to satisfy the constraint.
';
-----------
-- VIEWS --
-----------
-- View rel_constraints_violated_one
--
-- pseudo sql:
--
-- select all the side 'one' constraints
-- from the constraints and the associated relations of rel_segment
-- where the relation's container_id (i.e., object_id_one) is not in the
-- relational segment required_rel_segment.
create or replace view rel_constraints_violated_one as
select constrained_rels.*
from (select rel_constraints.constraint_id, rel_constraints.constraint_name,
r.rel_id, r.container_id, r.party_id, r.rel_type,
rel_constraints.rel_segment,
rel_constraints.rel_side,
rel_constraints.required_rel_segment
from rel_constraints, rel_segment_party_map r
where rel_constraints.rel_side = 'one'
and rel_constraints.rel_segment = r.segment_id
) constrained_rels,
rel_segment_party_map rspm
where rspm.segment_id(+) = constrained_rels.required_rel_segment
and rspm.party_id(+) = constrained_rels.container_id
and rspm.party_id is null;
-- Originally, we tried this view. It was slow. The one above is much
-- less slow. It moves the "not exists" query to an outer join, checking
-- for null rows in the outer join table. This turns out to be much faster
-- than "not exists".
--
-- create or replace view rel_constraints_violated_one as
-- select rel_constraints.constraint_id, rel_constraints.constraint_name,
-- r.rel_id, r.container_id, r.party_id, r.rel_type,
-- rel_constraints.rel_segment,
-- rel_constraints.rel_side,
-- rel_constraints.required_rel_segment
-- from rel_constraints, rel_segment_party_map r
-- where rel_constraints.rel_side = 'one'
-- and rel_constraints.rel_segment = r.segment_id
-- and not exists (
-- select 1 from rel_segment_party_map rspm
-- where rspm.segment_id = rel_constraints.required_rel_segment
-- and rspm.party_id = r.container_id
-- );
-- View rel_constraints_violated_two
--
-- pseudo sql:
--
-- select all the side 'two' constraints
-- from the constraints and the associated relations of rel_segment
-- where the relation's party_id (i.e., object_id_two) is not in the
-- relational segment required_rel_segment.
create or replace view rel_constraints_violated_two as
select constrained_rels.*
from (select rel_constraints.constraint_id, rel_constraints.constraint_name,
r.rel_id, r.container_id, r.party_id, r.rel_type,
rel_constraints.rel_segment,
rel_constraints.rel_side,
rel_constraints.required_rel_segment
from rel_constraints, rel_segment_party_map r
where rel_constraints.rel_side = 'two'
and rel_constraints.rel_segment = r.segment_id
) constrained_rels,
rel_segment_party_map rspm
where rspm.segment_id(+) = constrained_rels.required_rel_segment
and rspm.party_id(+) = constrained_rels.party_id
and rspm.party_id is null;
-- Originally, we tried this view. It was slow. The one above is much
-- less slow. It moves the "not exists" query to an outer join, checking
-- for null rows in the outer join table. This turns out to be much faster
-- than "not exists".
--
-- create or replace view rel_constraints_violated_two as
-- select rel_constraints.constraint_id, rel_constraints.constraint_name,
-- r.rel_id, r.container_id, r.party_id, r.rel_type,
-- rel_constraints.rel_segment,
-- rel_constraints.rel_side,
-- rel_constraints.required_rel_segment
-- from rel_constraints, rel_segment_party_map r
-- where rel_constraints.rel_side = 'two'
-- and rel_constraints.rel_segment = r.segment_id
-- and not exists (
-- select 1 from rel_segment_party_map rspm
-- where rspm.segment_id = rel_constraints.required_rel_segment
-- and rspm.party_id = r.party_id
-- );
-- View: rc_required_rel_segments
--
-- Question: Given group :group_id and rel_type :rel_type . . .
--
-- What segments must a party be in
-- if the party were to be belong to group :group_id
-- through a relation of type :rel_type ?
--
-- Answer: select required_rel_segment
-- from rc_required_rel_segments
-- where group_id = :group_id
-- and rel_type = :rel_type
--
create or replace view rc_required_rel_segments as
select group_ancestor_map.group_id,
rel_segments.rel_type,
required_rel_segment
from (select component_id as group_id,
group_id as ancestor_group_id
from group_component_map
union
select group_id as component_group_id,
group_id as ancestor_group_id
from groups) group_ancestor_map,
rel_segments,
rel_constraints
where rel_segments.group_id = group_ancestor_map.ancestor_group_id
and rel_constraints.rel_segment = rel_segments.segment_id
and rel_constraints.rel_side = 'two';
-- View: rc_parties_in_required_segs
--
-- Question: Given group :group_id and rel_type :rel_type . . .
--
-- What parties are "allowed" to be in group :group_id
-- through a relation of type :rel_type ? By "allowed",
-- we mean that no relational constraints would be violated.
--
-- Answer: select party_id, acs_object.name(party_id)
-- from parties_in_rc_required_rel_segments
-- where group_id = :group_id
-- and rel_type = :rel_type
--
create or replace view rc_parties_in_required_segs as
select parties_in_required_segs.group_id,
parties_in_required_segs.rel_type,
parties_in_required_segs.party_id
from
(select required_segs.group_id,
required_segs.rel_type,
seg_parties.party_id,
count(*) as num_matching_segs
from rc_required_rel_segments required_segs,
rel_segment_party_map seg_parties
where required_segs.required_rel_segment = seg_parties.segment_id
group by required_segs.group_id,
required_segs.rel_type,
seg_parties.party_id) parties_in_required_segs,
(select group_id, rel_type, count(*) as total
from rc_required_rel_segments
group by group_id, rel_type) total_num_required_segs
where
parties_in_required_segs.group_id = total_num_required_segs.group_id
and parties_in_required_segs.rel_type = total_num_required_segs.rel_type
and parties_in_required_segs.num_matching_segs = total_num_required_segs.total
UNION ALL
select group_rel_type_party_combos.group_id,
group_rel_type_party_combos.rel_type,
parties.party_id
from rc_required_rel_segments,
(select groups.group_id, acs_rel_types.rel_type
from groups, acs_rel_types) group_rel_type_party_combos,
parties
where rc_required_rel_segments.group_id(+) = group_rel_type_party_combos.group_id
and rc_required_rel_segments.rel_type(+) = group_rel_type_party_combos.rel_type
and rc_required_rel_segments.group_id is null;
-- View: rc_violations_by_removing_rel
--
-- Question: Given relation :rel_id
--
-- If we were to remove the relation specified by rel_id,
-- what constraints would be violated and by what parties?
--
-- Answer: select r.rel_id, r.constraint_id, r.constraint_name
-- acs_object_type.pretty_name(r.rel_type) as rel_type_pretty_name,
-- acs_object.name(r.object_id_one) as object_id_one_name,
-- acs_object.name(r.object_id_two) as object_id_two_name
-- from rc_violations_by_removing_rel r
-- where r.segment_rel_id = :rel_id
--
create or replace view rc_violations_by_removing_rel as
select r.rel_type as viol_rel_type, r.rel_id as viol_rel_id,
r.object_id_one as viol_object_id_one, r.object_id_two as viol_object_id_two,
s.rel_id,
cons.constraint_id, cons.constraint_name,
map.segment_id, map.party_id, map.group_id, map.container_id, map.ancestor_rel_type
from acs_rels r, rel_segment_party_map map, rel_constraints cons,
(select s.segment_id, r.rel_id
from rel_segments s, acs_rels r
where r.object_id_one = s.group_id
and r.rel_type = s.rel_type) s
where map.party_id = r.object_id_two
and map.rel_id = r.rel_id
and cons.rel_segment = map.segment_id
and cons.required_rel_segment = s.segment_id;
create or replace package rel_constraint
as
function new (
--/** Creates a new relational constraint
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
--*/
constraint_id in rel_constraints.constraint_id%TYPE default null,
constraint_type in acs_objects.object_type%TYPE default 'rel_constraint',
constraint_name in rel_constraints.constraint_name%TYPE,
rel_segment in rel_constraints.rel_segment%TYPE,
rel_side in rel_constraints.rel_side%TYPE default 'two',
required_rel_segment in rel_constraints.required_rel_segment%TYPE,
context_id in acs_objects.context_id%TYPE default null,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return rel_constraints.constraint_id%TYPE;
procedure delete (
constraint_id in rel_constraints.constraint_id%TYPE
);
function get_constraint_id (
--/** Returns the constraint_id associated with the specified
-- rel_segment and required_rel_segment for the specified site.
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
--*/
rel_segment in rel_constraints.rel_segment%TYPE,
rel_side in rel_constraints.rel_side%TYPE default 'two',
required_rel_segment in rel_constraints.required_rel_segment%TYPE
) return rel_constraints.constraint_id%TYPE;
function violation (
--/** Checks to see if there a relational constraint is violated
-- by the presence of the specified relation. If not, returns
-- null. If so, returns an appropriate error string.
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 12/2000
--
-- @param rel_id The relation for which we want to find
-- any violations
--*/
rel_id in acs_rels.rel_id%TYPE
) return varchar;
function violation_if_removed (
--/** Checks to see if removing the specified relation would violate
-- a relational constraint. If not, returns null. If so, returns
-- an appropriate error string.
--
-- @author Michael Bryzek (mbryzek@arsdigita.com)
-- @creation-date 1/2001
--
-- @param rel_id The relation that we are planning to remove
--*/
rel_id in acs_rels.rel_id%TYPE
) return varchar;
end;
/
show errors
-----------------------------
-- UPDATE ACS_OBJECT_TYPES AND ACS_REL_ROLES
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- add dynamic_p column to acs_object_types
-- add pretty_name, pretty_plural to acs_rel_roles and setup defaults
-----------------------------
-- we need a flag to know if object types were created dynamically and
-- can thus be administered through the web
alter table acs_object_types add ( dynamic_p char(1) default 'f'
constraint acs_obj_types_dynamic_p_ck
check (dynamic_p in ('t', 'f')));
comment on column acs_object_types.dynamic_p is '
This flag is used to identify object types created dynamically
(e.g. through a web interface). Dynamically created object types can
be administered differently. For example, the group type admin pages
only allow users to add attributes or otherwise modify dynamic
object types. This column is still experimental and may not be supported in the
future. That is the reason it is not yet part of the API.
';
-- Roles need pretty names and the such. Note we add them separately
-- in case one has already been added on an acs installation
alter table acs_rel_roles add (
pretty_name varchar2(100)
);
alter table acs_rel_roles add (
pretty_plural varchar2(100)
);
-- do these two updates separately in case the installation we are upgrading
-- has altered these two columns
update acs_rel_roles set pretty_name='Member', pretty_plural='Members' where role='member';
update acs_rel_roles set pretty_name='Composite', pretty_plural='Composites' where role='composite';
update acs_rel_roles set pretty_name='Component', pretty_plural='Components' where role='component';
update acs_rel_roles set pretty_name=role where pretty_name is null;
update acs_rel_roles set pretty_plural=role where pretty_plural is null;
alter table acs_rel_roles modify pretty_name not null;
alter table acs_rel_roles modify pretty_plural not null;
-----------------------------
-- PACKAGE BODY PARTY --
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- fix delete to simply call acs_object.delete
------------------------------
create or replace package body party
as
function new (
party_id in parties.party_id%TYPE default null,
object_type in acs_objects.object_type%TYPE
default 'party',
creation_date in acs_objects.creation_date%TYPE
default sysdate,
creation_user in acs_objects.creation_user%TYPE
default null,
creation_ip in acs_objects.creation_ip%TYPE default null,
email in parties.email%TYPE,
url in parties.url%TYPE default null,
context_id in acs_objects.context_id%TYPE default null
)
return parties.party_id%TYPE
is
v_party_id parties.party_id%TYPE;
begin
v_party_id :=
acs_object.new(party_id, object_type,
creation_date, creation_user, creation_ip, context_id);
insert into parties
(party_id, email, url)
values
(v_party_id, lower(email), url);
return v_party_id;
end new;
procedure delete (
party_id in parties.party_id%TYPE
)
is
begin
acs_object.delete(party_id);
end delete;
function name (
party_id in parties.party_id%TYPE
)
return varchar2
is
begin
if party_id = -1 then
return 'The Public';
else
return null;
end if;
end name;
end party;
/
show errors
-----------------------------
-- MODIFICATIONS TO GROUPS --
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- defined default and permissible relationship types for group
-- types and groups
-- NEW TABLES: group_type_rels, group_rels with defaults set for existing groups
-----------------------------
create table group_type_rels (
group_rel_type_id integer constraint gtr_group_rel_type_id_pk primary key,
rel_type not null
constraint gtr_rel_type_fk
references acs_rel_types (rel_type)
on delete cascade,
group_type not null
constraint gtr_group_type_fk
references acs_object_types (object_type)
on delete cascade,
constraint gtr_group_rel_types_un unique (group_type, rel_type)
);
-- rel_type references acs_rel_types. Create an index
create index group_type_rels_rel_type_idx on group_type_rels(rel_type);
comment on table group_type_rels is '
Stores the default relationship types available for use by groups of
a given type. We May want to generalize this table to object_types and
put it in the relationships sql file, though there is no need to do so
right now.
';
-- define standard types for groups of type 'group'
insert into group_type_rels
(group_rel_type_id, rel_type, group_type)
values
(acs_object_id_seq.nextval, 'membership_rel', 'group');
insert into group_type_rels
(group_rel_type_id, rel_type, group_type)
values
(acs_object_id_seq.nextval, 'composition_rel', 'group');
create table group_rels (
group_rel_id integer constraint group_rels_group_rel_id_pk primary key,
rel_type not null
constraint group_rels_rel_type_fk
references acs_rel_types (rel_type)
on delete cascade,
group_id not null
constraint group_rels_group_id_fk
references groups (group_id)
on delete cascade,
constraint group_rels_group_rel_type_un unique (group_id, rel_type)
);
-- rel_type references acs_rel_types. Create an index
create index group_rels_rel_type_idx on group_rels(rel_type);
comment on table group_rels is '
Stores the relationship types available for use by each group. Only
relationship types in this table are offered for adding
relations. Note that there is no restriction that says groups can
only have relationship types specified for their group type. The
group_type_rels
table just stores defaults for groups
of a new type.
';
-- insert defaults for all groups.
BEGIN
for rel_types in (select rel_type from acs_rel_types where rel_type in ('membership_rel','composition_rel')) loop
for row in (select group_id from groups) loop
insert into group_rels
(group_rel_id, rel_type, group_id)
values
(acs_object_id_seq.nextval, rel_types.rel_type, row.group_id);
end loop;
end loop;
END;
/
show errors
-------------------------------
-- ACS_OBJECT_ATTRIBUTE_VIEW
-- mbryzek@arsdigita.com
-- 1/5/2001
-------------------------------
-- Create a view to show us all the attributes for one object,
-- including attributes for each of its supertypes
create or replace view acs_object_type_attributes as
select all_types.object_type, all_types.ancestor_type,
attr.attribute_id, attr.table_name, attr.attribute_name,
attr.pretty_name, attr.pretty_plural, attr.sort_order,
attr.datatype, attr.default_value, attr.min_n_values,
attr.max_n_values, attr.storage, attr.static_p, attr.column_name
from acs_attributes attr,
(select map.object_type, map.ancestor_type
from acs_object_type_supertype_map map, acs_object_types t
where map.object_type=t.object_type
UNION
select t.object_type, t.object_type as ancestor_type
from acs_object_types t) all_types
where attr.object_type = all_types.ancestor_type;
-----------------------------
-- PACKAGE ACS_OBJECT_TYPE
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- Add a type->pretty_name lookup function
-- Drop all attributes of an object type when dropping the object type
-----------------------------
create or replace package acs_object_type
is
-- define an object type
procedure create_type (
object_type in acs_object_types.object_type%TYPE,
pretty_name in acs_object_types.pretty_name%TYPE,
pretty_plural in acs_object_types.pretty_plural%TYPE,
supertype in acs_object_types.supertype%TYPE
default 'acs_object',
table_name in acs_object_types.table_name%TYPE,
id_column in acs_object_types.id_column%TYPE default 'XXX',
package_name in acs_object_types.package_name%TYPE default null,
abstract_p in acs_object_types.abstract_p%TYPE default 'f',
type_extension_table in acs_object_types.type_extension_table%TYPE
default null,
name_method in acs_object_types.name_method%TYPE default null
);
-- delete an object type definition
procedure drop_type (
object_type in acs_object_types.object_type%TYPE,
cascade_p in char default 'f'
);
-- look up an object type's pretty_name
function pretty_name (
object_type in acs_object_types.object_type%TYPE
) return acs_object_types.pretty_name%TYPE;
end acs_object_type;
/
show errors
create or replace package body acs_object_type
is
procedure create_type (
object_type in acs_object_types.object_type%TYPE,
pretty_name in acs_object_types.pretty_name%TYPE,
pretty_plural in acs_object_types.pretty_plural%TYPE,
supertype in acs_object_types.supertype%TYPE
default 'acs_object',
table_name in acs_object_types.table_name%TYPE,
id_column in acs_object_types.id_column%TYPE,
package_name in acs_object_types.package_name%TYPE default null,
abstract_p in acs_object_types.abstract_p%TYPE default 'f',
type_extension_table in acs_object_types.type_extension_table%TYPE
default null,
name_method in acs_object_types.name_method%TYPE default null
)
is
v_package_name acs_object_types.package_name%TYPE;
begin
-- XXX This is a hack for losers who haven't created packages yet.
if package_name is null then
v_package_name := object_type;
else
v_package_name := package_name;
end if;
insert into acs_object_types
(object_type, pretty_name, pretty_plural, supertype, table_name,
id_column, abstract_p, type_extension_table, package_name,
name_method)
values
(object_type, pretty_name, pretty_plural, supertype, table_name,
id_column, abstract_p, type_extension_table, v_package_name,
name_method);
end create_type;
procedure drop_type (
object_type in acs_object_types.object_type%TYPE,
cascade_p in char default 'f'
)
is
cursor c_attributes (object_type IN varchar) is
select attribute_name from acs_attributes where object_type = object_type;
begin
-- drop all the attributes associated with this type
for row in c_attributes (drop_type.object_type) loop
acs_attribute.drop_attribute ( drop_type.object_type, row.attribute_name );
end loop;
delete from acs_attributes
where object_type = drop_type.object_type;
delete from acs_object_types
where object_type = drop_type.object_type;
end drop_type;
function pretty_name (
object_type in acs_object_types.object_type%TYPE
) return acs_object_types.pretty_name%TYPE
is
v_pretty_name acs_object_types.pretty_name%TYPE;
begin
select t.pretty_name into v_pretty_name
from acs_object_types t
where t.object_type = pretty_name.object_type;
return v_pretty_name;
end pretty_name;
end acs_object_type;
/
show errors
-----------------------------
-- PACKAGE BODY ACS_ATTRIBUTE
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- Modified drop_attribute to delete all values from acs_enum_values
-- when dropping an attribute
-----------------------------
create or replace package body acs_attribute
is
function create_attribute (
object_type in acs_attributes.object_type%TYPE,
attribute_name in acs_attributes.attribute_name%TYPE,
datatype in acs_attributes.datatype%TYPE,
pretty_name in acs_attributes.pretty_name%TYPE,
pretty_plural in acs_attributes.pretty_plural%TYPE default null,
table_name in acs_attributes.table_name%TYPE default null,
column_name in acs_attributes.column_name%TYPE default null,
default_value in acs_attributes.default_value%TYPE default null,
min_n_values in acs_attributes.min_n_values%TYPE default 1,
max_n_values in acs_attributes.max_n_values%TYPE default 1,
sort_order in acs_attributes.sort_order%TYPE default null,
storage in acs_attributes.storage%TYPE default 'type_specific',
static_p in acs_attributes.static_p%TYPE default 'f'
) return acs_attributes.attribute_id%TYPE
is
v_sort_order acs_attributes.sort_order%TYPE;
v_attribute_id acs_attributes.attribute_id%TYPE;
begin
if sort_order is null then
select nvl(max(sort_order), 1) into v_sort_order
from acs_attributes
where object_type = create_attribute.object_type
and attribute_name = create_attribute.attribute_name;
else
v_sort_order := sort_order;
end if;
select acs_attribute_id_seq.nextval into v_attribute_id from dual;
insert into acs_attributes
(attribute_id, object_type, table_name, column_name, attribute_name,
pretty_name, pretty_plural, sort_order, datatype, default_value,
min_n_values, max_n_values, storage, static_p)
values
(v_attribute_id, object_type, table_name, column_name, attribute_name,
pretty_name, pretty_plural, v_sort_order, datatype, default_value,
min_n_values, max_n_values, storage, static_p);
return v_attribute_id;
end create_attribute;
procedure drop_attribute (
object_type in varchar2,
attribute_name in varchar2
)
is
begin
-- first remove possible values for the enumeration
delete from acs_enum_values
where attribute_id in (select a.attribute_id
from acs_attributes a
where a.object_type = drop_attribute.object_type
and a.attribute_name = drop_attribute.attribute_name);
delete from acs_attributes
where object_type = drop_attribute.object_type
and attribute_name = drop_attribute.attribute_name;
end drop_attribute;
procedure add_description (
object_type in acs_attribute_descriptions.object_type%TYPE,
attribute_name in acs_attribute_descriptions.attribute_name%TYPE,
description_key in acs_attribute_descriptions.description_key%TYPE,
description in acs_attribute_descriptions.description%TYPE
)
is
begin
insert into acs_attribute_descriptions
(object_type, attribute_name, description_key, description)
values
(add_description.object_type, add_description.attribute_name,
add_description.description_key, add_description.description);
end;
procedure drop_description (
object_type in acs_attribute_descriptions.object_type%TYPE,
attribute_name in acs_attribute_descriptions.attribute_name%TYPE,
description_key in acs_attribute_descriptions.description_key%TYPE
)
is
begin
delete from acs_attribute_descriptions
where object_type = drop_description.object_type
and attribute_name = drop_description.attribute_name
and description_key = drop_description.description_key;
end;
end acs_attribute;
/
show errors
-----------------------------
-- PACKAGE ACS_REL_TYPE
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- Modified create_role to accept pretty_name and pretty_plural
-- added role_pretty_name, role_pretty_plural functions
-- Modified drop_type to call acs_object_type.drop_type
-----------------------------
create or replace package acs_rel_type
as
procedure create_role (
role in acs_rel_roles.role%TYPE,
pretty_name in acs_rel_roles.pretty_name%TYPE default null,
pretty_plural in acs_rel_roles.pretty_plural%TYPE default null
);
procedure drop_role (
role in acs_rel_roles.role%TYPE
);
function role_pretty_name (
role in acs_rel_roles.role%TYPE
) return acs_rel_roles.pretty_name%TYPE;
function role_pretty_plural (
role in acs_rel_roles.role%TYPE
) return acs_rel_roles.pretty_plural%TYPE;
procedure create_type (
rel_type in acs_rel_types.rel_type%TYPE,
pretty_name in acs_object_types.pretty_name%TYPE,
pretty_plural in acs_object_types.pretty_plural%TYPE,
supertype in acs_object_types.supertype%TYPE
default 'relationship',
table_name in acs_object_types.table_name%TYPE,
id_column in acs_object_types.id_column%TYPE,
package_name in acs_object_types.package_name%TYPE,
abstract_p in acs_object_types.abstract_p%TYPE default 'f',
type_extension_table in acs_object_types.type_extension_table%TYPE
default null,
name_method in acs_object_types.name_method%TYPE default null,
object_type_one in acs_rel_types.object_type_one%TYPE,
role_one in acs_rel_types.role_one%TYPE default null,
min_n_rels_one in acs_rel_types.min_n_rels_one%TYPE,
max_n_rels_one in acs_rel_types.max_n_rels_one%TYPE,
object_type_two in acs_rel_types.object_type_two%TYPE,
role_two in acs_rel_types.role_two%TYPE default null,
min_n_rels_two in acs_rel_types.min_n_rels_two%TYPE,
max_n_rels_two in acs_rel_types.max_n_rels_two%TYPE
);
procedure drop_type (
rel_type in acs_rel_types.rel_type%TYPE,
cascade_p in char default 'f'
);
end acs_rel_type;
/
show errors
create or replace package body acs_rel_type
as
procedure create_role (
role in acs_rel_roles.role%TYPE,
pretty_name in acs_rel_roles.pretty_name%TYPE default null,
pretty_plural in acs_rel_roles.pretty_plural%TYPE default null
)
is
begin
insert into acs_rel_roles
(role, pretty_name, pretty_plural)
values
(create_role.role, nvl(create_role.pretty_name,create_role.role), nvl(create_role.pretty_plural,create_role.role));
end;
procedure drop_role (
role in acs_rel_roles.role%TYPE
)
is
begin
delete from acs_rel_roles
where role = drop_role.role;
end;
function role_pretty_name (
role in acs_rel_roles.role%TYPE
) return acs_rel_roles.pretty_name%TYPE
is
v_pretty_name acs_rel_roles.pretty_name%TYPE;
begin
select r.pretty_name into v_pretty_name
from acs_rel_roles r
where r.role = role_pretty_name.role;
return v_pretty_name;
end role_pretty_name;
function role_pretty_plural (
role in acs_rel_roles.role%TYPE
) return acs_rel_roles.pretty_plural%TYPE
is
v_pretty_plural acs_rel_roles.pretty_plural%TYPE;
begin
select r.pretty_plural into v_pretty_plural
from acs_rel_roles r
where r.role = role_pretty_plural.role;
return v_pretty_plural;
end role_pretty_plural;
procedure create_type (
rel_type in acs_rel_types.rel_type%TYPE,
pretty_name in acs_object_types.pretty_name%TYPE,
pretty_plural in acs_object_types.pretty_plural%TYPE,
supertype in acs_object_types.supertype%TYPE
default 'relationship',
table_name in acs_object_types.table_name%TYPE,
id_column in acs_object_types.id_column%TYPE,
package_name in acs_object_types.package_name%TYPE,
abstract_p in acs_object_types.abstract_p%TYPE default 'f',
type_extension_table in acs_object_types.type_extension_table%TYPE
default null,
name_method in acs_object_types.name_method%TYPE default null,
object_type_one in acs_rel_types.object_type_one%TYPE,
role_one in acs_rel_types.role_one%TYPE default null,
min_n_rels_one in acs_rel_types.min_n_rels_one%TYPE,
max_n_rels_one in acs_rel_types.max_n_rels_one%TYPE,
object_type_two in acs_rel_types.object_type_two%TYPE,
role_two in acs_rel_types.role_two%TYPE default null,
min_n_rels_two in acs_rel_types.min_n_rels_two%TYPE,
max_n_rels_two in acs_rel_types.max_n_rels_two%TYPE
)
is
begin
acs_object_type.create_type(
object_type => rel_type,
pretty_name => pretty_name,
pretty_plural => pretty_plural,
supertype => supertype,
table_name => table_name,
id_column => id_column,
package_name => package_name,
abstract_p => abstract_p,
type_extension_table => type_extension_table,
name_method => name_method
);
insert into acs_rel_types
(rel_type,
object_type_one, role_one,
min_n_rels_one, max_n_rels_one,
object_type_two, role_two,
min_n_rels_two, max_n_rels_two)
values
(create_type.rel_type,
create_type.object_type_one, create_type.role_one,
create_type.min_n_rels_one, create_type.max_n_rels_one,
create_type.object_type_two, create_type.role_two,
create_type.min_n_rels_two, create_type.max_n_rels_two);
end;
procedure drop_type (
rel_type in acs_rel_types.rel_type%TYPE,
cascade_p in char default 'f'
)
is
begin
-- XXX do cascade_p
delete from acs_rel_types
where rel_type = drop_type.rel_type;
acs_object_type.drop_type(drop_type.rel_type, drop_type.cascade_p);
end;
end acs_rel_type;
/
show errors
-----------------------------
-- PACKAGE BODY ACS_REL
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- fixes the delete proc to not delete from acs_rels (handled by acs_object.delete)
-----------------------------
create or replace package body acs_rel
as
function new (
rel_id in acs_rels.rel_id%TYPE default null,
rel_type in acs_rels.rel_type%TYPE default 'relationship',
object_id_one in acs_rels.object_id_one%TYPE,
object_id_two in acs_rels.object_id_two%TYPE,
context_id in acs_objects.context_id%TYPE default null,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return acs_rels.rel_id%TYPE
is
v_rel_id acs_rels.rel_id%TYPE;
begin
-- XXX This should check that object_id_one and object_id_two are
-- of the appropriate types.
v_rel_id := acs_object.new (
object_id => rel_id,
object_type => rel_type,
context_id => context_id,
creation_user => creation_user,
creation_ip => creation_ip
);
insert into acs_rels
(rel_id, rel_type, object_id_one, object_id_two)
values
(v_rel_id, new.rel_type, new.object_id_one, new.object_id_two);
return v_rel_id;
end;
procedure delete (
rel_id in acs_rels.rel_id%TYPE
)
is
begin
acs_object.delete(rel_id);
end;
end;
/
show errors
-----------------------------
-- PACKAGE BODY COMPOSITION_REL
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- fixes the delete proc to not delete from composition_rels (handled by acs_object.delete)
-----------------------------
create or replace package body composition_rel
as
function new (
rel_id in composition_rels.rel_id%TYPE default null,
rel_type in acs_rels.rel_type%TYPE default 'composition_rel',
object_id_one in acs_rels.object_id_one%TYPE,
object_id_two in acs_rels.object_id_two%TYPE,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return composition_rels.rel_id%TYPE
is
v_rel_id integer;
begin
v_rel_id := acs_rel.new (
rel_id => rel_id,
rel_type => rel_type,
object_id_one => object_id_one,
object_id_two => object_id_two,
context_id => object_id_one,
creation_user => creation_user,
creation_ip => creation_ip
);
insert into composition_rels
(rel_id)
values
(v_rel_id);
return v_rel_id;
end;
procedure delete (
rel_id in composition_rels.rel_id%TYPE
)
is
begin
acs_rel.delete(rel_id);
end;
function check_path_exists_p (
component_id in groups.group_id%TYPE,
container_id in groups.group_id%TYPE
) return char
is
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 check_path_exists_p(row.parent_id, container_id) = 't' then
return 't';
end if;
end loop;
return 'f';
end;
function check_index (
component_id in groups.group_id%TYPE,
container_id in groups.group_id%TYPE
) return char
is
result char(1);
n_rows integer;
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 = component_id) loop
if check_path_exists_p(dc.container_id,
check_index.container_id) = 't' then
select decode(count(*),0,0,1) 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';
acs_log.error('composition_rel.check_representation',
'Row missing from group_component_index for (' ||
'group_id = ' || container_id || ', ' ||
'component_id = ' || 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
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
from dual) loop
if (r1.container_id != check_index.container_id or
r2.component_id != check_index.component_id) and
check_index(r2.component_id, r1.container_id) = 'f' then
result := 'f';
end if;
end loop;
end loop;
return result;
end;
function check_representation (
rel_id in composition_rels.rel_id%TYPE
) return char
is
container_id groups.group_id%TYPE;
component_id groups.group_id%TYPE;
result char(1);
begin
result := 't';
if acs_object.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's check that the index has all the rows it should.
if check_index(component_id, container_id) = 'f' then
result := 'f';
end if;
-- Now let's 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 check_path_exists_p(row.component_id, row.group_id) = 'f' then
result := 'f';
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;
end composition_rel;
/
show errors
-----------------------------
-- PACKAGE BODY MEMBERSHIP_REL
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- fixes the delete proc to not delete from composition_rels (handled by acs_object.delete)
-----------------------------
create or replace package body membership_rel
as
function new (
rel_id in membership_rels.rel_id%TYPE default null,
rel_type in acs_rels.rel_type%TYPE default 'membership_rel',
object_id_one in acs_rels.object_id_one%TYPE,
object_id_two in acs_rels.object_id_two%TYPE,
member_state in membership_rels.member_state%TYPE default null,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return membership_rels.rel_id%TYPE
is
v_rel_id integer;
begin
v_rel_id := acs_rel.new (
rel_id => rel_id,
rel_type => rel_type,
object_id_one => object_id_one,
object_id_two => object_id_two,
context_id => object_id_one,
creation_user => creation_user,
creation_ip => creation_ip
);
insert into membership_rels
(rel_id, member_state)
values
(v_rel_id, new.member_state);
return v_rel_id;
end;
procedure ban (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'banned'
where rel_id = ban.rel_id;
end;
procedure approve (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'approved'
where rel_id = approve.rel_id;
end;
procedure reject (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'rejected'
where rel_id = reject.rel_id;
end;
procedure unapprove (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = ''
where rel_id = unapprove.rel_id;
end;
procedure deleted (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'deleted'
where rel_id = deleted.rel_id;
end;
procedure delete (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
acs_rel.delete(rel_id);
end;
function check_index (
group_id in groups.group_id%TYPE,
member_id in parties.party_id%TYPE,
container_id in groups.group_id%TYPE
) return char
is
result char(1);
n_rows integer;
begin
select count(*) into n_rows
from group_member_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';
acs_log.error('membership_rel.check_representation',
'Row missing from group_member_index: ' ||
'group_id = ' || group_id || ', ' ||
'member_id = ' || member_id || ', ' ||
'container_id = ' || 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 = group_id) loop
if check_index(row.container_id, member_id, container_id) = 'f' then
result := 'f';
end if;
end loop;
return result;
end;
function check_representation (
rel_id in membership_rels.rel_id%TYPE
) return char
is
group_id groups.group_id%TYPE;
member_id parties.party_id%TYPE;
result char(1);
begin
result := 't';
if acs_object.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 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';
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;
end membership_rel;
/
show errors
-----------------------------
-- PACKAGE BODY ACS_GROUP
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- changed delete proc to delete all relations of any type.
-----------------------------
create or replace package body acs_group
is
function new (
group_id in groups.group_id%TYPE default null,
object_type in acs_objects.object_type%TYPE
default 'group',
creation_date in acs_objects.creation_date%TYPE
default sysdate,
creation_user in acs_objects.creation_user%TYPE
default null,
creation_ip in acs_objects.creation_ip%TYPE default null,
email in parties.email%TYPE default null,
url in parties.url%TYPE default null,
group_name in groups.group_name%TYPE,
context_id in acs_objects.context_id%TYPE default null
)
return groups.group_id%TYPE
is
v_group_id groups.group_id%TYPE;
begin
v_group_id :=
party.new(group_id, object_type, creation_date, creation_user,
creation_ip, email, url, context_id);
insert into groups
(group_id, group_name)
values
(v_group_id, group_name);
-- setup the permissible relationship types for this group
insert into group_rels
(group_rel_id, group_id, rel_type)
select acs_object_id_seq.nextval, v_group_id, g.rel_type
from group_type_rels g
where g.group_type = new.object_type;
return v_group_id;
end new;
procedure delete (
group_id in groups.group_id%TYPE
)
is
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 = acs_group.delete.group_id
or r.object_id_two = acs_group.delete.group_id)) loop
execute immediate 'begin ' || row.package_name || '.delete(' || row.rel_id || '); end;';
end loop;
party.delete(group_id);
end delete;
function name (
group_id in groups.group_id%TYPE
)
return varchar2
is
group_name varchar(200);
begin
select group_name
into group_name
from groups
where group_id = name.group_id;
return group_name;
end name;
function member_p (
party_id in parties.party_id%TYPE
)
return char
is
begin
-- TO DO: implement this for real
return 't';
end member_p;
function check_representation (
group_id in groups.group_id%TYPE
) return char
is
result char(1);
begin
result := 't';
acs_log.notice('acs_group.check_representation',
'Running check_representation on group ' || group_id);
if acs_object.check_representation(group_id) = 'f' then
result := 'f';
end if;
for c 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(c.rel_id) = 'f' then
result := 'f';
end if;
end loop;
for m 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(m.rel_id) = 'f' then
result := 'f';
end if;
end loop;
acs_log.notice('acs_group.check_representation',
'Done running check_representation on group ' || group_id);
return result;
end;
end acs_group;
/
show errors
-----------------------------
-- CREATE NEW ATTRIBUTES
-- mbryzek@arsdigita.com
-- 1/5/2001
--
-- CHANGES
-- creates additional attributes for group, party, and acs_object
-----------------------------
declare
attr_id acs_attributes.attribute_id%TYPE;
begin
attr_id := acs_attribute.create_attribute (
object_type => 'group',
attribute_name => 'group_name',
datatype => 'string',
pretty_name => 'Group name',
pretty_plural => 'Group names',
min_n_values => 1,
max_n_values => 1
);
attr_id := acs_attribute.create_attribute (
object_type => 'party',
attribute_name => 'email',
datatype => 'string',
pretty_name => 'Email Address',
pretty_plural => 'Email Addresses',
min_n_values => 0,
max_n_values => 1
);
attr_id := acs_attribute.create_attribute (
object_type => 'party',
attribute_name => 'url',
datatype => 'string',
pretty_name => 'URL',
pretty_plural => 'URLs',
min_n_values => 0,
max_n_values => 1
);
attr_id := acs_attribute.create_attribute (
object_type => 'acs_object',
attribute_name => 'creation_user',
datatype => 'integer',
pretty_name => 'Creation user',
pretty_plural => 'Creation users',
min_n_values => 0,
max_n_values => 1
);
attr_id := acs_attribute.create_attribute (
object_type => 'acs_object',
attribute_name => 'context_id',
datatype => 'integer',
pretty_name => 'Context ID',
pretty_plural => 'Context IDs',
min_n_values => 0,
max_n_values => 1
);
end;
/
show errors;
commit;
-----------------------------
-- UPDATE VIEW acs_object_party_privilege_map
-- mbryzek@arsdigita.com
-- 1/8/2001
--
-- CHANGES
-- looks at rel_segment_member_map also
-----------------------------
create or replace view acs_object_party_privilege_map
as select ogpm.object_id, gmm.member_id as party_id, ogpm.privilege
from acs_object_grantee_priv_map ogpm, group_member_map gmm
where ogpm.grantee_id = gmm.group_id
union
select ogpm.object_id, rsmm.member_id as party_id, ogpm.privilege
from acs_object_grantee_priv_map ogpm, rel_segment_member_map rsmm
where ogpm.grantee_id = rsmm.segment_id
union
select object_id, grantee_id as party_id, privilege
from acs_object_grantee_priv_map
union
select object_id, u.user_id as party_id, privilege
from acs_object_grantee_priv_map m, users u
where m.grantee_id = -1
union
select object_id, 0 as party_id, privilege
from acs_object_grantee_priv_map
where grantee_id = -1;
---------------------------------
-- UPDATE PACKAGE ACS PERMISSION
---------------------------------
create or replace package body acs_permission
as
procedure grant_permission (
object_id acs_permissions.object_id%TYPE,
grantee_id acs_permissions.grantee_id%TYPE,
privilege acs_permissions.privilege%TYPE
)
as
begin
insert into acs_permissions
(object_id, grantee_id, privilege)
values
(object_id, grantee_id, privilege);
exception
when dup_val_on_index then
return;
end grant_permission;
procedure revoke_permission (
object_id acs_permissions.object_id%TYPE,
grantee_id acs_permissions.grantee_id%TYPE,
privilege acs_permissions.privilege%TYPE
)
as
begin
delete from acs_permissions
where object_id = revoke_permission.object_id
and grantee_id = revoke_permission.grantee_id
and privilege = revoke_permission.privilege;
end revoke_permission;
function permission_p (
object_id acs_objects.object_id%TYPE,
party_id parties.party_id%TYPE,
privilege acs_privileges.privilege%TYPE
) return char
as
exists_p char(1);
begin
-- We should question whether we really want to use the
-- acs_object_party_privilege_map since it unions the
-- difference queries. UNION ALL would be more efficient.
-- Also, we may want to test replacing the decode with
-- select count(*) from dual where exists ...
-- 1/12/2001, mbryzek
select decode(count(*),0,'f','t') into exists_p
from acs_object_party_privilege_map
where object_id = permission_p.object_id
and party_id = permission_p.party_id
and privilege = permission_p.privilege;
return exists_p;
end;
end acs_permission;
/
show errors
----------------------------------------
-- CREATE VALIDATION TRIGGER ON ACS_RELS
-- oumi@arsdigita.com
-- 1/11/2001
--
-- CHANGES
-- add a trigger: before insert or update
-- on acs_rels, validate that the relation
-- is between objects of the correct
-- object type.
-----------------------------
create or replace trigger acs_rels_in_tr
before insert or update on acs_rels
for each row
declare
dummy integer;
target_object_type_one acs_object_types.object_type%TYPE;
target_object_type_two acs_object_types.object_type%TYPE;
actual_object_type_one acs_object_types.object_type%TYPE;
actual_object_type_two acs_object_types.object_type%TYPE;
begin
-- validate that the relation being added is between objects of the
-- correct object_type. If no rows are returned by this query,
-- then the types are wrong and we should return an error.
select 1 into dummy
from acs_rel_types rt,
acs_objects o1,
acs_objects o2
where exists (select 1
from acs_object_types t
where t.object_type = o1.object_type
connect by prior t.object_type = t.supertype
start with t.object_type = rt.object_type_one)
and exists (select 1
from acs_object_types t
where t.object_type = o2.object_type
connect by prior t.object_type = t.supertype
start with t.object_type = rt.object_type_two)
and rt.rel_type = :new.rel_type
and o1.object_id = :new.object_id_one
and o2.object_id = :new.object_id_two;
exception
when NO_DATA_FOUND then
-- At least one of the object types must have been wrong.
-- Get all the object type information and print it out.
select rt.object_type_one, rt.object_type_two,
o1.object_type, o2.object_type
into target_object_type_one, target_object_type_two,
actual_object_type_one, actual_object_type_two
from acs_rel_types rt, acs_objects o1, acs_objects o2
where rt.rel_type = :new.rel_type
and o1.object_id = :new.object_id_one
and o2.object_id = :new.object_id_two;
raise_application_error (-20001,
:new.rel_type || ' violation: Invalid object types. ' ||
'Object ' || :new.object_id_one ||
' (' || actual_object_type_one || ') ' ||
'must be of type ' || target_object_type_one || '. ' ||
'Object ' || :new.object_id_two ||
' (' || actual_object_type_two || ') ' ||
'must be of type ' || target_object_type_two || '.');
end;
/
show errors
------------------------------------------------------------
-- RECREATE GROUP TRIGGERS TO ENFORE RELATIONAL CONSTRAINTS
-- oumi@arsdigita.com
-- 1/11/2001
--
-- CHANGES
-- Modify insert and delete triggers to first check for
-- violations of relational constraint
-- Replace triggers that insert into group_member_index and
-- group_component_index, so that they insert into group_element_index.--
-- Replace triggers that delete from group_member_index and
-- group_component_index
--
-- Corresponding ACS File: ../groups-body-create.sql
------------------------------------------------------------
--
-- packages/acs-kernel/sql/groups-body-create.sql
--
-- @author rhs@mit.edu
-- @creation-date 2000-08-22
-- @cvs-id $Id: upgrade-4.0.1-4.1b.sql,v 1.5 2024/09/11 06:15:47 gustafn Exp $
--
--------------
-- TRIGGERS --
--------------
create or replace trigger membership_rels_in_tr
after insert on membership_rels
for each row
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 varchar2(4000);
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_application_error(-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 the group_member_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');
-- For all groups of which I am a component, insert a
-- row in the group_member_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');
end loop;
end;
/
show errors
create or replace trigger composition_rels_in_tr
after insert on composition_rels
for each row
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 varchar2(4000);
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_application_error(-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');
-- Make my 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,
rel_type, ancestor_rel_type
from group_element_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.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 rows for my 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,
rel_type, ancestor_rel_type
from group_element_map m
where group_id = v_object_id_two
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;
end;
/
show errors
create or replace trigger membership_rels_del_tr
before delete on membership_rels
for each row
declare
v_error varchar2(4000);
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_application_error(-20000,v_error);
end if;
delete from group_element_index
where rel_id = :old.rel_id;
end;
/
show errors;
--
-- TO DO: See if this can be optimized now that the member and component
-- mapping tables have been combined
--
create or replace trigger composition_rels_del_tr
before delete on composition_rels
for each row
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 varchar2(4000);
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_application_error(-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
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
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;
end;
/
show errors
--------------------
-- PACKAGE BODIES --
--------------------
create or replace package body composition_rel
as
function new (
rel_id in composition_rels.rel_id%TYPE default null,
rel_type in acs_rels.rel_type%TYPE default 'composition_rel',
object_id_one in acs_rels.object_id_one%TYPE,
object_id_two in acs_rels.object_id_two%TYPE,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return composition_rels.rel_id%TYPE
is
v_rel_id integer;
begin
v_rel_id := acs_rel.new (
rel_id => rel_id,
rel_type => rel_type,
object_id_one => object_id_one,
object_id_two => object_id_two,
context_id => object_id_one,
creation_user => creation_user,
creation_ip => creation_ip
);
insert into composition_rels
(rel_id)
values
(v_rel_id);
return v_rel_id;
end;
procedure delete (
rel_id in composition_rels.rel_id%TYPE
)
is
begin
acs_rel.delete(rel_id);
end;
function check_path_exists_p (
component_id in groups.group_id%TYPE,
container_id in groups.group_id%TYPE
) return char
is
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 check_path_exists_p(row.parent_id, container_id) = 't' then
return 't';
end if;
end loop;
return 'f';
end;
function check_index (
component_id in groups.group_id%TYPE,
container_id in groups.group_id%TYPE
) return char
is
result char(1);
n_rows integer;
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 = component_id) loop
if check_path_exists_p(dc.container_id,
check_index.container_id) = 't' then
select decode(count(*),0,0,1) 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';
acs_log.error('composition_rel.check_representation',
'Row missing from group_component_index for (' ||
'group_id = ' || container_id || ', ' ||
'component_id = ' || 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
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
from dual) loop
if (r1.container_id != check_index.container_id or
r2.component_id != check_index.component_id) and
check_index(r2.component_id, r1.container_id) = 'f' then
result := 'f';
end if;
end loop;
end loop;
return result;
end;
function check_representation (
rel_id in composition_rels.rel_id%TYPE
) return char
is
container_id groups.group_id%TYPE;
component_id groups.group_id%TYPE;
result char(1);
begin
result := 't';
if acs_object.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's check that the index has all the rows it should.
if check_index(component_id, container_id) = 'f' then
result := 'f';
end if;
-- Now let's 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 check_path_exists_p(row.component_id, row.group_id) = 'f' then
result := 'f';
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;
end composition_rel;
/
show errors
create or replace package body membership_rel
as
function new (
rel_id in membership_rels.rel_id%TYPE default null,
rel_type in acs_rels.rel_type%TYPE default 'membership_rel',
object_id_one in acs_rels.object_id_one%TYPE,
object_id_two in acs_rels.object_id_two%TYPE,
member_state in membership_rels.member_state%TYPE default null,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return membership_rels.rel_id%TYPE
is
v_rel_id integer;
begin
v_rel_id := acs_rel.new (
rel_id => rel_id,
rel_type => rel_type,
object_id_one => object_id_one,
object_id_two => object_id_two,
context_id => object_id_one,
creation_user => creation_user,
creation_ip => creation_ip
);
insert into membership_rels
(rel_id, member_state)
values
(v_rel_id, new.member_state);
return v_rel_id;
end;
procedure ban (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'banned'
where rel_id = ban.rel_id;
end;
procedure approve (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'approved'
where rel_id = approve.rel_id;
end;
procedure reject (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'rejected'
where rel_id = reject.rel_id;
end;
procedure unapprove (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = ''
where rel_id = unapprove.rel_id;
end;
procedure deleted (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
update membership_rels
set member_state = 'deleted'
where rel_id = deleted.rel_id;
end;
procedure delete (
rel_id in membership_rels.rel_id%TYPE
)
is
begin
acs_rel.delete(rel_id);
end;
function check_index (
group_id in groups.group_id%TYPE,
member_id in parties.party_id%TYPE,
container_id in groups.group_id%TYPE
) return char
is
result char(1);
n_rows integer;
begin
select count(*) into n_rows
from group_member_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';
acs_log.error('membership_rel.check_representation',
'Row missing from group_member_index: ' ||
'group_id = ' || group_id || ', ' ||
'member_id = ' || member_id || ', ' ||
'container_id = ' || 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 = group_id) loop
if check_index(row.container_id, member_id, container_id) = 'f' then
result := 'f';
end if;
end loop;
return result;
end;
function check_representation (
rel_id in membership_rels.rel_id%TYPE
) return char
is
group_id groups.group_id%TYPE;
member_id parties.party_id%TYPE;
result char(1);
begin
result := 't';
if acs_object.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 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';
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;
end membership_rel;
/
show errors
create or replace package body acs_group
is
function new (
group_id in groups.group_id%TYPE default null,
object_type in acs_objects.object_type%TYPE
default 'group',
creation_date in acs_objects.creation_date%TYPE
default sysdate,
creation_user in acs_objects.creation_user%TYPE
default null,
creation_ip in acs_objects.creation_ip%TYPE default null,
email in parties.email%TYPE default null,
url in parties.url%TYPE default null,
group_name in groups.group_name%TYPE,
context_id in acs_objects.context_id%TYPE default null
)
return groups.group_id%TYPE
is
v_group_id groups.group_id%TYPE;
begin
v_group_id :=
party.new(group_id, object_type, creation_date, creation_user,
creation_ip, email, url, context_id);
insert into groups
(group_id, group_name)
values
(v_group_id, group_name);
-- setup the permissible relationship types for this group
insert into group_rels
(group_rel_id, group_id, rel_type)
select acs_object_id_seq.nextval, v_group_id, g.rel_type
from group_type_rels g
where g.group_type = new.object_type;
return v_group_id;
end new;
procedure delete (
group_id in groups.group_id%TYPE
)
is
begin
-- Delete all segments defined for this group
for row in (select segment_id
from rel_segments
where group_id = acs_group.delete.group_id) loop
rel_segment.delete(row.segment_id);
end loop;
-- 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 = acs_group.delete.group_id
or r.object_id_two = acs_group.delete.group_id)) loop
execute immediate 'begin ' || row.package_name || '.delete(' || row.rel_id || '); end;';
end loop;
party.delete(group_id);
end delete;
function name (
group_id in groups.group_id%TYPE
)
return varchar2
is
group_name varchar(200);
begin
select group_name
into group_name
from groups
where group_id = name.group_id;
return group_name;
end name;
function member_p (
party_id in parties.party_id%TYPE
)
return char
is
begin
-- TO DO: implement this for real
return 't';
end member_p;
function check_representation (
group_id in groups.group_id%TYPE
) return char
is
result char(1);
begin
result := 't';
acs_log.notice('acs_group.check_representation',
'Running check_representation on group ' || group_id);
if acs_object.check_representation(group_id) = 'f' then
result := 'f';
end if;
for c 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(c.rel_id) = 'f' then
result := 'f';
end if;
end loop;
for m 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(m.rel_id) = 'f' then
result := 'f';
end if;
end loop;
acs_log.notice('acs_group.check_representation',
'Done running check_representation on group ' || group_id);
return result;
end;
end acs_group;
/
show errors
------------------------------------------------------------
-- CREATE THE rel_segment package body
-- oumi@arsdigita.com
-- 1/11/2001
--
-- Corresponding ACS File: ../rel-segments-body-create.sql
------------------------------------------------------------
--
-- packages/acs-kernel/sql/rel-segments-create.sql
--
-- @author Oumi Mehrotra oumi@arsdigita.com
-- @creation-date 2000-11-22
-- @cvs-id $Id: upgrade-4.0.1-4.1b.sql,v 1.5 2024/09/11 06:15:47 gustafn Exp $
-- Copyright (C) 1999-2000 ArsDigita Corporation
-- This is free software distributed under the terms of the GNU Public
-- License. Full text of the license is available from the GNU Project:
-- http://www.fsf.org/copyleft/gpl.html
------------------
-- PACKAGE BODY --
------------------
create or replace package body rel_segment
is
function new (
segment_id in rel_segments.segment_id%TYPE default null,
object_type in acs_objects.object_type%TYPE
default 'rel_segment',
creation_date in acs_objects.creation_date%TYPE
default sysdate,
creation_user in acs_objects.creation_user%TYPE
default null,
creation_ip in acs_objects.creation_ip%TYPE default null,
email in parties.email%TYPE default null,
url in parties.url%TYPE default null,
segment_name in rel_segments.segment_name%TYPE,
group_id in rel_segments.group_id%TYPE,
rel_type in rel_segments.rel_type%TYPE,
context_id in acs_objects.context_id%TYPE default null
) return rel_segments.segment_id%TYPE
is
v_segment_id rel_segments.segment_id%TYPE;
begin
v_segment_id :=
party.new(segment_id, object_type, creation_date, creation_user,
creation_ip, email, url, context_id);
insert into rel_segments
(segment_id, segment_name, group_id, rel_type)
values
(v_segment_id, new.segment_name, new.group_id, new.rel_type);
return v_segment_id;
end new;
procedure delete (
segment_id in rel_segments.segment_id%TYPE
)
is
begin
-- remove all constraints on this segment
for row in (select constraint_id
from rel_constraints
where rel_segment = rel_segment.delete.segment_id) loop
rel_constraint.delete(row.constraint_id);
end loop;
party.delete(segment_id);
end delete;
-- EXPERIMENTAL / UNSTABLE -- use at your own risk
--
function get (
group_id in rel_segments.group_id%TYPE,
rel_type in rel_segments.rel_type%TYPE
) return rel_segments.segment_id%TYPE
is
v_segment_id rel_segments.segment_id%TYPE;
begin
select min(segment_id) into v_segment_id
from rel_segments
where group_id = get.group_id
and rel_type = get.rel_type;
return v_segment_id;
end get;
-- EXPERIMENTAL / UNSTABLE -- use at your own risk
--
-- This function simplifies the use of segments a little by letting
-- you not have to worry about creating and initializing segments.
-- If the segment you're interested in exists, this function
-- returns its segment_id.
-- If the segment you're interested in doesn't exist, this function
-- does a pretty minimal amount of initialization for the segment
-- and returns a new segment_id.
function get_or_new (
group_id in rel_segments.group_id%TYPE,
rel_type in rel_segments.rel_type%TYPE,
segment_name in rel_segments.segment_name%TYPE
default null
) return rel_segments.segment_id%TYPE
is
v_segment_id rel_segments.segment_id%TYPE;
v_segment_name rel_segments.segment_name%TYPE;
begin
v_segment_id := get(group_id, rel_type);
if v_segment_id is null then
if v_segment_name is not null then
v_segment_name := segment_name;
else
select groups.group_name || ' - ' || acs_object_types.pretty_name ||
' segment'
into v_segment_name
from groups, acs_object_types
where groups.group_id = get_or_new.group_id
and acs_object_types.object_type = get_or_new.rel_type;
end if;
v_segment_id := rel_segment.new (
object_type => 'rel_segment',
creation_user => null,
creation_ip => null,
email => null,
url => null,
segment_name => v_segment_name,
group_id => get_or_new.group_id,
rel_type => get_or_new.rel_type,
context_id => get_or_new.group_id
);
end if;
return v_segment_id;
end get_or_new;
function name (
segment_id in rel_segments.segment_id%TYPE
)
return rel_segments.segment_name%TYPE
is
segment_name varchar(200);
begin
select segment_name
into segment_name
from rel_segments
where segment_id = name.segment_id;
return segment_name;
end name;
end rel_segment;
/
show errors
------------------------------------------------------------
-- CREATE THE rel_constraint package body
-- oumi@arsdigita.com
-- 1/11/2001
--
-- Corresponding ACS File: ../rel-constraints-body-create.sql
------------------------------------------------------------
--
-- /packages/acs-kernel/sql/rel-constraints-create.sql
--
-- Add support for relational constraints based on relational segmentation.
--
-- @author Oumi Mehrotra (oumi@arsdigita.com)
-- @creation-date 2000-11-22
-- @cvs-id $Id: upgrade-4.0.1-4.1b.sql,v 1.5 2024/09/11 06:15:47 gustafn Exp $
-- Copyright (C) 1999-2000 ArsDigita Corporation
-- This is free software distributed under the terms of the GNU Public
-- License. Full text of the license is available from the GNU Project:
-- http://www.fsf.org/copyleft/gpl.html
create or replace package body rel_constraint
as
function new (
constraint_id in rel_constraints.constraint_id%TYPE default null,
constraint_type in acs_objects.object_type%TYPE default 'rel_constraint',
constraint_name in rel_constraints.constraint_name%TYPE,
rel_segment in rel_constraints.rel_segment%TYPE,
rel_side in rel_constraints.rel_side%TYPE default 'two',
required_rel_segment in rel_constraints.required_rel_segment%TYPE,
context_id in acs_objects.context_id%TYPE default null,
creation_user in acs_objects.creation_user%TYPE default null,
creation_ip in acs_objects.creation_ip%TYPE default null
) return rel_constraints.constraint_id%TYPE
is
v_constraint_id rel_constraints.constraint_id%TYPE;
begin
v_constraint_id := acs_object.new (
object_id => constraint_id,
object_type => constraint_type,
context_id => context_id,
creation_user => creation_user,
creation_ip => creation_ip
);
insert into rel_constraints
(constraint_id, constraint_name,
rel_segment, rel_side, required_rel_segment)
values
(v_constraint_id, new.constraint_name,
new.rel_segment, new.rel_side, new.required_rel_segment);
return v_constraint_id;
end;
procedure delete (
constraint_id in rel_constraints.constraint_id%TYPE
)
is
begin
acs_object.delete(constraint_id);
end;
function get_constraint_id (
rel_segment in rel_constraints.rel_segment%TYPE,
rel_side in rel_constraints.rel_side%TYPE default 'two',
required_rel_segment in rel_constraints.required_rel_segment%TYPE
) return rel_constraints.constraint_id%TYPE
is
v_constraint_id rel_constraints.constraint_id%TYPE;
begin
select constraint_id into v_constraint_id
from rel_constraints
where rel_segment = get_constraint_id.rel_segment
and rel_side = get_constraint_id.rel_side
and required_rel_segment = get_constraint_id.required_rel_segment;
return v_constraint_id;
end;
function violation (
rel_id in acs_rels.rel_id%TYPE
) return varchar
is
v_error varchar(4000);
begin
v_error := null;
for constraint_violated in
(select /*+ FIRST_ROWS*/ constraint_id, constraint_name
from rel_constraints_violated_one
where rel_id = rel_constraint.violation.rel_id
and rownum = 1) loop
v_error := v_error || 'Relational Constraint Violation: ' ||
constraint_violated.constraint_name ||
' (constraint_id=' ||
constraint_violated.constraint_id || '). ';
return v_error;
end loop;
for constraint_violated in
(select /*+ FIRST_ROWS*/ constraint_id, constraint_name
from rel_constraints_violated_two
where rel_id = rel_constraint.violation.rel_id
and rownum = 1) loop
v_error := v_error || 'Relational Constraint Violation: ' ||
constraint_violated.constraint_name ||
' (constraint_id=' ||
constraint_violated.constraint_id || '). ';
return v_error;
end loop;
return v_error;
end violation;
function violation_if_removed (
rel_id in acs_rels.rel_id%TYPE
) return varchar
is
v_count integer;
v_error varchar(4000);
begin
v_error := null;
select count(*) into v_count
from dual
where exists (select 1 from rc_violations_by_removing_rel r where r.rel_id = violation_if_removed.rel_id);
if v_count > 0 then
-- some other relation depends on this one. Let's build up a string
-- of the constraints we are violating
for constraint_violated in (select constraint_id, constraint_name
from rc_violations_by_removing_rel r
where r.rel_id = violation_if_removed.rel_id) loop
v_error := v_error || 'Relational Constraint Violation: ' ||
constraint_violated.constraint_name ||
' (constraint_id=' ||
constraint_violated.constraint_id || '). ';
end loop;
end if;
return v_error;
end;
end;
/
show errors