Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-install.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-kernel-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-kernel-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-logs-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-logs-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-metadata-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-metadata-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-objects-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-objects-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-permissions-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-permissions-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-relationships-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/acs-relationships-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/apm-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/apm-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/community-core-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/community-core-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/groups-body-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/groups-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/groups-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/journal-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/journal-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/rel-constraints-body-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/rel-constraints-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/rel-constraints-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/rel-segments-body-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/rel-segments-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/rel-segments-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/security-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/security-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/site-nodes-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/site-nodes-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/utilities-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/utilities-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-kernel/sql/oracle/acs-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,274 @@ +-- +-- packages/acs-kernel/sql/acs-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id acs-create.sql,v 1.1.2.9 2000/08/24 07:09:18 rhs Exp +-- + +create table acs_magic_objects ( + name varchar2(100) + constraint acs_magic_objects_pk primary key, + object_id not null constraint acs_magic_objects_object_id_fk + references acs_objects(object_id) +); + +create index acs_mo_object_id_idx on acs_magic_objects (object_id); + +comment on table acs_magic_objects is ' + This table allows us to provide semantic names for certain special + objects like the site-wide organization, and the all users party. +'; + +create or replace package acs +as + + function add_user ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't', + member_state in membership_rels.member_state%TYPE default 'approved' + ) + return users.user_id%TYPE; + + procedure remove_user ( + user_id in users.user_id%TYPE + ); + + function magic_object_id ( + name in acs_magic_objects.name%TYPE + ) return acs_objects.object_id%TYPE; + +end acs; +/ +show errors + +create or replace package body acs +as + + function add_user ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't', + member_state in membership_rels.member_state%TYPE default 'approved' + ) return users.user_id%TYPE + is + v_user_id users.user_id%TYPE; + v_rel_id membership_rels.rel_id%TYPE; + begin + v_user_id := acs_user.new (user_id, object_type, creation_date, + creation_user, creation_ip, email, + url, first_names, last_name, password, + salt, password_question, password_answer, + screen_name, email_verified_p); + + v_rel_id := membership_rel.new ( + object_id_two => v_user_id, + object_id_one => acs.magic_object_id('registered_users'), + member_state => member_state); + + acs_permission.grant_permission ( + object_id => v_user_id, + grantee_id => v_user_id, + privilege => 'read' + ); + + acs_permission.grant_permission ( + object_id => v_user_id, + grantee_id => v_user_id, + privilege => 'write' + ); + + return v_user_id; + end; + + procedure remove_user ( + user_id in users.user_id%TYPE + ) + is + begin + delete from users + where user_id = remove_user.user_id; + end; + + function magic_object_id ( + name in acs_magic_objects.name%TYPE + ) return acs_objects.object_id%TYPE + is + object_id acs_objects.object_id%TYPE; + begin + select object_id + into magic_object_id.object_id + from acs_magic_objects + where name = magic_object_id.name; + + return object_id; + end magic_object_id; + +end acs; +/ +show errors + +-- ****************************************************************** +-- * Community Core API +-- ****************************************************************** + +create or replace view registered_users +as + select p.email, p.url, pe.first_names, pe.last_name, u.*, mr.member_state + from parties p, persons pe, users u, group_member_map m, membership_rels mr + where party_id = person_id + and person_id = user_id + and u.user_id = m.member_id + and m.rel_id = mr.rel_id + and m.group_id = acs.magic_object_id('registered_users') + and mr.member_state = 'approved' + and u.email_verified_p = 't'; + +create or replace view cc_users +as +select o.*, pa.*, pe.*, u.*, mr.member_state, mr.rel_id +from acs_objects o, parties pa, persons pe, users u, group_member_map m, membership_rels mr +where o.object_id = pa.party_id +and pa.party_id = pe.person_id +and pe.person_id = u.user_id +and u.user_id = m.member_id +and m.group_id = acs.magic_object_id('registered_users') +and m.rel_id = mr.rel_id +and m.container_id = m.group_id; + +----------------------------------- +-- Community Core Initialization -- +----------------------------------- + +-- The very first thing we must do is create the security_context_root +-- object. + +declare + root_id integer; +begin + root_id := acs_object.new ( + object_id => 0 + ); + + insert into acs_magic_objects + (name, object_id) + values + ('security_context_root', 0); +end; +/ +show errors + +begin + -------------------------------------------------------------- + -- Some privilege that will be fundamental to all objects. -- + -------------------------------------------------------------- + + acs_privilege.create_privilege('read'); + acs_privilege.create_privilege('write'); + acs_privilege.create_privilege('create'); + acs_privilege.create_privilege('delete'); + acs_privilege.create_privilege('admin'); + + --------------------------------------------------------- + -- Administrators can read, write, create, and delete. -- + --------------------------------------------------------- + + acs_privilege.add_child('admin', 'read'); + acs_privilege.add_child('admin', 'write'); + acs_privilege.add_child('admin', 'create'); + acs_privilege.add_child('admin', 'delete'); + + commit; +end; +/ +show errors + +begin + insert into acs_objects + (object_id, object_type) + values + (-1, 'party'); + + insert into parties + (party_id) + values + (-1); + + insert into acs_magic_objects + (name, object_id) + values + ('the_public', -1); + + commit; +end; +/ +show errors + +-- Insert the site-wide group. The members of this +-- group correspond to all registered users. +declare + group_id integer; +begin + group_id := acs_group.new ( + group_id => -2, + group_name => 'Registered Users' + ); + + insert into acs_magic_objects + (name, object_id) + values + ('registered_users', -2); + + commit; +end; +/ +show errors + +-- Create the default context. +declare + object_id integer; +begin + object_id := acs_object.new ( + object_id => -3 + ); + + insert into acs_magic_objects + (name, object_id) + values + ('default_context', object_id); + + commit; +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/acs-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,12 @@ +-- +-- packages/acs-kernel/sql/acs-drop.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id $Id: acs-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +drop view cc_users; +drop view registered_users; +drop package acs; +drop table acs_magic_objects; Index: openacs-4/packages/acs-kernel/sql/oracle/acs-install.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-install.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-install.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,119 @@ +-- +-- /packages/acs-kernel/sql/acs-install.sql +-- +-- Complete the install of the system by setting up some default URL mappings. +-- +-- @author Bryan Quinn (bquinn@arsdigita.com +-- @creation-date 2000/10/01 +-- @cvs-id $Id: acs-install.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +declare + kernel_id apm_packages.package_id%TYPE; + node_id site_nodes.node_id%TYPE; + main_site_id site_nodes.node_id%TYPE; + admin_id apm_packages.package_id%TYPE; + docs_id apm_packages.package_id%TYPE; + api_doc_id apm_packages.package_id%TYPE; + schema_user varchar2(100); + jobnum integer; +begin + kernel_id := apm_service.new( + package_key => 'acs-kernel', + instance_name => 'ACS Kernel', + context_id => acs.magic_object_id('default_context') + ); + commit; + + apm_package.enable(kernel_id); + + main_site_id := apm_service.new( + package_key => 'acs-subsite', + instance_name => 'Main Site', + context_id => acs.magic_object_id('default_context') + ); + apm_package.enable(main_site_id); + + node_id := site_node.new ( + name => '', + directory_p => 't', + pattern_p => 't', + object_id => main_site_id + ); + + acs_permission.grant_permission ( + object_id => main_site_id, + grantee_id => acs.magic_object_id('the_public'), + privilege => 'read' + ); + + admin_id := apm_service.new ( + instance_name => 'ACS Administration', + package_key => 'acs-admin' + ); + apm_package.enable(admin_id); + + node_id := site_node.new ( + parent_id => site_node.node_id('/'), + name => 'acs-admin', + directory_p => 't', + pattern_p => 't', + object_id => admin_id + ); + + docs_id := apm_service.new ( + instance_name => 'ACS Core Documents', + package_key => 'acs-core-docs', + context_id => main_site_id + ); + + docs_id := site_node.new ( + parent_id => site_node.node_id('/'), + name => 'doc', + directory_p => 't', + pattern_p => 't', + object_id => docs_id + ); + + api_doc_id := apm_service.new ( + instance_name => 'ACS API Browser', + package_key => 'acs-api-browser', + context_id => main_site_id + ); + + apm_package.enable(api_doc_id); + + -- Set default permissions for ACS API Browser so + -- that only users logged in can view it + + update acs_objects + set security_inherit_p = 'f' + where object_id = api_doc_id; + + acs_permission.grant_permission ( + object_id => api_doc_id, + grantee_id => acs.magic_object_id ('registered_users'), + privilege => 'read' + ); + + api_doc_id := site_node.new ( + parent_id => site_node.node_id('/'), + name => 'api-doc', + directory_p => 't', + pattern_p => 't', + object_id => api_doc_id + ); + + select user into schema_user from dual; + + dbms_job.submit ( + jobnum, + 'dbms_stats.gather_schema_stats (''' || schema_user || ''', 10, cascade => true);', + trunc(sysdate+1) + 4/24, + 'trunc(sysdate+1) + 4/24' + ); + + commit; +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/acs-kernel-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-kernel-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-kernel-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,32 @@ +-- +-- /packages/acs-kernel/sql/acs-kernel-create.sql +-- +-- Load the entire ACS Core package's data model +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @creation-date 2000/07/29 +-- @cvs-id $Id: acs-kernel-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +set feedback off + +@@ acs-logs-create +@@ acs-metadata-create +@@ acs-objects-create +@@ acs-relationships-create +@@ utilities-create +@@ community-core-create +@@ groups-create +@@ rel-segments-create +@@ rel-constraints-create +@@ groups-body-create +@@ rel-segments-body-create +@@ rel-constraints-body-create +@@ acs-permissions-create +@@ security-create +@@ journal-create +@@ site-nodes-create +@@ apm-create +@@ acs-create + +set feedback on Index: openacs-4/packages/acs-kernel/sql/oracle/acs-kernel-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-kernel-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-kernel-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,25 @@ +-- +-- /packages/acs-kernel/sql/acs-kernel-drop.sql +-- +-- Purge the entire ACS Core package's data model +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @creation-date 2000/07/29 +-- @cvs-id $Id: acs-kernel-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +@@ acs-drop +@@ journal-drop +@@ utilities-drop +@@ security-drop +@@ acs-permissions-drop +@@ rel-constraints-drop +@@ rel-segments-drop +@@ groups-drop +@@ site-nodes-drop.sql +@@ community-core-drop +@@ acs-relationships-drop +@@ acs-objects-drop +@@ acs-metadata-drop +@@ apm-drop +@@ acs-logs-drop Index: openacs-4/packages/acs-kernel/sql/oracle/acs-logs-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-logs-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-logs-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,104 @@ +-- +-- packages/acs-kernel/sql/acs-logs-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-10-02 +-- @cvs-id $Id: acs-logs-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +create sequence acs_log_id_seq; + +create table acs_logs ( + log_id integer + constraint acs_logs_pk + primary key, + log_date date default sysdate not null, + log_level varchar2(20) + constraint acs_logs_log_level_ck + check (log_level in ('notice', 'warn', 'error', + 'debug')), + log_key varchar2(100) not null, + message varchar2(4000) not null +); + +create or replace package acs_log +as + + procedure notice ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ); + + procedure warn ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ); + + procedure error ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ); + + procedure debug ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ); + +end; +/ +show errors + +create or replace package body acs_log +as + + procedure notice ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ) + is + begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, 'notice', notice.log_key, notice.message); + end; + + procedure warn ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ) + is + begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, 'warn', warn.log_key, warn.message); + end; + + procedure error ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ) + is + begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, 'error', error.log_key, error.message); + end; + + procedure debug ( + log_key in acs_logs.log_key%TYPE, + message in acs_logs.message%TYPE + ) + is + begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, 'debug', debug.log_key, debug.message); + end; + +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/acs-logs-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-logs-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-logs-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,3 @@ +drop package acs_log; +drop table acs_logs; +drop sequence acs_log_id_seq; Index: openacs-4/packages/acs-kernel/sql/oracle/acs-metadata-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-metadata-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-metadata-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,689 @@ +-- +-- acs-kernel/sql/acs-metadata-create.sql +-- +-- A generic metadata system that allows table inheritence. This is +-- based in many ways on Problem Set 4 by Philip Greenspun +-- (philg@mit.edu), and the user-groups data model by Tracy Adams +-- (teadams@mit.edu). +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @author Rafael Schloming (rhs@mit.edu) +-- @author Jon Salz (jsalz@mit.edu) +-- +-- @creation-date 2000-05-18 +-- +-- @cvs-id $Id: acs-metadata-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +-- ****************************************************************** +-- * KNOWLEDGE LEVEL +-- ****************************************************************** + +------------------ +-- OBJECT TYPES -- +------------------ + +create table acs_object_types ( + object_type varchar2(100) not null + constraint acs_object_types_pk primary key, + supertype constraint acs_object_types_supertype_fk + references acs_object_types (object_type), + abstract_p char(1) default 'f' not null + constraint acs_obj_types_abstract_p_ck + check (abstract_p in ('t', 'f')), + pretty_name varchar2(100) not null + constraint acs_obj_types_pretty_name_un + unique, + pretty_plural varchar2(100) not null + constraint acs_obj_types_pretty_plural_un + unique, + table_name varchar2(30) not null + constraint acs_object_types_tbl_name_un unique, + id_column varchar2(30) not null, + package_name varchar2(30) not null + constraint acs_object_types_pkg_name_un unique, + name_method varchar2(30), + type_extension_table varchar2(30), + dynamic_p char(1) default 'f' + constraint acs_obj_types_dynamic_p_ck + check (dynamic_p in ('t', 'f')) +); + +create bitmap index acs_obj_types_supertype_idx on acs_object_types (supertype); + +comment on table acs_object_types is ' + Each row in the acs_object_types table represents a distinct class + of objects. For each instance of any acs_object_type, there is a + corresponding row in the acs_objects table. Essentially, + acs_objects.object_id supersedes the on_which_table/on_what_id pair + that ACS 3.x used as the system-wide identifier for heterogeneous + objects. The value of having a system-wide identifier for + heterogeneous objects is that it helps us provide general solutions + for common problems like access control, workflow, categorppization, + and search. (Note that this framework is not overly restrictive, + because it doesn''t force every type of object to be represented in + the acs_object_types table.) Each acs_object_type has: + * Attributes (stored in the acs_attributes table) + Examples: + - the "user" object_type has "email" and "password" attributes + - the "content_item" object_type has "title" and "body" attributes + * Relationship types (stored in the acs_rel_types table) + Examples: + - "a team has one team leader who is a user" (in other words, + instances of the "team" object_type must have one "team leader" + relationship to an instance of the "user" object_type) + - "a content item may have zero or authors who are people or + organizations, i.e., parties" (in other words, instances of + the "content_item" object_type may have zero or more "author" + relationships to instances of the "party" object_type) + Possible extensions include automatic versioning, logical deletion, + and auditing. +'; + +comment on column acs_object_types.supertype is ' + The object_type of which this object_type is a specialization (if + any). For example, the supertype of the "user" object_type is + "person". An object_type inherits the attributes and relationship + rules of its supertype, though it can add constraints to the + attributes and/or it can override the relationship rules. For + instance, the "person" object_type has an optional "email" attribute, + while its "user" subtype makes "email" mandatory. +'; + +comment on column acs_object_types.abstract_p is ' + ... + If the object_type is not abstract, then all of its attributes must + have a non-null storage specified. +'; + +comment on column acs_object_types.table_name is ' + The name of the type-specific table in which the values of attributes + specific to this object_type are stored, if any. +'; + +comment on column acs_object_types.id_column is ' + The name of the primary key column in the table identified by + table_name. +'; + +comment on column acs_object_types.name_method is ' + The name of a stored function that takes an object_id as an argument + and returns a varchar2: the corresponding object name. This column is + required to implement the polymorphic behavior of the acs.object_name() + function. +'; + +comment on column acs_object_types.type_extension_table is ' + Object types (and their subtypes) that require more type-specific + data than the fields already existing in acs_object_types may name + a table in which that data is stored. The table should be keyed + by the associated object_type. For example, a row in the user_group_types + table stores a default approval policy for every user group of that type. + In this example, the user_group_types table has a primary key named + group_type that references acs_object_types. If a subtype of user_groups + for example, lab_courses, has its own type-specific data, it could be + maintained in a table called lab_course_types, with a primary key named + lab_course_type that references user_group_types. This provides the same + functionality as static class fields in an object-oriented programming language. +'; + + +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. +'; + +create or replace view acs_object_type_supertype_map +as select ot.object_type, ota.object_type as ancestor_type + from acs_object_types ot, acs_object_types ota + where ota.object_type in (select object_type + from acs_object_types + start with object_type = ot.supertype + connect by object_type = prior supertype); + + +create table acs_object_type_tables ( + object_type not null constraint acs_obj_type_tbls_obj_type_fk + references acs_object_types (object_type), + table_name varchar2(30) not null, + id_column varchar2(30), + constraint acs_object_type_tables_pk + primary key (object_type, table_name) +); + +create bitmap index acs_objtype_tbls_objtype_idx on acs_object_type_tables (object_type); + +comment on table acs_object_type_tables is ' + This table is used for objects that want to vertically partition + their data storage, for example user_demographics stores a set of + optional columns that belong to a user object. +'; + +comment on column acs_object_type_tables.id_column is ' + If this is null then the id column is assumed to have the same name + as the primary table. +'; + +------------------------------------ +-- DATATYPES AND ATTRIBUTES -- +------------------------------------ + +create table acs_datatypes ( + datatype varchar2(50) not null + constraint acs_datatypes_pk primary key, + max_n_values integer default 1 + constraint acs_datatypes_max_n_ck + check (max_n_values > 0) +); + +comment on table acs_datatypes is ' + Defines the set of available datatypes for acs_attributes. These + datatypes are abstract, not implementation-specific, i.e., they + are not Oracle datatypes. The set of pre-defined datatypes is + inspired by XForms (http://www.w3.org/TR/xforms-datamodel/). +'; + +comment on column acs_datatypes.max_n_values is ' + The maximum number of values that any attribute with this datatype + can have. Of the predefined attribute types, only "boolean" specifies + a non-null max_n_values, because it doesn''t make sense to have a + boolean attribute with more than one value. There is no + corresponding min_n_values column, because each attribute may be + optional, i.e., min_n_values would always be zero. +'; + +-- Load pre-defined datatypes. +-- +begin + insert into acs_datatypes + (datatype, max_n_values) + values + ('string', null); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('boolean', 1); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('number', null); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('integer', 1); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('money', null); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('date', null); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('timestamp', null); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('time_of_day', null); + + insert into acs_datatypes + (datatype, max_n_values) + values + ('enumeration', null); + + commit; +end; +/ + +--create table acs_input_types ( +--); + +create sequence acs_attribute_id_seq; + +create table acs_attributes ( + attribute_id integer not null + constraint acs_attributes_pk + primary key, + object_type not null + constraint acs_attributes_object_type_fk + references acs_object_types (object_type), + table_name varchar2(30), + constraint acs_attrs_obj_type_tbl_name_fk + foreign key (object_type, table_name) references acs_object_type_tables, + attribute_name varchar2(100) not null, + pretty_name varchar2(100) not null, + pretty_plural varchar2(100), + sort_order integer not null, + datatype not null + constraint acs_attributes_datatype_fk + references acs_datatypes (datatype), + default_value varchar2(4000), + min_n_values integer default 1 not null + constraint acs_attributes_min_n_ck + check (min_n_values >= 0), + max_n_values integer default 1 not null + constraint acs_attributes_max_n_ck + check (max_n_values >= 0), + storage varchar2(13) default 'type_specific' + constraint acs_attributes_storage_ck + check (storage in ('type_specific', + 'generic')), + static_p varchar2(1) default 'f' + constraint acs_attributes_static_bool + check (static_p in ('t', 'f')), + column_name varchar2(30), + constraint acs_attributes_attr_name_un + unique (attribute_name, object_type), + constraint acs_attributes_pretty_name_un + unique (pretty_name, object_type), + constraint acs_attributes_sort_order_un + unique (attribute_id, sort_order), + constraint acs_attributes_n_values_ck + check (min_n_values <= max_n_values) +); +-- constraint acs_attrs_pretty_plural_un +-- unique (pretty_plural, object_type), + +create bitmap index acs_attrs_obj_type_idx on acs_attributes (object_type); +create index acs_attrs_tbl_name_idx on acs_attributes (table_name); +create bitmap index acs_attrs_datatype_idx on acs_attributes (datatype); + +comment on table acs_attributes is ' + Each row in the acs_attributes table defines an + attribute of the specified object type. Each object of this type + must have a minimum of min_n_values values and a maximum of + max_n_values for this attribute. +'; + +comment on column acs_attributes.table_name is ' + If the data storage for the object type is arranged in a vertically + partitioned manner, then this column should indicate in which table + the attribute is stored. +'; + +comment on column acs_attributes.storage is ' + Indicates how values of this attribute are stored: either + "type_specific" (i.e., in the table identified by + object_type.table_name) or "generic" (i.e., in the + acs_attribute_values table). (Or we could just have a column_name and, + if it''s null, then assume that we''re using acs_attribute_values.) +'; + +comment on column acs_attributes.static_p is ' + Determines whether this attribute is static. If so, only one copy of + the attribute''s value exists for all objects of the same type. This + value is stored in acs_static_attr_values table if storage_type is + "generic". Otherwise, each object of this type can have its own + distinct value for the attribute. +'; + +comment on column acs_attributes.column_name is ' + If storage is "type_specific", column_name identifies the column in + the table identified by object_type.table_name that holds the values + of this attribute. If column_name is null, then we assume that + attribute_name identifies a column in the table identified by + object_type.table_name. +'; + +create table acs_enum_values ( + attribute_id not null + constraint asc_enum_values_attr_id_fk + references acs_attributes (attribute_id), + enum_value varchar2(1000), + pretty_name varchar2(100) not null, + sort_order integer not null, + constraint acs_enum_values_pk + primary key (attribute_id, enum_value), + constraint acs_enum_values_pretty_name_un + unique (attribute_id, pretty_name), + constraint acs_enum_values_sort_order_un + unique (attribute_id, sort_order) +); + +create index acs_enum_values_attr_id_idx on acs_enum_values (attribute_id); + +create table acs_attribute_descriptions ( + object_type not null constraint acs_attr_descs_obj_type_fk + references acs_object_types (object_type), + attribute_name varchar2(100) not null, + constraint acs_attr_descs_ob_tp_at_na_fk + foreign key (object_type, attribute_name) + references acs_attributes (object_type, attribute_name), + description_key varchar2(100), + constraint acs_attribute_descriptions_pk + primary key (object_type, attribute_name, description_key), + description clob not null +); + +create bitmap index acs_attr_desc_obj_type_idx on acs_attribute_descriptions (object_type); +create index acs_attr_desc_attr_name_idx on acs_attribute_descriptions (attribute_name); + + +-- Create a view to show us all the attributes for one object, +-- including attributes for each of its supertypes + +-- Note that the internal union is required to get attributes for the +-- object type we specify. Without this union, we would get attributes +-- for all supertypes, but not for the specific type in question + +-- Note also that we cannot select attr.* in the view because the +-- object_type in the attributes table refers to one attribute (kind +-- of like the owner of the attribute). That object_type is really the +-- ancestor type... that is, the ancestor of the user-specified object +-- type for which the attribute should be specified. + +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 ALL + 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; + + +----------------------- +-- METADATA PACKAGES -- +----------------------- + +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; + + -- Returns 't' if object_type_2 is a subtype of object_type_1. Note + -- that this function will return 'f' if object_type_1 = + -- object_type_2 + function is_subtype_p ( + object_type_1 in acs_object_types.object_type%TYPE, + object_type_2 in acs_object_types.object_type%TYPE + ) return char; + +end acs_object_type; +/ +show errors + + +create or replace package acs_attribute +is + + -- define an object attribute + 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; + + procedure drop_attribute ( + object_type in varchar2, + attribute_name in varchar2 + ); + + 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 + ); + + 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 + ); + +end acs_attribute; +/ +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; + + + function is_subtype_p ( + object_type_1 in acs_object_types.object_type%TYPE, + object_type_2 in acs_object_types.object_type%TYPE + ) return char + is + v_result integer; + begin + select count(*) into v_result + from dual + where exists (select 1 + from acs_object_types t + where t.object_type = is_subtype_p.object_type_2 + connect by prior t.object_type = t.supertype + start with t.supertype = is_subtype_p.object_type_1); + + if v_result > 0 then + return 't'; + end if; + + return 'f'; + + end is_subtype_p; + +end acs_object_type; +/ +show errors + + + +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 Index: openacs-4/packages/acs-kernel/sql/oracle/acs-metadata-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-metadata-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-metadata-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,21 @@ +-- +-- acs-kernel/sql/acs-metadata-drop.sql +-- +-- DDL commands to purge the Community Core data model +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @creation-date 2000-05-18 +-- @cvs-id $Id: acs-metadata-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +drop package acs_attribute; +drop package acs_object_type; +drop view acs_object_type_attributes; +drop table acs_attribute_descriptions; +drop table acs_enum_values; +drop table acs_attributes; +drop sequence acs_attribute_id_seq; +drop table acs_datatypes; +drop table acs_object_type_tables; +drop view acs_object_type_supertype_map; +drop table acs_object_types; Index: openacs-4/packages/acs-kernel/sql/oracle/acs-objects-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-objects-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-objects-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,1024 @@ +-- +-- acs-kernel/sql/acs-objects-create.sql +-- +-- A base object type that provides auditing columns, permissioning, +-- attributes, and relationships to any subtypes. +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @author Rafael Schloming (rhs@mit.edu) +-- @author Jon Salz (jsalz@mit.edu) +-- +-- @creation-date 2000-05-18 +-- +-- @cvs-id $Id: acs-objects-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +----------------------------- +-- PREDEFINED OBJECT TYPES -- +----------------------------- + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + -- + -- The ultimate supertype: object + -- + acs_object_type.create_type ( + supertype => null, + object_type => 'acs_object', + pretty_name => 'Object', + pretty_plural => 'Objects', + table_name => 'acs_objects', + id_column => 'object_id', + package_name => 'acs_object', + name_method => 'acs_object.default_name' + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'acs_object', + attribute_name => 'object_type', + datatype => 'string', + pretty_name => 'Object Type', + pretty_plural => 'Object Types' + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'acs_object', + attribute_name => 'creation_date', + datatype => 'date', + pretty_name => 'Created Date' + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'acs_object', + attribute_name => 'creation_ip', + datatype => 'string', + pretty_name => 'Creation IP Address' + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'acs_object', + attribute_name => 'last_modified', + datatype => 'date', + pretty_name => 'Last Modified On' + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'acs_object', + attribute_name => 'modifying_ip', + datatype => 'string', + pretty_name => 'Modifying IP Address' + ); + + 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 + ); + + commit; +end; +/ +show errors + +-- ****************************************************************** +-- * OPERATIONAL LEVEL +-- ****************************************************************** + +------------- +-- OBJECTS -- +------------- + +create sequence acs_object_id_seq cache 1000; + +create table acs_objects ( + object_id integer not null + constraint acs_objects_pk primary key, + object_type not null + constraint acs_objects_object_type_fk + references acs_object_types (object_type), + context_id constraint acs_objects_context_id_fk + references acs_objects(object_id), + security_inherit_p char(1) default 't' not null, + constraint acs_objects_sec_inherit_p_ck + check (security_inherit_p in ('t', 'f')), + creation_user integer, + creation_date date default sysdate not null, + creation_ip varchar2(50), + last_modified date default sysdate not null, + modifying_user integer, + modifying_ip varchar2(50), + constraint acs_objects_context_object_un + unique (context_id, object_id) disable +); + +create index acs_objects_context_object_idx on + acs_objects (context_id, object_id); + +alter table acs_objects modify constraint acs_objects_context_object_un enable; + +create index acs_objects_creation_user_idx on acs_objects (creation_user); +create index acs_objects_modify_user_idx on acs_objects (modifying_user); + +create bitmap index acs_objects_object_type_idx on acs_objects (object_type); + +create or replace trigger acs_objects_mod_ip_insert_tr +before insert on acs_objects +for each row +begin + :new.modifying_ip := :new.creation_ip; +end acs_objects_mod_ip_insert_tr; +/ +show errors + +create or replace trigger acs_objects_last_mod_update_tr +before update on acs_objects +for each row +begin + :new.last_modified := sysdate; +end acs_objects_last_mod_update_tr; +/ +show errors + +comment on table acs_objects is ' +'; + +comment on column acs_objects.context_id is ' + The context_id column points to an object that provides a context for + this object. Often this will reflect an observed hierarchy in a site, + for example a bboard message would probably list a bboard topic as + it''s context, and a bboard topic might list a sub-site as it''s + context. Whenever we ask a question of the form "can user X perform + action Y on object Z", the acs security model will defer to an + object''s context if there is no information about user X''s + permission to perform action Y on object Z. +'; + +comment on column acs_objects.creation_user is ' + Who created the object; may be null since objects can be created by + automated processes +'; + +comment on column acs_objects.modifying_user is ' + Who last modified the object +'; + +----------------------- +-- CONTEXT HIERARCHY -- +----------------------- + +create table acs_object_context_index ( + object_id not null + constraint acs_obj_context_idx_obj_id_fk + references acs_objects(object_id), + ancestor_id not null + constraint acs_obj_context_idx_anc_id_fk + references acs_objects(object_id), + n_generations integer not null + constraint acs_obj_context_idx_n_gen_ck + check (n_generations >= 0), + constraint acs_object_context_index_pk + primary key (object_id, ancestor_id) +) organization index; + +create index acs_obj_ctx_idx_ancestor_idx on acs_object_context_index (ancestor_id); + +create or replace view acs_object_paths +as select object_id, ancestor_id, n_generations + from acs_object_context_index; + +create or replace view acs_object_contexts +as select object_id, ancestor_id, n_generations + from acs_object_context_index + where object_id != ancestor_id; + +create or replace trigger acs_objects_context_id_in_tr +after insert on acs_objects +for each row +begin + insert into acs_object_context_index + (object_id, ancestor_id, n_generations) + values + (:new.object_id, :new.object_id, 0); + + if :new.context_id is not null and :new.security_inherit_p = 't' then + insert into acs_object_context_index + (object_id, ancestor_id, + n_generations) + select + :new.object_id as object_id, ancestor_id, + n_generations + 1 as n_generations + from acs_object_context_index + where object_id = :new.context_id; + elsif :new.object_id != 0 then + -- 0 is the id of the security context root object + insert into acs_object_context_index + (object_id, ancestor_id, n_generations) + values + (:new.object_id, 0, 1); + end if; +end; +/ +show errors + +create or replace trigger acs_objects_context_id_up_tr +after update on acs_objects +for each row +begin + if :new.object_id = :old.object_id and + :new.context_id = :old.context_id and + :new.security_inherit_p = :old.security_inherit_p then + return; + end if; + + -- Remove my old ancestors from my descendants. + delete from acs_object_context_index + where object_id in (select object_id + from acs_object_contexts + where ancestor_id = :old.object_id) + and ancestor_id in (select ancestor_id + from acs_object_contexts + where object_id = :old.object_id); + + -- Kill all my old ancestors. + delete from acs_object_context_index + where object_id = :old.object_id; + + insert into acs_object_context_index + (object_id, ancestor_id, n_generations) + values + (:new.object_id, :new.object_id, 0); + + if :new.context_id is not null and :new.security_inherit_p = 't' then + -- Now insert my new ancestors for my descendants. + for pair in (select * + from acs_object_context_index + where ancestor_id = :new.object_id) loop + insert into acs_object_context_index + (object_id, ancestor_id, n_generations) + select + pair.object_id, ancestor_id, + n_generations + pair.n_generations + 1 as n_generations + from acs_object_context_index + where object_id = :new.context_id; + end loop; + elsif :new.object_id != 0 then + -- We need to make sure that :NEW.OBJECT_ID and all of its + -- children have 0 as an ancestor. + for pair in (select * + from acs_object_context_index + where ancestor_id = :new.object_id) loop + insert into acs_object_context_index + (object_id, ancestor_id, n_generations) + values + (pair.object_id, 0, pair.n_generations + 1); + end loop; + end if; +end; +/ +show errors + +create or replace trigger acs_objects_context_id_del_tr +before delete on acs_objects +for each row +begin + delete from acs_object_context_index + where object_id = :old.object_id; +end; +/ +show errors + +---------------------- +-- ATTRIBUTE VALUES -- +---------------------- + +create sequence acs_attribute_value_id_seq; + +create table acs_attribute_values ( + object_id not null + constraint acs_attr_values_obj_id_fk + references acs_objects (object_id) on delete cascade, + attribute_id not null + constraint acs_attr_values_attr_id_fk + references acs_attributes (attribute_id), + attr_value varchar2(4000), + constraint acs_attribute_values_pk primary key + (object_id, attribute_id) +); + +create index acs_attr_values_attr_id_idx on acs_attribute_values (attribute_id); + +comment on table acs_attribute_values is ' + Instead of coercing everything into a big string, we could use + a "union", i.e, a string column, a number column, a date column, + and a discriminator. +'; + +create table acs_static_attr_values ( + object_type not null + constraint acs_static_a_v_obj_id_fk + references acs_object_types (object_type) on delete cascade, + attribute_id not null + constraint acs_static_a_v_attr_id_fk + references acs_attributes (attribute_id), + attr_value varchar2(4000), + constraint acs_static_a_v_pk primary key + (object_type, attribute_id) +); + +create index acs_stat_attrs_attr_id_idx on acs_static_attr_values (attribute_id); + +comment on table acs_static_attr_values is ' + Stores static values for the object attributes. One row per object + type. +'; + +------------------------ +-- ACS_OBJECT PACKAGE -- +------------------------ + +create or replace package acs_object +as + + function new ( + object_id in acs_objects.object_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'acs_object', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + object_id in acs_objects.object_id%TYPE + ); + + function name ( + object_id in acs_objects.object_id%TYPE + ) return varchar2; + + -- The acs_object_types.name_method for "acs_object" + -- + function default_name ( + object_id in acs_objects.object_id%TYPE + ) return varchar2; + + -- Determine where the attribute is stored and what sql needs to be + -- in the where clause to retreive it + -- Used in get_attribute and set_attribute + procedure get_attribute_storage ( + object_id_in in acs_objects.object_id%TYPE, + attribute_name_in in acs_attributes.attribute_name%TYPE, + v_column out varchar2, + v_table_name out varchar2, + v_key_sql out varchar2 + ); + + -- Get/set the value of an object attribute, as long as + -- the type can be cast to varchar2 + function get_attribute ( + object_id_in in acs_objects.object_id%TYPE, + attribute_name_in in acs_attributes.attribute_name%TYPE + ) return varchar2; + + procedure set_attribute ( + object_id_in in acs_objects.object_id%TYPE, + attribute_name_in in acs_attributes.attribute_name%TYPE, + value_in in varchar2 + ); + + function check_representation ( + object_id in acs_objects.object_id%TYPE + ) return char; + +end acs_object; +/ +show errors + +create or replace package body acs_object +as + + procedure initialize_attributes ( + object_id in acs_objects.object_id%TYPE + ) + is + v_object_type acs_objects.object_type%TYPE; + begin + -- XXX This should be fixed to initialize supertypes properly. + + -- Initialize dynamic attributes + insert into acs_attribute_values + (object_id, attribute_id, attr_value) + select + initialize_attributes.object_id, a.attribute_id, a.default_value + from acs_attributes a, acs_objects o + where a.object_type = o.object_type + and o.object_id = initialize_attributes.object_id + and a.storage = 'generic' + and a.static_p = 'f'; + + -- Retreive type for static attributes + select object_type into v_object_type from acs_objects + where object_id = initialize_attributes.object_id; + + -- Initialize static attributes + begin + insert into acs_static_attr_values + (object_type, attribute_id, attr_value) + select + v_object_type, a.attribute_id, a.default_value + from acs_attributes a, acs_objects o + where a.object_type = o.object_type + and o.object_id = initialize_attributes.object_id + and a.storage = 'generic' + and a.static_p = 't' + and not exists (select 1 from acs_static_attr_values + where object_type = a.object_type); + exception when no_data_found then null; + end; + + end initialize_attributes; + + function new ( + object_id in acs_objects.object_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'acs_object', + 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, + context_id in acs_objects.context_id%TYPE default null + ) + return acs_objects.object_id%TYPE + is + v_object_id acs_objects.object_id%TYPE; + begin + if object_id is null then + select acs_object_id_seq.nextval + into v_object_id + from dual; + else + v_object_id := object_id; + end if; + + insert into acs_objects + (object_id, object_type, context_id, + creation_date, creation_user, creation_ip) + values + (v_object_id, object_type, context_id, + creation_date, creation_user, creation_ip); + + acs_object.initialize_attributes(v_object_id); + + return v_object_id; + end new; + + procedure delete ( + object_id in acs_objects.object_id%TYPE + ) + is + begin + + -- Delete dynamic/generic attributes + delete from acs_attribute_values where object_id = acs_object.delete.object_id; + + for object_type + in (select table_name, id_column + from acs_object_types + start with object_type = (select object_type + from acs_objects o + where o.object_id = acs_object.delete.object_id) + connect by object_type = prior supertype) + loop + -- Delete from the table. + execute immediate 'delete from ' || object_type.table_name || + ' where ' || object_type.id_column || ' = :object_id' + using in object_id; + end loop; + end delete; + + function name ( + object_id in acs_objects.object_id%TYPE + ) + return varchar2 + is + object_name varchar2(500); + v_object_id integer := object_id; + begin + -- Find the name function for this object, which is stored in the + -- name_method column of acs_object_types. Starting with this + -- object's actual type, traverse the type hierarchy upwards until + -- a non-null name_method value is found. + -- + for object_type + in (select name_method + from acs_object_types + start with object_type = (select object_type + from acs_objects o + where o.object_id = name.object_id) + connect by object_type = prior supertype) + loop + if object_type.name_method is not null then + + -- Execute the first name_method we find (since we're traversing + -- up the type hierarchy from the object's exact type) using + -- Native Dynamic SQL, to ascertain the name of this object. + -- + --execute immediate 'select ' || object_type.name_method || '(:1) from dual' + execute immediate 'begin :1 := ' || object_type.name_method || '(:2); end;' + using out object_name, in object_id; + --into object_name + + exit; + end if; + end loop; + + return object_name; + end name; + + function default_name ( + object_id in acs_objects.object_id%TYPE + ) return varchar2 + is + object_type_pretty_name acs_object_types.pretty_name%TYPE; + begin + select ot.pretty_name + into object_type_pretty_name + from acs_objects o, acs_object_types ot + where o.object_id = default_name.object_id + and o.object_type = ot.object_type; + + return object_type_pretty_name || ' ' || object_id; + end default_name; + + procedure get_attribute_storage ( + object_id_in in acs_objects.object_id%TYPE, + attribute_name_in in acs_attributes.attribute_name%TYPE, + v_column out varchar2, + v_table_name out varchar2, + v_key_sql out varchar2 + ) + is + v_object_type acs_attributes.object_type%TYPE; + v_static acs_attributes.static_p%TYPE := null; + v_attr_id acs_attributes.attribute_id%TYPE := null; + v_storage acs_attributes.storage%TYPE := null; + v_attr_name acs_attributes.attribute_name%TYPE := null; + v_id_column varchar2(200) := null; + v_sql varchar2(4000) := null; + v_return varchar2(4000) := null; + + -- Fetch the most inherited attribute + cursor c_attribute is + select + a.attribute_id, a.static_p, a.storage, a.table_name, a.attribute_name, + a.object_type, a.column_name, t.id_column + from + acs_attributes a, + (select + object_type, id_column + from + acs_object_types + connect by + object_type = prior supertype + start with + object_type = (select object_type from acs_objects + where object_id = object_id_in) + ) t + where + a.attribute_name = attribute_name_in + and + a.object_type = t.object_type; + + begin + + -- Determine the attribute parameters + open c_attribute; + fetch c_attribute into + v_attr_id, v_static, v_storage, v_table_name, v_attr_name, + v_object_type, v_column, v_id_column; + if c_attribute%NOTFOUND then + close c_attribute; + raise_application_error (-20000, + 'No such attribute ' || v_object_type || '::' || attribute_name_in || + ' in acs_object.get_attribute_storage.'); + end if; + close c_attribute; + + -- This should really be done in a trigger on acs_attributes, + -- instead of generating it each time in this function + + -- If there is no specific table name for this attribute, + -- figure it out based on the object type + if v_table_name is null then + + -- Determine the appropriate table name + if v_storage = 'generic' then + -- Generic attribute: table name/column are hardcoded + + v_column := 'attr_value'; + + if v_static = 'f' then + v_table_name := 'acs_attribute_values'; + v_key_sql := '(object_id = ' || object_id_in || ' and ' || + 'attribute_id = ' || v_attr_id || ')'; + else + v_table_name := 'acs_static_attr_values'; + v_key_sql := '(object_type = ''' || v_object_type || ''' and ' || + 'attribute_id = ' || v_attr_id || ')'; + end if; + + else + -- Specific attribute: table name/column need to be retreived + + if v_static = 'f' then + select + table_name, id_column + into + v_table_name, v_id_column + from + acs_object_types + where + object_type = v_object_type; + else + raise_application_error(-20000, + 'No table name specified for storage specific static attribute ' || + v_object_type || '::' || attribute_name_in || + ' in acs_object.get_attribute_storage.'); + end if; + + end if; + else + -- There is a custom table name for this attribute. + -- Get the id column out of the acs_object_tables + -- Raise an error if not found + select id_column into v_id_column from acs_object_type_tables + where object_type = v_object_type + and table_name = v_table_name; + + end if; + + if v_column is null then + + if v_storage = 'generic' then + v_column := 'attr_value'; + else + v_column := v_attr_name; + end if; + + end if; + + if v_key_sql is null then + if v_static = 'f' then + v_key_sql := v_id_column || ' = ' || object_id_in ; + else + v_key_sql := v_id_column || ' = ''' || v_object_type || ''''; + end if; + end if; + + exception when no_data_found then + raise_application_error(-20000, 'No data found for attribute ' || + v_object_type || '::' || attribute_name_in || + ' in acs_object.get_attribute_storage'); + + end get_attribute_storage; + + -- Get/set the value of an object attribute, as long as + -- the type can be cast to varchar2 + function get_attribute ( + object_id_in in acs_objects.object_id%TYPE, + attribute_name_in in acs_attributes.attribute_name%TYPE + ) return varchar2 + is + v_table_name varchar2(200); + v_column varchar2(200); + v_key_sql varchar2(4000); + v_return varchar2(4000); + begin + + get_attribute_storage(object_id_in, attribute_name_in, + v_column, v_table_name, v_key_sql); + + begin + execute immediate 'select ' + || v_column || ' from ' || v_table_name || ' where ' || v_key_sql + into + v_return; + exception when no_data_found then + return null; + end; + + return v_return; + end get_attribute; + + procedure set_attribute ( + object_id_in in acs_objects.object_id%TYPE, + attribute_name_in in acs_attributes.attribute_name%TYPE, + value_in in varchar2 + ) + is + v_table_name varchar2(200); + v_column varchar2(200); + v_key_sql varchar2(4000); + v_return varchar2(4000); + v_dummy integer; + begin + + get_attribute_storage(object_id_in, attribute_name_in, + v_column, v_table_name, v_key_sql); + + execute immediate 'update ' + || v_table_name || ' set ' || v_column || ' = :value where ' || v_key_sql + using value_in; + + end set_attribute; + + function check_context_index ( + object_id in acs_objects.object_id%TYPE, + ancestor_id in acs_objects.object_id%TYPE, + n_generations in integer + ) return char + is + n_rows integer; + n_gens integer; + begin + -- Verify that this row exists in the index. + select decode(count(*),0,0,1) into n_rows + from acs_object_context_index + where object_id = check_context_index.object_id + and ancestor_id = check_context_index.ancestor_id; + + if n_rows = 1 then + -- Verify that the count is correct. + select n_generations into n_gens + from acs_object_context_index + where object_id = check_context_index.object_id + and ancestor_id = check_context_index.ancestor_id; + + if n_gens != n_generations then + acs_log.error('acs_object.check_representation', 'Ancestor ' || + ancestor_id || ' of object ' || object_id || + ' reports being generation ' || n_gens || + ' when it is actually generation ' || n_generations || + '.'); + return 'f'; + else + return 't'; + end if; + else + acs_log.error('acs_object.check_representation', 'Ancestor ' || + ancestor_id || ' of object ' || object_id || + ' is missing an entry in acs_object_context_index.'); + return 'f'; + end if; + end; + + function check_object_ancestors ( + object_id in acs_objects.object_id%TYPE, + ancestor_id in acs_objects.object_id%TYPE, + n_generations in integer + ) return char + is + context_id acs_objects.context_id%TYPE; + security_inherit_p acs_objects.security_inherit_p%TYPE; + n_rows integer; + n_gens integer; + result char(1); + begin + -- OBJECT_ID is the object we are verifying + -- ANCESTOR_ID is the current ancestor we are tracking + -- N_GENERATIONS is how far ancestor_id is from object_id + + -- Note that this function is only supposed to verify that the + -- index contains each ancestor for OBJECT_ID. It doesn''t + -- guarantee that there aren''t extraneous rows or that + -- OBJECT_ID''s children are contained in the index. That is + -- verified by seperate functions. + + result := 't'; + + -- Grab the context and security_inherit_p flag of the current + -- ancestor''s parent. + select context_id, security_inherit_p into context_id, security_inherit_p + from acs_objects + where object_id = check_object_ancestors.ancestor_id; + + if ancestor_id = 0 then + if context_id is null then + result := 't'; + else + -- This can be a constraint, can''t it? + acs_log.error('acs_object.check_representation', + 'Object 0 doesn''t have a null context_id'); + result := 'f'; + end if; + else + if context_id is null or security_inherit_p = 'f' then + context_id := 0; + end if; + + if check_context_index(object_id, ancestor_id, n_generations) = 'f' then + result := 'f'; + end if; + + if check_object_ancestors(object_id, context_id, + n_generations + 1) = 'f' then + result := 'f'; + end if; + end if; + + return result; + end; + + function check_object_descendants ( + object_id in acs_objects.object_id%TYPE, + descendant_id in acs_objects.object_id%TYPE, + n_generations in integer + ) return char + is + result char(1); + begin + -- OBJECT_ID is the object we are verifying. + -- DESCENDANT_ID is the current descendant we are tracking. + -- N_GENERATIONS is how far the current DESCENDANT_ID is from + -- OBJECT_ID. + + -- This function will verfy that each actualy descendant of + -- OBJECT_ID has a row in the index table. It does not check that + -- there aren't extraneous rows or that the ancestors of OBJECT_ID + -- are maintained correctly. + + result := 't'; + + -- First verify that OBJECT_ID and DESCENDANT_ID are actually in + -- the index. + if check_context_index(descendant_id, object_id, n_generations) = 'f' then + result := 'f'; + end if; + + -- For every child that reports inheriting from OBJECT_ID we need to call + -- ourselves recursively. + for obj in (select * + from acs_objects + where context_id = descendant_id + and security_inherit_p = 't') loop + if check_object_descendants(object_id, obj.object_id, + n_generations + 1) = 'f' then + result := 'f'; + end if; + end loop; + + return result; + end; + + function check_path ( + object_id in acs_objects.object_id%TYPE, + ancestor_id in acs_objects.object_id%TYPE + ) return char + is + context_id acs_objects.context_id%TYPE; + security_inherit_p acs_objects.security_inherit_p%TYPE; + begin + if object_id = ancestor_id then + return 't'; + end if; + + select context_id, security_inherit_p into context_id, security_inherit_p + from acs_objects + where object_id = check_path.object_id; + + if context_id is null or security_inherit_p = 'f' then + context_id := 0; + end if; + + return check_path(context_id, ancestor_id); + end; + + function check_representation ( + object_id in acs_objects.object_id%TYPE + ) return char + is + result char(1); + object_type acs_objects.object_type%TYPE; + n_rows integer; + begin + result := 't'; + acs_log.notice('acs_object.check_representation', + 'Running acs_object.check_representation on object_id = ' || + object_id || '.'); + + -- If this fails then there isn''t even an object associated with + -- this id. I'm going to let that error propogate as an exception. + select object_type into object_type + from acs_objects + where object_id = check_representation.object_id; + + acs_log.notice('acs_object.check_representation', + 'OBJECT STORAGE INTEGRITY TEST'); + + -- Let's look through every primary storage table associated with + -- this object type and all of its supertypes and make sure there + -- is a row with OBJECT_ID as theh primary key. + for t in (select t.object_type, t.table_name, t.id_column + from acs_object_type_supertype_map m, acs_object_types t + where m.ancestor_type = t.object_type + and m.object_type = check_representation.object_type + union + select object_type, table_name, id_column + from acs_object_types + where object_type = check_representation.object_type) loop + execute immediate 'select decode(count(*),0,0,1) from ' || t.table_name || + ' where ' || t.id_column || ' = ' || object_id + into n_rows; + + if n_rows = 0 then + result := 'f'; + acs_log.error('acs_object.check_representation', + 'Table ' || t.table_name || ' (primary storage for ' || + t.object_type || ') doesn''t have a row for object ' || + object_id || ' of type ' || object_type || '.'); + end if; + end loop; + + acs_log.notice('acs_object.check_representation', + 'OBJECT CONTEXT INTEGRITY TEST'); + + -- Do a bunch of dirt simple sanity checks. + + -- First let's check that all of our ancestors appear in + -- acs_object_context_index with the correct generation listed. + if check_object_ancestors(object_id, object_id, 0) = 'f' then + result := 'f'; + end if; + + -- Now let's check that all of our descendants appear in + -- acs_object_context_index with the correct generation listed. + if check_object_descendants(object_id, object_id, 0) = 'f' then + result := 'f'; + end if; + + -- Ok, we know that the index contains every entry that it is + -- supposed to have. Now let's make sure it doesn't contain any + -- extraneous entries. + for row in (select * + from acs_object_context_index + where object_id = check_representation.object_id + or ancestor_id = check_representation.object_id) loop + if check_path(row.object_id, row.ancestor_id) = 'f' then + acs_log.error('acs_object.check_representation', + 'acs_object_context_index contains an extraneous row: ' || + 'object_id = ' || row.object_id || ', ancestor_id = ' || + row.ancestor_id || ', n_generations = ' || + row.n_generations || '.'); + result := 'f'; + end if; + end loop; + + acs_log.notice('acs_object.check_representation', + 'Done running acs_object.check_representation ' || + 'on object_id = ' || object_id || '.'); + return result; + end check_representation; + +end acs_object; +/ +show errors + +------------------- +-- MISCELLANEOUS -- +------------------- + +create table general_objects ( + object_id not null + constraint general_objects_object_id_fk + references acs_objects (object_id) + constraint general_objects_pk + primary key, + on_which_table varchar2(30) not null, + on_what_id integer not null, + constraint general_objects_un + unique (on_which_table, on_what_id) +); + +comment on table general_objects is ' + This table can be used to treat non-acs_objects as acs_objects for + purposes of access control, categorization, etc. +'; Index: openacs-4/packages/acs-kernel/sql/oracle/acs-objects-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-objects-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-objects-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,25 @@ +-- +-- acs-kernel/sql/acs-objects-drop.sql +-- +-- DDL commands to purge the ACS Objects data model +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @creation-date 2000-05-18 +-- @cvs-id $Id: acs-objects-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +drop table general_objects; +drop package acs_object; +drop table acs_static_attr_values; +drop table acs_attribute_values; +drop sequence acs_attribute_value_id_seq; +drop trigger acs_objects_context_id_del_tr; +drop trigger acs_objects_context_id_up_tr; +drop trigger acs_objects_context_id_in_tr; +drop view acs_object_contexts; +drop view acs_object_paths; +drop table acs_object_context_index; +drop trigger acs_objects_last_mod_update_tr; +drop trigger acs_objects_mod_ip_insert_tr; +drop table acs_objects; +drop sequence acs_object_id_seq; Index: openacs-4/packages/acs-kernel/sql/oracle/acs-permissions-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-permissions-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-permissions-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,391 @@ +-- +-- acs-kernel/sql/acs-permissions-create.sql +-- +-- The ACS core permissioning system. The knowledge level of system +-- allows you to define a hierarchichal system of privilages, and +-- associate them with low level operations on object types. The +-- operational level allows you to grant to any party a privilege on +-- any object. +-- +-- @author Rafael Schloming (rhs@mit.edu) +-- +-- @creation-date 2000-08-13 +-- +-- @cvs-id $Id: acs-permissions-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + + +--------------------------------------------- +-- KNOWLEDGE LEVEL: PRIVILEGES AND ACTIONS -- +--------------------------------------------- + +-- suggestion: acs_methods, acs_operations, acs_transactions? +-- what about cross-type actions? new-stuff? site-wide search? + +--create table acs_methods ( +-- object_type not null constraint acs_methods_object_type_fk +-- references acs_object_types (object_type), +-- method varchar2(100) not null, +-- constraint acs_methods_pk +-- primary key (object_type, method) +--); + +--comment on table acs_methods is ' +-- Each row in the acs_methods table directly corresponds to a +-- transaction on an object. For example an sql statement that updates a +-- bboard message would require an entry in this table. +--' + +create table acs_privileges ( + privilege varchar2(100) not null constraint acs_privileges_pk + primary key, + pretty_name varchar2(100), + pretty_plural varchar2(100) +); + +create table acs_privilege_hierarchy ( + privilege not null constraint acs_priv_hier_priv_fk + references acs_privileges (privilege), + child_privilege not null constraint acs_priv_hier_child_priv_fk + references acs_privileges (privilege), + constraint acs_privilege_hierarchy_pk + primary key (privilege, child_privilege) +); + +create bitmap index acs_priv_hier_child_priv_idx on acs_privilege_hierarchy (child_privilege); + +--create table acs_privilege_method_rules ( +-- privilege not null constraint acs_priv_method_rules_priv_fk +-- references acs_privileges (privilege), +-- object_type varchar2(100) not null, +-- method varchar2(100) not null, +-- constraint acs_privilege_method_rules_pk +-- primary key (privilege, object_type, method), +-- constraint acs_priv_meth_rul_type_meth_fk +-- foreign key (object_type, method) references acs_methods +--); + +comment on table acs_privileges is ' + The rows in this table correspond to aggregations of specific + methods. Privileges share a global namespace. This is to avoid a + situation where granting the foo privilege on one type of object can + have an entirely different meaning than granting the foo privilege on + another type of object. +'; + +comment on table acs_privilege_hierarchy is ' + The acs_privilege_hierarchy gives us an easy way to say: The foo + privilege is a superset of the bar privilege. +'; + +--comment on table acs_privilege_method_rules is ' +-- The privilege method map allows us to create rules that specify which +-- methods a certain privilege is allowed to invoke in the context of a +-- particular object_type. Note that the same privilege can have +-- different methods for different object_types. This is because each +-- method corresponds to a piece of code, and the code that displays an +-- instance of foo will be different than the code that displays an +-- instance of bar. If there are no methods defined for a particular +-- (privilege, object_type) pair, then that privilege is not relavent to +-- that object type, for example there is no way to moderate a user, so +-- there would be no additional methods that you could invoke if you +-- were granted moderate on a user. +--' + +--create or replace view acs_privilege_method_map +--as select r1.privilege, pmr.object_type, pmr.method +-- from acs_privileges r1, acs_privileges r2, acs_privilege_method_rules pmr +-- where r2.privilege in (select distinct rh.child_privilege +-- from acs_privilege_hierarchy rh +-- start with privilege = r1.privilege +-- connect by prior child_privilege = privilege +-- union +-- select r1.privilege +-- from dual) +-- and r2.privilege = pmr.privilege; + +create or replace package acs_privilege +as + + procedure create_privilege ( + privilege in acs_privileges.privilege%TYPE, + pretty_name in acs_privileges.pretty_name%TYPE default null, + pretty_plural in acs_privileges.pretty_plural%TYPE default null + ); + + procedure drop_privilege ( + privilege in acs_privileges.privilege%TYPE + ); + + procedure add_child ( + privilege in acs_privileges.privilege%TYPE, + child_privilege in acs_privileges.privilege%TYPE + ); + + procedure remove_child ( + privilege in acs_privileges.privilege%TYPE, + child_privilege in acs_privileges.privilege%TYPE + ); + +end; +/ +show errors + +create or replace package body acs_privilege +as + + procedure create_privilege ( + privilege in acs_privileges.privilege%TYPE, + pretty_name in acs_privileges.pretty_name%TYPE default null, + pretty_plural in acs_privileges.pretty_plural%TYPE default null + ) + is + begin + insert into acs_privileges + (privilege, pretty_name, pretty_plural) + values + (create_privilege.privilege, + create_privilege.pretty_name, + create_privilege.pretty_plural); + end; + + procedure drop_privilege ( + privilege in acs_privileges.privilege%TYPE + ) + is + begin + delete from acs_privileges + where privilege = drop_privilege.privilege; + end; + + procedure add_child ( + privilege in acs_privileges.privilege%TYPE, + child_privilege in acs_privileges.privilege%TYPE + ) + is + begin + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + (add_child.privilege, add_child.child_privilege); + end; + + procedure remove_child ( + privilege in acs_privileges.privilege%TYPE, + child_privilege in acs_privileges.privilege%TYPE + ) + is + begin + delete from acs_privilege_hierarchy + where privilege = remove_child.privilege + and child_privilege = remove_child.child_privilege; + end; + + +end; +/ +show errors + + +------------------------------------ +-- OPERATIONAL LEVEL: PERMISSIONS -- +------------------------------------ + +create table acs_permissions ( + object_id not null + constraint acs_permissions_on_what_id_fk + references acs_objects (object_id), + grantee_id not null + constraint acs_permissions_grantee_id_fk + references parties (party_id), + privilege not null constraint acs_permissions_priv_fk + references acs_privileges (privilege), + constraint acs_permissions_pk + primary key (object_id, grantee_id, privilege) +); + +create index acs_permissions_grantee_idx on acs_permissions (grantee_id); +create bitmap index acs_permissions_privilege_idx on acs_permissions (privilege); + +create or replace view acs_privilege_descendant_map +as select p1.privilege, p2.privilege as descendant + from acs_privileges p1, acs_privileges p2 + where p2.privilege in (select child_privilege + from acs_privilege_hierarchy + start with privilege = p1.privilege + connect by prior child_privilege = privilege) + or p2.privilege = p1.privilege; + +create or replace view acs_permissions_all +as select op.object_id, p.grantee_id, p.privilege + from acs_object_paths op, acs_permissions p + where op.ancestor_id = p.object_id; + +create or replace view acs_object_grantee_priv_map +as select a.object_id, a.grantee_id, m.descendant as privilege + from acs_permissions_all a, acs_privilege_descendant_map m + where a.privilege = m.privilege; + +-- The last two unions make sure that the_public gets expaned to all +-- users plus 0 (the default user_id) we should probably figure out a +-- better way to handle this eventually since this view is getting +-- pretty freaking hairy. I'd love to be able to move this stuff into +-- a Java middle tier. + +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_approved_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_seg_approved_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; + +---------------------------------------------------- +-- ALTERNATE VIEW: ALL_OBJECT_PARTY_PRIVILEGE_MAP -- +---------------------------------------------------- + +-- This view is a helper for all_object_party_privilege_map +create or replace view acs_grantee_party_map as + select -1 as grantee_id, 0 as party_id from dual + union all + select -1 as grantee_id, user_id as party_id + from users + union all + select party_id as grantee_id, party_id + from parties + union all + select segment_id as grantee_id, member_id + from rel_seg_approved_member_map + union all + select group_id as grantee_id, member_id as party_id + from group_approved_member_map; + +-- This view is like acs_object_party_privilege_map, but does not +-- necessarily return distinct rows. It may be *much* faster to join +-- against this view instead of acs_object_party_privilege_map, and is +-- usually not much slower. The tradeoff for the performance boost is +-- increased complexity in your usage of the view. Example usage that I've +-- found works well is: +-- +-- select DISTINCT +-- my_table.* +-- from my_table, +-- (select object_id +-- from all_object_party_privilege_map +-- where party_id = :user_id and privilege = :privilege) oppm +-- where oppm.object_id = my_table.my_id; +-- + +create or replace view all_object_party_privilege_map as +select /*+ ORDERED */ + op.object_id, + pdm.descendant as privilege, + gpm.party_id as party_id + from acs_object_paths op, + acs_permissions p, + acs_privilege_descendant_map pdm, + acs_grantee_party_map gpm + where op.ancestor_id = p.object_id + and pdm.privilege = p.privilege + and gpm.grantee_id = p.grantee_id; + + +--create or replace view acs_object_party_method_map +--as select opp.object_id, opp.party_id, pm.object_type, pm.method +-- from acs_object_party_privilege_map opp, acs_privilege_method_map pm +-- where opp.privilege = pm.privilege; + +create or replace package 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 + ); + + procedure revoke_permission ( + object_id acs_permissions.object_id%TYPE, + grantee_id acs_permissions.grantee_id%TYPE, + privilege acs_permissions.privilege%TYPE + ); + + function permission_p ( + object_id acs_objects.object_id%TYPE, + party_id parties.party_id%TYPE, + privilege acs_privileges.privilege%TYPE + ) return char; + +end acs_permission; +/ +show errors + +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 Index: openacs-4/packages/acs-kernel/sql/oracle/acs-permissions-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-permissions-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-permissions-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,23 @@ +-- +-- packages/acs-kernel/sql/acs-permissions-drop.sql +-- +-- @creation-date 2000-08-13 +-- +-- @author rhs@mit.edu +-- +-- @cvs-id $Id: acs-permissions-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +--drop view acs_object_party_method_map; +drop view acs_object_party_privilege_map; +drop view acs_object_grantee_priv_map; +drop view acs_permissions_all; +drop view acs_privilege_descendant_map; +drop package acs_permission; +drop table acs_permissions; +--drop view acs_privilege_method_map; +--drop table acs_privilege_method_rules; +drop package acs_privilege; +drop table acs_privilege_hierarchy; +drop table acs_privileges; +--drop table acs_methods; Index: openacs-4/packages/acs-kernel/sql/oracle/acs-relationships-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-relationships-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-relationships-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,506 @@ +-- +-- packages/acs-kernel/sql/acs-relationships-create.sql +-- +-- XXX Fill this in later. +-- +-- @creation-date 2000-08-13 +-- +-- @author rhs@mit.edu +-- +-- @cvs-id $Id: acs-relationships-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +---------------------------------------------------------------- +-- KNOWLEDGE LEVEL: RELATIONSHIP TYPES AND RELATIONSHIP RULES -- +---------------------------------------------------------------- + +create table acs_rel_roles ( + role varchar2(100) not null + constraint acs_rel_roles_pk primary key, + pretty_name varchar2(100) not null, + pretty_plural varchar2(100) not null +); + +create table acs_rel_types ( + rel_type varchar2(100) not null + constraint acs_rel_types_pk primary key + constraint acs_rel_types_rel_type_fk + references acs_object_types(object_type), + object_type_one not null + constraint acs_rel_types_obj_type_1_fk + references acs_object_types (object_type), + role_one constraint acs_rel_types_role_1_fk + references acs_rel_roles (role), + min_n_rels_one integer default 0 not null + constraint acs_rel_types_min_n_1_ck + check (min_n_rels_one >= 0), + max_n_rels_one integer + constraint acs_rel_types_max_n_1_ck + check (max_n_rels_one >= 0), + object_type_two not null + constraint acs_rel_types_obj_type_2_fk + references acs_object_types (object_type), + role_two constraint acs_rel_types_role_2_fk + references acs_rel_roles (role), + min_n_rels_two integer default 0 not null + constraint acs_rel_types_min_n_2_ck + check (min_n_rels_two >= 0), + max_n_rels_two integer + constraint acs_rel_types_max_n_2_ck + check (max_n_rels_two >= 0), + constraint acs_rel_types_n_rels_one_ck + check (min_n_rels_one <= max_n_rels_one), + constraint acs_rel_types_n_rels_two_ck + check (min_n_rels_two <= max_n_rels_two) +); + +create bitmap index acs_rel_types_objtypeone_idx on acs_rel_types (object_type_one); +create bitmap index acs_rel_types_role_one_idx on acs_rel_types (role_one); +create bitmap index acs_rel_types_objtypetwo_idx on acs_rel_types (object_type_two); +create bitmap index acs_rel_types_role_two_idx on acs_rel_types (role_two); + +comment on table acs_rel_types is ' + Each row in acs_rel_types represents a type of + relationship between objects. For example, the following DML + statement: +
+ 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
+  (''employment'',
+   ''person'', ''employee'', 0, null,
+   ''company'', ''employer'', 0, null)
+ 
+ defines an "employment" relationship type that can be expressed in + in natural language as: +
+ A person may be the employee of zero or more companies, and a company + may be the employer of zero or more people. +
+'; + +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 + +begin + acs_rel_type.create_type ( + rel_type => 'relationship', + pretty_name => 'Relationship', + pretty_plural => 'Relationships', + supertype => 'acs_object', + table_name => 'acs_rels', + id_column => 'rel_id', + package_name => 'acs_rel', + type_extension_table => 'acs_rel_types', + object_type_one => 'acs_object', + min_n_rels_one => 0, + max_n_rels_one => null, + object_type_two => 'acs_object', + min_n_rels_two => 0, + max_n_rels_two => null + ); + + commit; +end; +/ +show errors + +-------------------------------------- +-- OPERATIONAL LEVEL: RELATIONSHIPS -- +-------------------------------------- + +create sequence acs_rel_id_seq; + +create table acs_rels ( + rel_id not null + constraint acs_rels_rel_id_fk + references acs_objects (object_id) + constraint acs_rels_pk primary key, + rel_type not null + constraint acs_rels_rel_type_fk + references acs_rel_types (rel_type), + object_id_one not null + constraint acs_object_rels_one_fk + references acs_objects (object_id), + object_id_two not null + constraint acs_object_rels_two_fk + references acs_objects (object_id), + constraint acs_object_rels_un unique + (rel_type, object_id_one, object_id_two) +); + +create index acs_rels_object_id_one_idx on acs_rels (object_id_one); +create index acs_rels_object_id_two_idx on acs_rels (object_id_two); + +comment on table acs_rels is ' + The acs_rels table is essentially a generic mapping table for + acs_objects. Once we come up with a way to associate attributes with + relationship types, we could replace many of the ACS 3.x mapping + tables like user_content_map, user_group_map, and + user_group_type_modules_map with this one table. Much application + logic consists of asking questions like "Does object X have a + relationship of type Y to object Z?" where all that differs is + X, Y, and Z. Thus, the value of consolidating many mapping tables + into one is that we can provide a generic API for defining and + querying relationships. In addition, we may need to design a way to + enable "type_specific" storage for relationships (i.e., foreign key + columns for one-to-many relationships and custom mapping tables for + many-to-many relationships), instead of only supporting "generic" + storage in the acs_rels table. This would parallel what we do with + acs_attributes. +'; + +-------------- +-- TRIGGERS -- +-------------- + +-- added by oumi@arsdigita.com - Jan 11, 2001 + +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 + + +create or replace package 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; + + procedure delete ( + rel_id in acs_rels.rel_id%TYPE + ); + +end; +/ +show errors + +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 + + +----------- +-- VIEWS -- +----------- + +-- These views are handy for metadata driven UI + +-- View: rel_types_valid_obj_one_types +-- +-- Question: Given rel_type :rel_type, +-- +-- What are all the valid object_types for object_id_one of +-- a relation of type :rel_type +-- +-- Answer: select object_type +-- from rel_types_valid_obj__one_types +-- where rel_type = :rel_type +-- +create or replace view rel_types_valid_obj_one_types as +select rt.rel_type, th.object_type +from acs_rel_types rt, + (select object_type, ancestor_type + from acs_object_type_supertype_map + UNION ALL + select object_type, object_type as ancestor_type + from acs_object_types) th +where rt.object_type_one = th.ancestor_type; + +-- View: rel_types_valid_obj_two_types +-- +-- Question: Given rel_type :rel_type, +-- +-- What are all the valid object_types for object_id_two of +-- a relation of type :rel_type +-- +-- Answer: select object_type +-- from rel_types_valid_obj_two_types +-- where rel_type = :rel_type +-- +create or replace view rel_types_valid_obj_two_types as +select rt.rel_type, th.object_type +from acs_rel_types rt, + (select object_type, ancestor_type + from acs_object_type_supertype_map + UNION ALL + select object_type, object_type as ancestor_type + from acs_object_types) th +where rt.object_type_two = th.ancestor_type; + Index: openacs-4/packages/acs-kernel/sql/oracle/acs-relationships-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/acs-relationships-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/acs-relationships-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,16 @@ +-- +-- packages/acs-kernel/sql/acs-relationships-drop.sql +-- +-- @creation-date 2000-08-13 +-- +-- @author rhs@mit.edu +-- +-- @cvs-id $Id: acs-relationships-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +drop package acs_rel; +drop package acs_rel_type; +drop table acs_rels; +drop sequence acs_rel_id_seq; +drop table acs_rel_types; +drop table acs_rel_roles; Index: openacs-4/packages/acs-kernel/sql/oracle/apm-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/apm-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/apm-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,2624 @@ +-- +-- /packages/acs-kernel/sql/apm-create.sql +-- +-- Data model for the ACS Package Manager (APM) +-- +-- @author Bryan Quinn (bquinn@arsdigita.com) +-- @author Jon Salz (jsalz@mit.edu) +-- @creation-date 2000/04/30 +-- @cvs-id $Id: apm-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ + +----------------------------- +-- PACKAGE OBJECT -- +----------------------------- + +----------------------------- +-- Knowledge Level -- +----------------------------- + +create table apm_package_types ( + package_key varchar2(100) + constraint apm_package_types_p_key_pk primary key, + pretty_name varchar(100) + constraint apm_package_types_pretty_n_nn not null + constraint apm_package_types_pretty_n_un unique, + pretty_plural varchar2(100) + constraint apm_package_types_pretty_pl_un unique, + package_uri varchar2(1500) + constraint apm_packages_types_p_uri_nn not null + constraint apm_packages_types_p_uri_un unique, + package_type varchar2(300) + constraint apm_packages_pack_type_ck + check (package_type in ('apm_application', 'apm_service')), + spec_file_path varchar2(1500), + spec_file_mtime integer, + singleton_p char(1) default 'f' not null + constraint apm_packages_site_avail_p_ck + check (singleton_p in ('t', 'f')) +); + +comment on table apm_package_types is ' + This table holds additional knowledge level attributes for the + apm_package type and its subtypes. +'; + + +comment on column apm_package_types.package_key is ' + The package_key is what we call the package on this system. +'; + +comment on column apm_package_types.package_uri is ' + The package URI indicates where the package can be downloaded and + is a unique identifier for the package. +'; + +comment on column apm_package_types.spec_file_path is ' + The path to the package specification file. +'; + +comment on column apm_package_types.spec_file_mtime is ' + The last time a spec file was modified. This information is maintained in the +database so that if a user changes the specification file by editing the file +(as opposed to using the UI, the system can read the .info file and update +the information in the database appropriately. +'; + +comment on column apm_package_types.singleton_p is ' + Indicates if the package can be used for subsites. If this is set to + ''t'', the package can be enabled for any subsite. Otherwise, it is + restricted to the acs-admin/ subsite. +'; + + +begin +-- Create a new object type for packages. + acs_object_type.create_type ( + supertype => 'acs_object', + object_type => 'apm_package', + pretty_name => 'Package', + pretty_plural => 'Packages', + table_name => 'APM_PACKAGES', + id_column => 'package_id', + package_name => 'apm_package', + type_extension_table => 'apm_package_types', + name_method => 'apm_package.name' + ); +end; +/ +show errors; + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin +-- Register the meta-data for APM-packages + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package', + attribute_name => 'package_key', + datatype => 'string', + pretty_name => 'Package Key', + pretty_plural => 'Package Keys' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package', + attribute_name => 'package_uri', + datatype => 'string', + pretty_name => 'Package URI', + pretty_plural => 'Package URIs' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package', + attribute_name => 'spec_file_path', + datatype => 'string', + pretty_name => 'Specification File Path', + pretty_plural => 'Specification File Paths' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package', + attribute_name => 'spec_file_mtime', + datatype => 'number', + pretty_name => 'Specification File Modified Time', + pretty_plural => 'Specification File Modified Times' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package', + attribute_name => 'singleton_p', + datatype => 'boolean', + pretty_name => 'Singleton', + pretty_plural => 'Singletons' + ); + +end; +/ +show errors; + +create table apm_packages ( + package_id constraint apm_packages_package_id_fk + references acs_objects(object_id) + constraint apm_packages_pack_id_pk primary key, + package_key constraint apm_packages_package_key_fk + references apm_package_types(package_key), + instance_name varchar2(300) + constraint apm_packages_inst_name_nn not null, + enabled_p char(1) default 'f' + constraint apm_packages_enabled_p_ck + check (enabled_p in ('t', 'f')) +); + +create bitmap index apm_packages_package_key_idx on apm_packages (package_key); + +comment on table apm_packages is ' + This table maintains the list of all package instances in the sytem. +'; + +comment on column apm_packages.instance_name is ' + This column enables a name to associated with each instance of package. This enables the storage +of a human-readable distinction between different package instances. This is useful +if a site admin wishes to name an instance of an application, e.g. bboard, for a subsite. The admin +might create one instance, "Boston Public Bboard" for managing public forums for the Boston subsite, +and "Boston Private Bboard" for managing private forums for the Boston subsite. +'; + +comment on column apm_packages.enabled_p is ' + This indicates whether a package instance is enabled or not. Enabling a package instance means that +if a user accesses a URL mapped to the object, the package content will display. +Disabling a package prevents its content from ever being displayed. +'; + +----------------------------- +-- Operational Level -- +----------------------------- + +create table apm_package_versions ( + version_id integer + constraint apm_package_vers_id_pk primary key + constraint apm_package_vers_id_fk + references acs_objects(object_id), + package_key varchar2(100) + constraint apm_package_vers_pack_key_nn not null + constraint apm_package_vers_pack_key_fk + references apm_package_types(package_key), + version_name varchar2(100) + constraint apm_package_vers_ver_name_nn not null, + version_uri varchar2(1500) + constraint apm_package_vers_ver_uri_nn not null + constraint apm_package_vers_ver_uri_un unique, + summary varchar2(3000), + description_format varchar2(100) + constraint apm_package_vers_desc_for_ck + check (description_format in ('text/html', 'text/plain')), + description varchar2(4000), + release_date date, + vendor varchar2(500), + vendor_uri varchar2(1500), + enabled_p char(1) default 'f' + constraint apm_package_vers_enabled_p_nn not null + constraint apm_package_vers_enabled_p_ck check(enabled_p in ('t','f')), + installed_p char(1) default 'f' + constraint apm_package_vers_inst_p_nn not null + constraint apm_package_vers_inst_p_ck check(installed_p in ('t','f')), + tagged_p char(1) default 'f' + constraint apm_package_vers_tagged_p_nn not null + constraint apm_package_vers_tagged_p_ck check(tagged_p in ('t','f')), + imported_p char(1) default 'f' + constraint apm_package_vers_imp_p_nn not null + constraint apm_package_vers_imp_p_ck check(imported_p in ('t','f')), + data_model_loaded_p char(1) default 'f' + constraint apm_package_vers_dml_p_nn not null + constraint apm_package_vers_dml_p_ck check(data_model_loaded_p in ('t','f')), + cvs_import_results clob, + activation_date date, + deactivation_date date, + distribution_tarball blob, + distribution_uri varchar2(1500), + distribution_date date, + constraint apm_package_vers_id_name_un unique(package_key, version_name) +); + +comment on table apm_package_versions is ' + The table apm_package_versions contains one row for each version of each package + we know about, e.g., acs-kernel-3.3, acs-kernel-3.3.1, bboard-1.0, + bboard-1.0.1, etc. +'; + +comment on column apm_package_versions.version_name is ' +A version number consists of: + 1.A major version number. + 2.Optionally, up to three minor version numbers. + 3.One of the following: + The letter d, indicating a development-only version. + The letter a, indicating an alpha release. + The letter b, indicating a beta release. + No letter at all, indicating a final release. +In addition, the letters d, a, and b may be followed by another integer, indicating a version within the release. +For those who like regular expressions: + version_number := integer (''.'' integer){0,3} ((''d''|''a''|''b'') integer?)? +So the following is a valid progression for version numbers: + 0.9d, 0.9d1, 0.9a1, 0.9b1, 0.9b2, 0.9, 1.0, 1.0.1, 1.1b1, 1.1 +'; + +comment on column apm_package_versions.version_uri is ' + This column should uniquely identify a package version. This URI should in practice be a URL at which this specific +version can be downloaded. +'; + +comment on column apm_package_versions.summary is ' +Type a brief, one-sentence-or-less summary of the functionality of +your package. The summary should begin with a capital letter +and end with a period. +XXX (bquinn): Move to Content Repository? +'; + +comment on column apm_package_versions.description_format is ' + Must indicate whether the description is plain text or HTML. +'; + +comment on column apm_package_versions.description is ' +Type a one-paragraph description of your package. This is probably analogous +to the first paragraph in your package''s documentation. This is used to describe +the system to users considering installing it. +'; + +comment on column apm_package_versions.release_date is ' +This tracks when the package was released. Releasing a package means +freezing the code and files, creating an archive, and making the +package available for donwload. XXX (bquinn): I''m skeptical about the +usefulness of storing this information here. +'; + +comment on column apm_package_versions.vendor is ' +If the package is being released by a company or some kind of organization, +its name should go here. +'; + +comment on column apm_package_versions.vendor_uri is ' +This should be a URL pointing to the vendor. +'; + +comment on column apm_package_versions.enabled_p is ' + Is the version scheduled to be loaded at startup? +'; + +comment on column apm_package_versions.installed_p is ' + Is the version actually present in the filesystem? +'; + +comment on column apm_package_versions.tagged_p is ' + Have we ever assigned all the files in this version a CVS tag. + XXX (bquinn): deprecated. CVS management should not be through + this table. +'; + +comment on column apm_package_versions.imported_p is ' + Did we perform a vendor import on this version? + XXX (bquinn): deprecated. CVS management should not be through + this table. +'; + +comment on column apm_package_versions.data_model_loaded_p is ' + Have we brought the data model up to date for this version. + XXX (bquinn): deprecated. Its not useful to track this information. +'; + +comment on column apm_package_versions.cvs_import_results is ' + Store the results of an attempted CVS import. + XXX (bquinn): deprecated. CVS management should not be through + this table. +'; + +comment on column apm_package_versions.activation_date is ' + When was the version last enabled? + XXX (bquinn): do we really care about this enough to keep the information around? +'; + +comment on column apm_package_versions.deactivation_date is ' + When was the version last disabled? + XXX (bquinn): do we really care about this enough to keep the information around? +'; + +comment on column apm_package_versions.distribution_tarball is ' + The archive of the distribution. + XXX (bquinn): This should definitely be moved + to the content repository and renamed distribution_archive, or simply + stored in the file system. +'; + +comment on column apm_package_versions.distribution_uri is ' + Where was the distribution tarball downloaded from. +'; + +comment on column apm_package_versions.distribution_date is ' + When was the distribution tarball downloaded. +'; + +-- Metadata for the apm_package_versions object. + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + acs_object_type.create_type ( + supertype => 'acs_object', + object_type => 'apm_package_version', + pretty_name => 'Package Version', + pretty_plural => 'Package Versions', + table_name => 'APM_PACKAGE_VERSIONS', + id_column => 'version_id', + package_name => 'APM_PACKAGE_VERSION' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'package_key', + datatype => 'string', + pretty_name => 'Package Key', + pretty_plural => 'Package Keys' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'version_name', + datatype => 'string', + pretty_name => 'Version Name', + pretty_plural => 'Version Names' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'version_uri', + datatype => 'string', + pretty_name => 'Version URI', + pretty_plural => 'Version URIs' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'summary', + datatype => 'string', + pretty_name => 'Summary', + pretty_plural => 'Summaries' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'description_format', + datatype => 'string', + pretty_name => 'Description Format', + pretty_plural => 'Description Formats' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'description', + datatype => 'string', + pretty_name => 'Description', + pretty_plural => 'Descriptions' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'vendor', + datatype => 'string', + pretty_name => 'Vendor', + pretty_plural => 'Vendors' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'vendor_uri', + datatype => 'string', + pretty_name => 'Vendor URI', + pretty_plural => 'Vendor URIs' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'enabled_p', + datatype => 'string', + pretty_name => 'Enabled', + pretty_plural => 'Enabled' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'activation_date', + datatype => 'date', + pretty_name => 'Activation Date', + pretty_plural => 'Activation Dates' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'deactivation_date', + datatype => 'string', + pretty_name => 'Deactivation Date', + pretty_plural => 'Deactivation Dates' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'distribution_uri', + datatype => 'string', + pretty_name => 'Distribution URI', + pretty_plural => 'Distribution URIs' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_package_version', + attribute_name => 'distribution_date', + datatype => 'date', + pretty_name => 'Distribution Date', + pretty_plural => 'Distribution Dates' + ); + +end; +/ +show errors; + +-- Who owns a version? +create table apm_package_owners ( + version_id constraint apm_package_owners_ver_id_fk references apm_package_versions on delete cascade, + -- if the uri is an email address, it should look like 'mailto:alex@arsdigita.com' + owner_uri varchar2(1500), + owner_name varchar2(200) + constraint apm_package_owners_name_nn not null, + sort_key integer +); + +create index apm_pkg_owners_version_idx on apm_package_owners (version_id); + +comment on table apm_package_owners is ' + This table tracks all of the owners of a particular package, and their email information. The sort_key column + manages the order of the authors. +'; + +-- Ths view faciliates accessing information about package versions by joining +-- the apm_package_types information and acs_object_types information (which is +-- invariant across versions) with the specific version information. +create or replace view apm_package_version_info as + select v.package_key, t.package_uri, t.pretty_name, v.version_id, v.version_name, + v.version_uri, v.summary, v.description_format, v.description, v.release_date, + v.vendor, v.vendor_uri, v.enabled_p, v.installed_p, v.tagged_p, v.imported_p, v.data_model_loaded_p, + v.activation_date, v.deactivation_date, + dbms_lob.getlength(distribution_tarball) tarball_length, + distribution_uri, distribution_date + from apm_package_types t, apm_package_versions v + where v.package_key = t.package_key; + + +-- A useful view for simply determining which packages are eanbled. +create or replace view apm_enabled_package_versions as + select * from apm_package_version_info + where enabled_p = 't'; + +create table apm_package_file_types ( + file_type_key varchar2(50) + constraint apm_package_file_types_pk primary key, + pretty_name varchar2(200) + constraint apm_package_file_types_name_nn not null +); + +comment on table apm_package_file_types is ' + A list of all the different kinds of files that can be part of an APM package. +'; + +begin + insert into apm_package_file_types(file_type_key, pretty_name) values('documentation', 'Documentation'); + insert into apm_package_file_types(file_type_key, pretty_name) values('tcl_procs', 'Tcl procedure library'); + insert into apm_package_file_types(file_type_key, pretty_name) values('tcl_init', 'Tcl initialization'); + insert into apm_package_file_types(file_type_key, pretty_name) values('content_page', 'Content page'); + insert into apm_package_file_types(file_type_key, pretty_name) values('package_spec', 'Package specification'); + insert into apm_package_file_types(file_type_key, pretty_name) values('data_model', 'Data model'); + insert into apm_package_file_types(file_type_key, pretty_name) values('data_model_create', 'Data model installation'); + insert into apm_package_file_types(file_type_key, pretty_name) values('data_model_drop', 'Data model deinstallation'); + insert into apm_package_file_types(file_type_key, pretty_name) values('data_model_upgrade', 'Data model upgrade'); + insert into apm_package_file_types(file_type_key, pretty_name) values('java_code', 'Java Code'); + insert into apm_package_file_types(file_type_key, pretty_name) values('template', 'Template file'); + insert into apm_package_file_types(file_type_key, pretty_name) values('shell', 'Shell utility'); + insert into apm_package_file_types(file_type_key, pretty_name) values('sqlj_code', 'SQLJ Library'); + commit; +end; +/ +show errors + +-- Which files are contained in a version? +create table apm_package_files ( + file_id integer + constraint apm_package_files_id_pk primary key, + version_id constraint apm_package_files_ver_id_fk references apm_package_versions + on delete cascade + constraint apm_package_files_ver_id_nn not null, + path varchar2(1500) + constraint apm_package_files_path_nn not null, + file_type constraint apm_package_files_type_fk references apm_package_file_types, + constraint apm_package_files_un unique(version_id, path) +); + +create bitmap index apm_pkg_files_file_type_idx on apm_package_files (file_type); + +comment on table apm_package_files is ' + The files that belong to an APM package. We store this information in the database +so that we can identify when a file is missing or added to the filesystem. +'; + +comment on column apm_package_files.path is ' + The relative path of the file underneath the package-root, i.e., + /packages/package-key. For example, packages/address-book/www/index.tcl would have + "www/index.tcl" as a path. +'; + +comment on column apm_package_files.file_type is ' + What kind of file is it? +'; + + +create index apm_package_files_by_path on apm_package_files(path); +create index apm_package_files_by_version on apm_package_files(version_id); + +-- A useful view for combining the package information with the file information. + +create or replace view apm_file_info as + select f.*, p.package_key, 'packages/' || p.package_key || '/' || f.path full_path + from apm_package_files f, apm_package_versions v, apm_package_types p + where f.version_id = v.version_id + and v.package_key = p.package_key; + + +create table apm_parameters ( + parameter_id constraint apm_parameters_fk + references acs_objects(object_id) + constraint apm_parameters_pk primary key, + package_key varchar2(100) + constraint apm_pack_param_pack_key_nn not null + constraint apm_pack_param_type_fk + references apm_package_types (package_key), + parameter_name varchar2(100) + constraint apm_pack_params_name_nn not null, + description varchar2(2000), + section_name varchar2(200), + datatype varchar2(100) not null + constraint apm_parameter_datatype_ck + check(datatype in ('number', 'string')), + default_value varchar2(4000), + min_n_values integer default 1 not null + constraint apm_paramters_min_n_ck + check (min_n_values >= 0), + max_n_values integer default 1 not null + constraint apm_paramters_max_n_ck + check (max_n_values >= 0), + constraint apm_paramters_attr_name_un + unique (parameter_name, package_key), + constraint apm_paramters_n_values_ck + check (min_n_values <= max_n_values) +); + +create index apm_parameters_package_idx on apm_parameters (package_key); + +comment on table apm_parameters is ' + This table stores information about parameters on packages. Every package parameter +is specific to a particular package instance and is queryable with the Tcl call +ad_parameter. +'; + +comment on column apm_parameters.parameter_name is ' + This is the name of the parameter, for example "DebugP." +'; + +comment on column apm_parameters.description is ' + A human readable description of what the parameter is used for. +'; + +comment on column apm_parameters.datatype is ' + Acceptable datatypes for parameters. Currently only numbers and strings. + XXX (bquinn): Integrate with acs objects metadata system. It is not + currently so integrated because of fluctuations with the general + storage mechanism during development. +'; + +comment on column apm_parameters.default_value is ' + The default value that any package instance will inherit unless otherwise + specified. +'; + +comment on column apm_parameters.min_n_values is ' + The minimum number of values that this parameter can take. Zero values means + that the default is always enforced (but is somewhat pointless). One value means that + it can only be set to one value. Increasing this number beyond one enables associating + a list of values with a parameter. + XXX (bquinn): More than one value is not supported by ad_parameter call at this time. +'; + +comment on column apm_parameters.max_n_values is ' +The maximum number of values that any attribute with this datatype + can have. +'; + +create table apm_parameter_values ( + value_id constraint apm_parameter_values_fk + references acs_objects(object_id) + constraint apm_parameter_values_pk primary key, + package_id constraint apm_pack_values_obj_id_fk + references apm_packages (package_id) on delete cascade, + parameter_id constraint apm_pack_values_parm_id_fk + references apm_parameters (parameter_id), + attr_value varchar2(4000), + constraint apm_parameter_values_un + unique (package_id, parameter_id) +); + +create index apm_par_vals_parameter_idx on apm_parameter_values (parameter_id); + +comment on table apm_parameter_values is ' + This table holds the values of parameters for package instances. +'; + +comment on column apm_parameter_values.attr_value is ' + This column holds the value for the instance parameter. +'; + +-- Metadata for the apm_parameter and apm_parameter_value system. + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + acs_object_type.create_type ( + supertype => 'acs_object', + object_type => 'apm_parameter', + pretty_name => 'Package Parameter', + pretty_plural => 'Package Parameters', + table_name => 'APM_PARAMETERS', + id_column => 'parameter_id', + package_name => 'apm_parameter' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter', + attribute_name => 'package_key', + datatype => 'string', + pretty_name => 'Package Key', + pretty_plural => 'Package Keys' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter', + attribute_name => 'parameter_name', + datatype => 'string', + pretty_name => 'Parameter Name', + pretty_plural => 'Parameter Name' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter', + attribute_name => 'datatype', + datatype => 'string', + pretty_name => 'Datatype', + pretty_plural => 'Datatypes' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter', + attribute_name => 'default_value', + datatype => 'string', + pretty_name => 'Default Value', + pretty_plural => 'Default Values' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter', + attribute_name => 'min_n_values', + datatype => 'number', + pretty_name => 'Minimum Number of Values', + pretty_plural => 'Minimum Numer of Values Settings', + default_value => 1 + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter', + attribute_name => 'max_n_values', + datatype => 'string', + pretty_name => 'Maximum Number of Values', + pretty_plural => 'Maximum Number of Values Settings', + default_value => 1 + ); +end; +/ +show errors; + + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + acs_object_type.create_type ( + supertype => 'acs_object', + object_type => 'apm_parameter_value', + pretty_name => 'APM Package Parameter Value', + pretty_plural => 'APM Package Parameter Values', + table_name => 'apm_parameter_values', + id_column => 'value_id', + package_name => 'apm_parameter_value' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter_value', + attribute_name => 'package_id', + datatype => 'number', + pretty_name => 'Package ID', + pretty_plural => 'Package IDs' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter_value', + attribute_name => 'parameter_id', + datatype => 'number', + pretty_name => 'Parameter ID', + pretty_plural => 'Parameter IDs' + ); + + attr_id := acs_attribute.create_attribute( + object_type => 'apm_parameter_value', + attribute_name => 'attr_value', + datatype => 'string', + pretty_name => 'Parameter Value', + pretty_plural => 'Parameter Values' + ); +end; +/ +show errors; + +create table apm_package_dependencies ( + dependency_id integer + constraint apm_package_deps_id_pk primary key, + version_id constraint apm_package_deps_version_id_fk references apm_package_versions on delete cascade + constraint apm_package_deps_version_id_nn not null, + dependency_type varchar2(20) + constraint apm_package_deps_type_nn not null + constraint apm_package_deps_type_ck check(dependency_type in ('provides','requires')), + service_uri varchar2(1500) + constraint apm_package_deps_uri_nn not null, + service_version varchar2(100) + constraint apm_package_deps_ver_name_nn not null, + constraint apm_package_deps_un unique(version_id, service_uri) +); + +comment on table apm_package_dependencies is ' + This table indicates what services are provided or required by a particular version. +'; + +comment on column apm_package_dependencies.service_version is ' + The restrictions on service version should match those on apm_package_versions.version_name. +'; + + +create table apm_applications ( + application_id integer + constraint applications_application_id_fk + references apm_packages(package_id) + constraint applications_pk primary key +); + +comment on table apm_applications is ' +This table records data on all of the applications registered in the ACS. +'; + + +create table apm_services ( + service_id integer + constraint services_service_id_fk + references apm_packages(package_id) + constraint services_pk primary key +); + +comment on table apm_services is ' +This table records data on all of the services registered in the ACS. +'; + + +begin +-- Create a new object type for applications. + acs_object_type.create_type ( + supertype => 'apm_package', + object_type => 'apm_application', + pretty_name => 'Application', + pretty_plural => 'Applications', + table_name => 'apm_applications', + id_column => 'application_id', + package_name => 'apm_application' + ); +end; +/ +show errors + + +begin +-- Create a new object type for services. + acs_object_type.create_type ( + supertype => 'apm_package', + object_type => 'apm_service', + pretty_name => 'Service', + pretty_plural => 'Services', + table_name => 'apm_services', + id_column => 'service_id', + package_name => 'apm_service' + ); +end; +/ +show errors + +-- Public Programmer level API. +create or replace package apm +as + procedure register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ); + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ); + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + -- Informs the APM that this application is available for use. + procedure register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ); + + -- Remove the application from the system. + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this application. + cascade_p in char default 'f' + ); + + procedure register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ); + + -- Remove the service from the system. + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this service. + cascade_p in char default 'f' + ); + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer; + + -- Remove any uses of this parameter. + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ); + + -- Return the value of this parameter for a specific package and parameter. + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + +end apm; +/ +show errors + +create or replace package apm_package +as + +function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ); + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2; + + -- Enable a package to be utilized by a subsite. + procedure enable ( + package_id in apm_packages.package_id%TYPE + ); + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ); + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE; + +end apm_package; +/ +show errors + +create or replace package 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; + + procedure delete ( + version_id in apm_packages.package_id%TYPE + ); + + procedure enable ( + version_id in apm_package_versions.version_id%TYPE + ); + + procedure disable ( + version_id in apm_package_versions.version_id%TYPE + ); + + 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; + + -- Add a file to the indicated version. + 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; + + -- 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 + ); + + -- 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; + + procedure remove_interface( + interface_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- 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; + + procedure remove_dependency( + dependency_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- Given a version_name (e.g. 3.2a), return + -- something that can be lexicographically sorted. + function sortable_version_name ( + version_name in apm_package_versions.version_name%TYPE + ) return varchar2; + + -- Given two version names, return 1 if one > two, -1 if two > one, 0 otherwise. + -- Deprecate? + 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; + + 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; + + procedure upgrade( + version_id in apm_package_versions.version_id%TYPE + ); + +end apm_package_version; +/ +show errors + +create or replace package apm_package_type +as + procedure create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ); + + function update_type ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ); + + function num_parameters ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + +end apm_package_type; +/ +show errors + + + +-- Private APM System API for managing parameter values. +create or replace package apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ); + end apm_parameter_value; +/ +show errors + +create or replace package apm_application +as + +function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + + +create or replace package apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + +create or replace package body apm +as + procedure register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm_package_type.create_type( + package_key => register_package.package_key, + pretty_name => register_package.pretty_name, + pretty_plural => register_package.pretty_plural, + package_uri => register_package.package_uri, + package_type => register_package.package_type, + singleton_p => register_package.singleton_p, + spec_file_path => register_package.spec_file_path, + spec_file_mtime => spec_file_mtime + ); + end register_package; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + + return apm_package_type.update_type( + package_key => update_package.package_key, + pretty_name => update_package.pretty_name, + pretty_plural => update_package.pretty_plural, + package_uri => update_package.package_uri, + package_type => update_package.package_type, + singleton_p => update_package.singleton_p, + spec_file_path => update_package.spec_file_path, + spec_file_mtime => update_package.spec_file_mtime + ); + + end update_package; + + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ) + is + begin + apm_package_type.drop_type( + package_key => unregister_package.package_key, + cascade_p => unregister_package.cascade_p + ); + end unregister_package; + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_register_p integer; + begin + select decode(count(*),0,0,1) into v_register_p from apm_package_types + where package_key = register_p.package_key; + return v_register_p; + end register_p; + + procedure register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm.register_package( + package_key => register_application.package_key, + pretty_name => register_application.pretty_name, + pretty_plural => register_application.pretty_plural, + package_uri => register_application.package_uri, + package_type => 'apm_application', + singleton_p => register_application.singleton_p, + spec_file_path => register_application.spec_file_path, + spec_file_mtime => register_application.spec_file_mtime + ); + end register_application; + + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_application.package_key, + cascade_p => unregister_application.cascade_p + ); + end unregister_application; + + procedure register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm.register_package( + package_key => register_service.package_key, + pretty_name => register_service.pretty_name, + pretty_plural => register_service.pretty_plural, + package_uri => register_service.package_uri, + package_type => 'apm_service', + singleton_p => register_service.singleton_p, + spec_file_path => register_service.spec_file_path, + spec_file_mtime => register_service.spec_file_mtime + ); + end register_service; + + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_service.package_key, + cascade_p => unregister_service.cascade_p + ); + end unregister_service; + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE + is + v_parameter_id apm_parameters.parameter_id%TYPE; + cursor all_parameters is + select ap.package_id, p.parameter_id, p.default_value + from apm_parameters p, apm_parameter_values v, apm_packages ap + where p.package_key = ap.package_key + and p.parameter_id = v.parameter_id (+) + and v.attr_value is null + and p.package_key = register_parameter.package_key; + begin + -- Create the new parameter. + v_parameter_id := acs_object.new( + object_id => parameter_id, + object_type => 'apm_parameter' + ); + + insert into apm_parameters + (parameter_id, parameter_name, description, package_key, datatype, + default_value, section_name, min_n_values, max_n_values) + values + (v_parameter_id, register_parameter.parameter_name, register_parameter.description, + register_parameter.package_key, register_parameter.datatype, + register_parameter.default_value, register_parameter.section_name, + register_parameter.min_n_values, register_parameter.max_n_values); + -- Propagate parameter to new instances. + for cur_val in all_parameters + loop + apm.set_value( + package_id => cur_val.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + return v_parameter_id; + end register_parameter; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE + is + begin + update apm_parameters + set parameter_name = nvl(update_parameter.parameter_name, parameter_name), + default_value = nvl(update_parameter.default_value, default_value), + datatype = nvl(update_parameter.datatype, datatype), + description = nvl(update_parameter.description, description), + section_name = nvl(update_parameter.section_name, section_name), + min_n_values = nvl(update_parameter.min_n_values, min_n_values), + max_n_values = nvl(update_parameter.max_n_values, max_n_values) + where parameter_id = update_parameter.parameter_id; + return parameter_id; + end; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer + is + v_parameter_p integer; + begin + select decode(count(*),0,0,1) into v_parameter_p + from apm_parameters + where package_key = parameter_p.package_key + and parameter_name = parameter_p.parameter_name; + return v_parameter_p; + end parameter_p; + + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ) + is + begin + delete from apm_parameter_values + where parameter_id = unregister_parameter.parameter_id; + delete from apm_parameters + where parameter_id = unregister_parameter.parameter_id; + acs_object.delete(parameter_id); + end unregister_parameter; + + function id_for_name ( + parameter_name in apm_parameters.parameter_name%TYPE, + package_key in apm_parameters.package_key%TYPE + ) return apm_parameters.parameter_id%TYPE + is + a_parameter_id apm_parameters.parameter_id%TYPE; + begin + select parameter_id into a_parameter_id + from apm_parameters p + where p.parameter_name = id_for_name.parameter_name and + p.package_key = id_for_name.package_key; + return a_parameter_id; + end id_for_name; + + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + value apm_parameter_values.attr_value%TYPE; + begin + select attr_value into value from apm_parameter_values v + where v.package_id = get_value.package_id + and parameter_id = get_value.parameter_id; + return value; + end get_value; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = get_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = get_value.package_id); + return apm.get_value( + parameter_id => v_parameter_id, + package_id => get_value.package_id + ); + end get_value; + + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + -- Determine if the value exists + select value_id into v_value_id from apm_parameter_values + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + update apm_parameter_values set attr_value = set_value.attr_value + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + exception + when NO_DATA_FOUND + then + v_value_id := apm_parameter_value.new( + package_id => set_value.package_id, + parameter_id => set_value.parameter_id, + attr_value => set_value.attr_value + ); + end set_value; + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = set_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = set_value.package_id); + apm.set_value( + parameter_id => v_parameter_id, + package_id => set_value.package_id, + attr_value => set_value.attr_value + ); + exception + when NO_DATA_FOUND + then + RAISE_APPLICATION_ERROR(-20000, 'The specified package ' || set_value.package_id || + ' does not exist in the system.'); + end set_value; +end apm; +/ +show errors + +create or replace package body apm_package +as + procedure initialize_parameters ( + package_id in apm_packages.package_id%TYPE, + package_key in apm_package_types.package_key%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + cursor cur is + select parameter_id, default_value + from apm_parameters + where package_key = initialize_parameters.package_key; + begin + -- need to initialize all params for this type + for cur_val in cur + loop + v_value_id := apm_parameter_value.new( + package_id => initialize_parameters.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + end initialize_parameters; + + function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE + is + v_singleton_p integer; + v_package_type apm_package_types.package_type%TYPE; + v_num_instances integer; + v_package_id apm_packages.package_id%TYPE; + v_instance_name apm_packages.instance_name%TYPE; + begin + v_singleton_p := apm_package.singleton_p( + package_key => apm_package.new.package_key + ); + v_num_instances := apm_package.num_instances( + package_key => apm_package.new.package_key + ); + + if v_singleton_p = 1 and v_num_instances >= 1 then + select package_id into v_package_id + from apm_packages + where package_key = apm_package.new.package_key; + return v_package_id; + else + v_package_id := acs_object.new( + object_id => package_id, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + if instance_name is null then + v_instance_name := package_key || ' ' || v_package_id; + else + v_instance_name := instance_name; + end if; + + select package_type into v_package_type + from apm_package_types + where package_key = apm_package.new.package_key; + + insert into apm_packages + (package_id, package_key, instance_name) + values + (v_package_id, package_key, v_instance_name); + + if v_package_type = 'apm_application' then + insert into apm_applications + (application_id) + values + (v_package_id); + else + insert into apm_services + (service_id) + values + (v_package_id); + end if; + + initialize_parameters( + package_id => v_package_id, + package_key => apm_package.new.package_key + ); + return v_package_id; + + end if; +end new; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ) + is + cursor all_values is + select value_id from apm_parameter_values + where package_id = apm_package.delete.package_id; + cursor all_site_nodes is + select node_id from site_nodes + where object_id = apm_package.delete.package_id; + begin + -- Delete all parameters. + for cur_val in all_values loop + apm_parameter_value.delete(value_id => cur_val.value_id); + end loop; + delete from apm_applications where application_id = apm_package.delete.package_id; + delete from apm_services where service_id = apm_package.delete.package_id; + delete from apm_packages where package_id = apm_package.delete.package_id; + -- Delete the site nodes for the objects. + for cur_val in all_site_nodes loop + site_node.delete(cur_val.node_id); + end loop; + -- Delete the object. + acs_object.delete ( + object_id => package_id + ); + end delete; + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer + is + v_singleton_p integer; + begin + select 1 into v_singleton_p + from apm_package_types + where package_key = singleton_p.package_key + and singleton_p = 't'; + return v_singleton_p; + + exception + when NO_DATA_FOUND + then + return 0; + end singleton_p; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_num_instances integer; + begin + select count(*) into v_num_instances + from apm_packages + where package_key = num_instances.package_key; + return v_num_instances; + + exception + when NO_DATA_FOUND + then + return 0; + end num_instances; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2 + is + v_result apm_packages.instance_name%TYPE; + begin + select instance_name into v_result + from apm_packages + where package_id = name.package_id; + + return v_result; + end name; + + procedure enable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 't' + where package_id = enable.package_id; + end enable; + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 'f' + where package_id = disable.package_id; + end disable; + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE + is + v_version_id apm_package_versions.version_id%TYPE; + begin + select version_id into v_version_id + from apm_package_version_info i + where apm_package_version.sortable_version_name(version_name) = + (select max(apm_package_version.sortable_version_name(v.version_name)) + from apm_package_version_info v where v.package_key = highest_version.package_key) + and package_key = highest_version.package_key; + return v_version_id; + exception + when NO_DATA_FOUND + then + return 0; + end highest_version; +end apm_package; +/ +show errors + + +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 + +create or replace package body apm_package_type +as + procedure create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ) + is + begin + insert into apm_package_types + (package_key, pretty_name, pretty_plural, package_uri, package_type, + spec_file_path, spec_file_mtime, singleton_p) + values + (create_type.package_key, create_type.pretty_name, create_type.pretty_plural, + create_type.package_uri, create_type.package_type, create_type.spec_file_path, + create_type.spec_file_mtime, create_type.singleton_p); + end create_type; + + function update_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + UPDATE apm_package_types SET + pretty_name = nvl(update_type.pretty_name, pretty_name), + pretty_plural = nvl(update_type.pretty_plural, pretty_plural), + package_uri = nvl(update_type.package_uri, package_uri), + package_type = nvl(update_type.package_type, package_type), + spec_file_path = nvl(update_type.spec_file_path, spec_file_path), + spec_file_mtime = nvl(update_type.spec_file_mtime, spec_file_mtime), + singleton_p = nvl(update_type.singleton_p, singleton_p) + where package_key = update_type.package_key; + return update_type.package_key; + end update_type; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + cursor all_package_ids is + select package_id + from apm_packages + where package_key = drop_type.package_key; + + cursor all_parameters is + select parameter_id from apm_parameters + where package_key = drop_type.package_key; + + cursor all_versions is + select version_id from apm_package_versions + where package_key = drop_type.package_key; + begin + if cascade_p = 't' then + for cur_val in all_package_ids + loop + apm_package.delete( + package_id => cur_val.package_id + ); + end loop; + -- Unregister all parameters. + for cur_val in all_parameters + loop + apm.unregister_parameter(parameter_id => cur_val.parameter_id); + end loop; + + -- Unregister all versions + for cur_val in all_versions + loop + apm_package_version.delete(version_id => cur_val.version_id); + end loop; + end if; + delete from apm_package_types + where package_key = drop_type.package_key; + end drop_type; + + function num_parameters ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_count integer; + begin + select count(*) into v_count + from apm_parameters + where package_key = num_parameters.package_key; + return v_count; + end num_parameters; + +end apm_package_type; + + +/ +show errors + +create or replace package body apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + v_value_id := acs_object.new( + object_id => value_id, + object_type => 'apm_parameter_value' + ); + insert into apm_parameter_values + (value_id, package_id, parameter_id, attr_value) + values + (v_value_id, apm_parameter_value.new.package_id, + apm_parameter_value.new.parameter_id, + apm_parameter_value.new.attr_value); + return v_value_id; + end new; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ) + is + begin + delete from apm_parameter_values + where value_id = apm_parameter_value.delete.value_id; + acs_object.delete(value_id); + end delete; + + end apm_parameter_value; +/ +show errors; + +create or replace package body apm_application +as + + function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_application_id integer; + begin + v_application_id := apm_package.new ( + package_id => application_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_application_id; + end new; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_applications + where application_id = apm_application.delete.application_id; + apm_package.delete( + package_id => application_id); + end delete; + +end; +/ +show errors + +create or replace package body apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_service_id integer; + begin + v_service_id := apm_package.new ( + package_id => service_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_service_id; + end new; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_services + where service_id = apm_service.delete.service_id; + apm_package.delete( + package_id => service_id + ); + end delete; + +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/apm-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/apm-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/apm-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,60 @@ +-- Uninstall file for the data model created by 'apm-create.sql' +-- +-- @author Bryan Quinn (bquinn) +-- @creation-date Mon Sep 18 16:46:56 2000 +-- +-- $Id: apm-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +drop package apm_service; +drop package apm_application; +drop package apm_parameter_value; +drop package apm_package_type; +drop package apm_package_version; +drop package apm_package; +drop package apm; +drop table apm_package_dependencies; +drop table apm_parameter_values; +drop table apm_parameters; +drop view apm_file_info; +drop index apm_package_files_by_version; +drop index apm_package_files_by_path; +drop table apm_package_files; +drop table apm_package_file_types; +drop view apm_enabled_package_versions; +drop view apm_package_version_info; +drop table apm_package_owners; +drop table apm_package_versions; +drop table apm_services cascade constraints; +drop table apm_applications cascade constraints; +drop table apm_packages cascade constraints; +drop table apm_package_types cascade constraints; + +begin + acs_object_type.drop_type ( + object_type => 'apm_package' + ); + + acs_object_type.drop_type ( + object_type => 'apm_application' + ); + + acs_object_type.drop_type ( + object_type => 'apm_service' + ); + + acs_object_type.drop_type ( + object_type => 'apm_package_version' + ); + + acs_object_type.drop_type ( + object_type => 'apm_parameter_value' + ); + + acs_object_type.drop_type ( + object_type => 'apm_parameter' + ); + commit; +end; +/ +show errors; Index: openacs-4/packages/acs-kernel/sql/oracle/community-core-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/community-core-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/community-core-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,675 @@ +-- +-- acs-kernel/sql/community-core-create.sql +-- +-- Abstractions fundamental to any online community (or information +-- system, in general), derived in large part from the ACS 3.x +-- community-core data model by Philip Greenspun (philg@mit.edu), from +-- the ACS 3.x user-groups data model by Tracy Adams (teadams@mit.edu) +-- from Chapter 3 (The Enterprise and Its World) of David Hay's +-- book _Data_Model_Patterns_, and from Chapter 2 (Accountability) +-- of Martin Fowler's book _Analysis_Patterns_. +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @author Rafael Schloming (rhs@mit.edu) +-- @author Jon Salz (jsalz@mit.edu) +-- +-- @creation-date 2000-05-18 +-- +-- @cvs-id $Id: community-core-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +-- HIGH PRIORITY: +-- +-- * What can subtypes add to the specification of supertype +-- attributes? Extra constraints like "not null"? What about +-- "storage"? Can a subtype override how a given attribute is +-- stored? +-- +-- * Can we realistically revoke INSERT and UPDATE permission on the +-- tables (users, persons, etc.) and make people use the PL/SQL API? +-- One downside is that it would then be difficult or impossible to +-- do things like "update ... set ... where ..." directly, without +-- creating a PL/SQL procedure to do it. +-- +-- * Figure out how to migrate from ACS 3.x users, user_groups, +-- user_group_types, etc. to ACS 4.0 objects/parties/users/organizations; +-- also need to consider general_* and site_wide_* tables +-- (Rafi and Luke) +-- +-- * Take an inventory of acs-kernel tables and other objects (some of which +-- may still be in /www/doc/sql/) and create their ACS 4 analogs, including +-- mapping over all general_* and site_wide_* data models, and make +-- appropriate adjustments to code +-- (Rafi and Yon/Luke/?). +-- +-- * Create magic users: system and anonymous (do we actually need these?) +-- +-- * Define and implement APIs +-- +-- * Figure out user classes, e.g., treat "the set of parties that +-- have relationship X to object Y" as a party in its own right +-- +-- * Explain why acs_rel_types, acs_rel_rules, and acs_rels are not +-- merely replicating the functionality of a relational database. +-- +-- * acs_attribute_type should impose some rules on the min_n_values +-- and max_n_values columns of acs_attributes, e.g., it doesn't +-- really make sense for a boolean attribute to have more than +-- one value +-- +-- * Add support for default values to acs_attributes. +-- +-- * Add support for instance-specific attributes (e.g., +-- user_group_member_fields) +-- +-- MEDIUM PRIORITY: +-- +-- * Read-only attributes? +-- +-- * Do we need to store metadata about enumerations and valid ranges +-- or should we query the Oracle data dictionary for info on check +-- constraints? +-- +-- * Create a "user_group_type" (an object_type with "organization" +-- as its supertype (do we need this?) +-- +-- * Add in ancestor permission view, assuming that we'll use a +-- magical rel_type: "acs_acl"? +-- +-- * How do we get all attribute values for objects of a specific +-- type? "We probably want some convention or standard way for +-- providing a view that joins supertypes and a type. This could +-- be automatically generated through metadata, or it could simply +-- be a convention." - Rafi +-- +-- LOW PRIORITY: +-- +-- * Formalize Rafi's definition of an "object": "A collection of rows +-- identified by an object ID for which we maintain metadata" or +-- something like that. +-- +-- * "We definitely need some standard way of extending a supertype into +-- a subtype, and 'deleting' a subtype into a supertype. This will be +-- needed when we want to transform a 'person' into a registered +-- user, and do 'nuke user' but keep around the user's contributed +-- content and associate it with the 'person' part of that user. This +-- actually works quite nicely with standard oracle inheritance since +-- you can just insert or delete a row in the subtype table and +-- mutate the object type." - Rafi +-- +-- ACS 4.1: +-- +-- * Figure out what to do with pretty names (message catalog) +-- +-- COMPLETED: +-- +-- * Create magic parties: all_users (or just use null party_id?) +-- and registered_users +-- +-- * Test out relationship attributes (making "relationship" an +-- acs_object_type) +-- +-- * Create magic object_types (object, party, person, user, +-- organization) including attrs and rels +-- +-- * Create constraints for creation_user and modifying_user + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + -- + -- Party: the supertype of person and organization + -- + acs_object_type.create_type ( + supertype => 'acs_object', + object_type => 'party', + pretty_name => 'Party', + pretty_plural => 'Parties', + table_name => 'parties', + id_column => 'party_id', + package_name => 'party', + name_method => 'party.name' + ); + + 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 + ); + + -- + -- Person: the supertype of user + -- + acs_object_type.create_type ( + supertype => 'party', + object_type => 'person', + pretty_name => 'Person', + pretty_plural => 'People', + table_name => 'persons', + id_column => 'person_id', + package_name => 'person', + name_method => 'person.name' + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'person', + attribute_name => 'first_names', + datatype => 'string', + pretty_name => 'First Names', + pretty_plural => 'First Names', + min_n_values => 0, + max_n_values => 1 + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'person', + attribute_name => 'last_name', + datatype => 'string', + pretty_name => 'Last Name', + pretty_plural => 'Last Names', + min_n_values => 0, + max_n_values => 1 + ); + + -- + -- User: people who have registered in the system + -- + acs_object_type.create_type ( + supertype => 'person', + object_type => 'user', + pretty_name => 'User', + pretty_plural => 'Users', + table_name => 'users', + id_column => 'user_id', + package_name => 'acs_user' + ); + + commit; +end; +/ +show errors + +-- ****************************************************************** +-- * OPERATIONAL LEVEL +-- ****************************************************************** + +create table parties ( + party_id not null + constraint parties_party_id_fk references + acs_objects (object_id) + constraint parties_pk primary key, + email varchar2(100) + constraint parties_email_un unique, + url varchar2(200) +); + +comment on table parties is ' + Party is the supertype of person and organization. It exists because + many other types of object can have relationships to parties. +'; + +comment on column parties.url is ' + We store url here so that we can always make party names hyperlinks + without joining to any other table. +'; + +------------------- +-- PARTY PACKAGE -- +------------------- + +create or replace package 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; + + procedure delete ( + party_id in parties.party_id%TYPE + ); + + function name ( + party_id in parties.party_id%TYPE + ) return varchar2; + +end party; +/ +show errors + + +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 + +------------- +-- PERSONS -- +------------- + +create table persons ( + person_id not null + constraint persons_person_id_fk + references parties (party_id) + constraint persons_pk primary key, + first_names varchar2(100) not null, + last_name varchar2(100) not null +); + +comment on table persons is ' + Need to handle titles like Mr., Ms., Mrs., Dr., etc. and suffixes + like M.D., Ph.D., Jr., Sr., III, IV, etc. +'; + +-------------------- +-- PERSON PACKAGE -- +-------------------- + +create or replace package person +as + + function new ( + person_id in persons.person_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'person', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + context_id in acs_objects.context_id%TYPE default null + ) return persons.person_id%TYPE; + + procedure delete ( + person_id in persons.person_id%TYPE + ); + + function name ( + person_id in persons.person_id%TYPE + ) return varchar2; + +end person; +/ +show errors + +create or replace package body person +as + + function new ( + person_id in persons.person_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'person', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + context_id in acs_objects.context_id%TYPE default null + ) + return persons.person_id%TYPE + is + v_person_id persons.person_id%TYPE; + begin + v_person_id := + party.new(person_id, object_type, + creation_date, creation_user, creation_ip, + email, url, context_id); + + insert into persons + (person_id, first_names, last_name) + values + (v_person_id, first_names, last_name); + + return v_person_id; + end new; + + procedure delete ( + person_id in persons.person_id%TYPE + ) + is + begin + delete from persons + where person_id = person.delete.person_id; + + party.delete(person_id); + end delete; + + function name ( + person_id in persons.person_id%TYPE + ) + return varchar2 + is + person_name varchar2(200); + begin + select first_names || ' ' || last_name + into person_name + from persons + where person_id = name.person_id; + + return person_name; + end name; + +end person; +/ +show errors + +create table users ( + user_id not null + constraint users_user_id_fk + references persons (person_id) + constraint users_pk primary key, + password char(40), + salt char(40), + screen_name varchar2(100) + constraint users_screen_name_un + unique, + priv_name integer default 0 not null, + priv_email integer default 5 not null, + email_verified_p char(1) default 't' + constraint users_email_verified_p_ck + check (email_verified_p in ('t', 'f')), + email_bouncing_p char(1) default 'f' not null + constraint users_email_bouncing_p_ck + check (email_bouncing_p in ('t','f')), + no_alerts_until date, + last_visit date, + second_to_last_visit date, + n_sessions integer default 1 not null, + password_question varchar2(1000), + password_answer varchar2(1000) +); + +create table user_preferences ( + user_id constraint user_prefs_user_id_fk + references users (user_id) + constraint user_preferences_pk + primary key, + prefer_text_only_p char(1) default 'f' + constraint user_prefs_pref_txt_only_p_ck + check (prefer_text_only_p in ('t','f')), + -- an ISO 639 language code (in lowercase) + language_preference char(2) default 'en', + dont_spam_me_p char(1) default 'f' + constraint user_prefs_dont_spam_me_p_ck + check (dont_spam_me_p in ('t','f')), + email_type varchar2(64) +); + +begin + + insert into acs_object_type_tables + (object_type, table_name, id_column) + values + ('user', 'user_preferences', 'user_id'); +end; +/ +show errors; + + +alter table acs_objects add ( + constraint acs_objects_creation_user_fk + foreign key (creation_user) references users(user_id), + constraint acs_objects_modifying_user_fk + foreign key (modifying_user) references users(user_id) +); + +comment on table users is ' + The creation_date and creation_ip columns inherited from acs_objects + indicate when and from where the user registered. How do we apply a + constraint ("email must not be null") to the parent type? +'; + +comment on column users.no_alerts_until is ' + For suppressing email alerts +'; + +comment on column users.last_visit is ' + Set when user reappears at site +'; + +comment on column users.second_to_last_visit is ' + This is what most pages query against (since last_visit will only be + a few minutes old for most pages in a session) +'; + +comment on column users.n_sessions is ' + How many times this user has visited +'; + +---------------------- +-- ACS_USER PACKAGE -- +---------------------- + +create or replace package acs_user +as + + function new ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't', + context_id in acs_objects.context_id%TYPE default null + ) + return users.user_id%TYPE; + + function receives_alerts_p ( + user_id in users.user_id%TYPE + ) + return char; + + procedure approve_email ( + user_id in users.user_id%TYPE + ); + + procedure unapprove_email ( + user_id in users.user_id%TYPE + ); + + procedure delete ( + user_id in users.user_id%TYPE + ); + +end acs_user; +/ +show errors + +create or replace package body acs_user +as + + function new ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't', + context_id in acs_objects.context_id%TYPE default null + ) + return users.user_id%TYPE + is + v_user_id users.user_id%TYPE; + begin + v_user_id := + person.new(user_id, object_type, + creation_date, creation_user, creation_ip, + email, url, + first_names, last_name, context_id); + + insert into users + (user_id, password, salt, password_question, password_answer, screen_name, + email_verified_p) + values + (v_user_id, password, salt, password_question, password_answer, screen_name, + email_verified_p); + + insert into user_preferences + (user_id) + values + (v_user_id); + + return v_user_id; + end new; + + function receives_alerts_p ( + user_id in users.user_id%TYPE + ) + return char + is + counter char(1); + begin + select decode(count(*),0,'f','t') into counter + from users + where no_alerts_until >= sysdate + and user_id = acs_user.receives_alerts_p.user_id; + + return counter; + + end receives_alerts_p; + + procedure approve_email ( + user_id in users.user_id%TYPE + ) + is + begin + update users + set email_verified_p = 't' + where user_id = approve_email.user_id; + end approve_email; + + + procedure unapprove_email ( + user_id in users.user_id%TYPE + ) + is + begin + update users + set email_verified_p = 'f' + where user_id = unapprove_email.user_id; + end unapprove_email; + + procedure delete ( + user_id in users.user_id%TYPE + ) + is + begin + delete from user_preferences + where user_id = acs_user.delete.user_id; + + delete from users + where user_id = acs_user.delete.user_id; + + person.delete(user_id); + end delete; + +end acs_user; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/community-core-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/community-core-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/community-core-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,25 @@ +-- +-- acs-kernel/sql/community-core-drop.sql +-- +-- DDL commands to purge the Community Core data model +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @creation-date 2000-05-18 +-- @cvs-id $Id: community-core-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +-- We need to drop the circular creation_user and modifying_user +-- references before we can drop the users table. +-- +alter table acs_objects drop constraint acs_objects_creation_user_fk; +alter table acs_objects drop constraint acs_objects_modifying_user_fk; + +drop package acs_user; +drop table user_preferences; +drop table users; + +drop package person; +drop table persons; + +drop package party; +drop table parties; Index: openacs-4/packages/acs-kernel/sql/oracle/groups-body-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/groups-body-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/groups-body-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,749 @@ +-- +-- packages/acs-kernel/sql/groups-body-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id $Id: groups-body-create.sql,v 1.1 2001/03/20 22:51:55 donb 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 'approved', + 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 = 'needs approval' + 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, + join_policy in groups.join_policy%TYPE default null, + context_id in acs_objects.context_id%TYPE default null + ) + return groups.group_id%TYPE + is + v_group_id groups.group_id%TYPE; + v_group_type_exists_p integer; + v_join_policy groups.join_policy%TYPE; + begin + v_group_id := + party.new(group_id, object_type, creation_date, creation_user, + creation_ip, email, url, context_id); + + v_join_policy := join_policy; + + -- if join policy wasn't specified, select the default based on group type + if v_join_policy is null then + select count(*) into v_group_type_exists_p + from group_types + where group_type = object_type; + + if v_group_type_exists_p = 1 then + select default_join_policy into v_join_policy + from group_types + where group_type = object_type; + else + v_join_policy := 'open'; + end if; + end if; + + insert into groups + (group_id, group_name, join_policy) + values + (v_group_id, group_name, v_join_policy); + + + -- setup the permissable 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 varchar2(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 Index: openacs-4/packages/acs-kernel/sql/oracle/groups-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/groups-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/groups-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,484 @@ +-- +-- packages/acs-kernel/sql/groups-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id $Id: groups-create.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +---------------------------- +-- GROUP TYPES AND GROUPS -- +---------------------------- + +-- NOTE: developers should not do dml to manipulate/add/delete membership +-- or composition relations. Use the APIs (the composition_rel and +-- membership_rel pl/sql packages). In particular, NEVER UPDATE object_id_one +-- and object_id_two of acs_rels, or you'll break the denormalization (see +-- the "DENORMALIZATION" section further below). + +create table composition_rels ( + rel_id constraint composition_rel_rel_id_fk + references acs_rels (rel_id) + constraint composition_rel_rel_id_pk + primary key +); + +create table membership_rels ( + rel_id constraint membership_rel_rel_id_fk + references acs_rels (rel_id) + constraint membership_rel_rel_id_pk + primary key, + member_state varchar2(20) not null + constraint membership_rel_mem_ck + check (member_state in ('approved', 'needs approval', + 'banned', 'rejected', 'deleted')) +); + +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + -- + -- Group: a composite party + -- + acs_object_type.create_type ( + supertype => 'party', + object_type => 'group', + pretty_name => 'Group', + pretty_plural => 'Groups', + table_name => 'groups', + id_column => 'group_id', + package_name => 'acs_group', + type_extension_table => 'group_types', + name_method => 'acs_group.name' + ); + + 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 + ); + + -- + -- Composition Relationship + -- + acs_rel_type.create_role ('composite', 'Composite', 'Composites'); + acs_rel_type.create_role('component', 'Component', 'Components'); + + acs_rel_type.create_type ( + rel_type => 'composition_rel', + pretty_name => 'Composition Relation', + pretty_plural => 'Composition Relationships', + table_name => 'composition_rels', + id_column => 'rel_id', + package_name => 'composition_rel', + object_type_one => 'group', role_one => 'composite', + min_n_rels_one => 0, max_n_rels_one => null, + object_type_two => 'group', role_two => 'component', + min_n_rels_two => 0, max_n_rels_two => null + ); + + -- + -- Membership Relationship + -- + acs_rel_type.create_role ('member', 'Member', 'Members'); + + acs_rel_type.create_type ( + rel_type => 'membership_rel', + pretty_name => 'Membership Relation', + pretty_plural => 'Membership Relationships', + table_name => 'membership_rels', + id_column => 'rel_id', + package_name => 'membership_rel', + object_type_one => 'group', + min_n_rels_one => 0, max_n_rels_one => null, + object_type_two => 'person', role_two => 'member', + min_n_rels_two => 0, max_n_rels_two => null + ); + + commit; +end; +/ +show errors + +create table group_types ( + group_type not null + constraint group_types_pk primary key + constraint group_types_obj_type_fk + references acs_object_types (object_type), + default_join_policy varchar2(30) default 'open' not null + constraint group_types_join_policy_ck + check (default_join_policy in + ('open', 'needs approval', 'closed')) +); + +comment on table group_types is ' + This table holds additional knowledge level attributes for the + group type and its subtypes. +'; + +create table groups ( + group_id not null + constraint groups_group_id_fk + references parties (party_id) + constraint groups_pk primary key, + group_name varchar2(100) not null, + join_policy varchar2(30) default 'open' not null + constraint groups_join_policy_ck + check (join_policy in + ('open', 'needs approval', 'closed')) +); + + + +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. +'; + + +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. +'; + + +------------------------------------------ +-- DENORMALIZATION: group_element_index -- +------------------------------------------ + +-- group_element_index is an internal mapping table maintained by the +-- parties system for optimizaiton of the views in the "VIEWS" section +-- further below. + +-- Instead of writing a complicated trigger to keep this map up to +-- date when people edit membership or composition relationships, I +-- think I'm going to make it illegal to mutate membership or +-- composition relationships, or at least the object_id_one and +-- object_id_two columns, since I don't know that it makes sense +-- anyways. Also, by making this constraint we can probably do some +-- nifty optimizaitons at some point in the future. + +-- This means, you can't edit a membership or composition relation. +-- Instead, you have to delete the relation and recreate it. By doing this, +-- we only have "on insert" and "on delete" triggers and avoid maintaining +-- the more complex "on update" trigger" + +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; + +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); + +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. +'; + + +----------- +-- VIEWS -- +----------- + +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; + +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'; + +create or replace view group_approved_member_map +as select gm.group_id, gm.member_id, gm.rel_id, gm.container_id, gm.rel_type + from group_member_map gm, membership_rels mr + where gm.rel_id = mr.rel_id + and mr.member_state = 'approved'; + +create or replace view group_distinct_member_map +as select distinct group_id, member_id + from group_approved_member_map; + +-- some more views, like party_memeber_map and party_approved_member_map, +-- are created in rel-segments-create.sql + +-- 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; + + +--------------- +-- FUNCTIONS -- +--------------- + +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 + + +------------------------ +-- TEMPORARY TRIGGERS -- +------------------------ + +-- These triggers are used to prevent people from defining membership +-- or composition relations until the groups-triggers-create file is +-- sourced. That file will replace these triggers with triggers +-- that actually do useful work + +create or replace trigger membership_rels_in_tr +after insert on membership_rels +declare +begin + raise_application_error(-20000,'Insert to membership rels not yet supported'); +end; +/ +show errors + + +create or replace trigger composition_rels_in_tr +after insert on composition_rels +declare +begin + raise_application_error(-20000,'Insert to membership rels not yet supported'); +end; +/ +show errors + + +--------------------------------------------- +-- POPULATE DATA FOR PERMISSABLE REL TYPES -- +--------------------------------------------- + +-- 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'); + + +-------------- +-- PACKAGES -- +-------------- + +create or replace package 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; + + procedure delete ( + rel_id in composition_rels.rel_id%TYPE + ); + + function check_path_exists_p ( + component_id in groups.group_id%TYPE, + container_id in groups.group_id%TYPE + ) return char; + + function check_representation ( + rel_id in composition_rels.rel_id%TYPE + ) return char; + +end composition_rel; +/ +show errors + + +create or replace package 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 'approved', + 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; + + procedure ban ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure approve ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure reject ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure unapprove ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure deleted ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure delete ( + rel_id in membership_rels.rel_id%TYPE + ); + + function check_representation ( + rel_id in membership_rels.rel_id%TYPE + ) return char; + +end membership_rel; +/ +show errors + + +create or replace package 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, + join_policy in groups.join_policy%TYPE default null, + context_id in acs_objects.context_id%TYPE default null + ) return groups.group_id%TYPE; + + procedure delete ( + group_id in groups.group_id%TYPE + ); + + function name ( + group_id in groups.group_id%TYPE + ) return varchar2; + + function member_p ( + party_id in parties.party_id%TYPE + ) return char; + + function check_representation ( + group_id in groups.group_id%TYPE + ) return char; + +end acs_group; +/ +show errors + Index: openacs-4/packages/acs-kernel/sql/oracle/groups-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/groups-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/groups-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,26 @@ +- +-- packages/acs-kernel/sql/groups-drop.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id $Id: groups-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +drop package acs_group; +drop function group_contains_p; +drop view group_distinct_member_map; +drop view group_approved_member_map; +drop view group_member_index; +drop view group_component_index; +drop view group_member_map; +drop view group_component_map; +drop view group_element_map; +drop table group_element_index; +drop table group_type_rels; +drop table group_rels; +drop table groups; +drop package composition_rel; +drop package membership_rel; +drop table composition_rels; +drop table membership_rels; +drop table group_types; Index: openacs-4/packages/acs-kernel/sql/oracle/journal-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/journal-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/journal-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,135 @@ +-- Data model to keep a journal of all actions on objects. +-- +-- +-- @author Lars Pind (lars@pinds.com) +-- @creation-date 2000-22-18 +-- @cvs-id $Id: journal-create.sql,v 1.1 2001/03/20 22:51:55 donb 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 + + +begin + acs_object_type.create_type( + object_type => 'journal_entry', + pretty_name => 'Journal Entry', + pretty_plural => 'Journal Entries', + table_name => 'journal_entries', + id_column => 'journal_id', + package_name => 'journal_entry' + ); + + -- XXX fill in all the attributes in later. +end; +/ +show errors + +create table journal_entries ( + journal_id constraint journal_entries_journal_id_fk + references acs_objects (object_id) + constraint journal_entries_pk + primary key, + object_id integer + constraint journal_entries_object_fk + references acs_objects on delete cascade, + action varchar2(100), + action_pretty varchar2(4000), + msg varchar2(4000) +); + +create index journal_entries_object_idx on journal_entries (object_id); + +comment on table journal_entries is ' + Keeps track of actions performed on objects, e.g. banning a user, + starting or finishing a workflow task, etc. +'; + + +create or replace package journal_entry +as + + function new ( + journal_id in journal_entries.journal_id%TYPE default null, + object_id in journal_entries.object_id%TYPE, + action in journal_entries.action%TYPE, + action_pretty in journal_entries.action_pretty%TYPE default null, + 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, + msg in journal_entries.msg%TYPE default null + ) return journal_entries.journal_id%TYPE; + + procedure delete( + journal_id in journal_entries.journal_id%TYPE + ); + + procedure delete_for_object( + object_id in acs_objects.object_id%TYPE + ); + +end journal_entry; +/ +show errors; + +create or replace package body journal_entry +as + + function new ( + journal_id in journal_entries.journal_id%TYPE default null, + object_id in journal_entries.object_id%TYPE, + action in journal_entries.action%TYPE, + action_pretty in journal_entries.action_pretty%TYPE, + 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, + msg in journal_entries.msg%TYPE default null + ) return journal_entries.journal_id%TYPE + is + v_journal_id journal_entries.journal_id%TYPE; + begin + v_journal_id := acs_object.new ( + object_id => journal_id, + object_type => 'journal_entry', + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => object_id + ); + + insert into journal_entries ( + journal_id, object_id, action, action_pretty, msg + ) values ( + v_journal_id, object_id, action, action_pretty, msg + ); + + return v_journal_id; + end new; + + procedure delete( + journal_id in journal_entries.journal_id%TYPE + ) + is + begin + delete from journal_entries where journal_id = journal_entry.delete.journal_id; + acs_object.delete(journal_entry.delete.journal_id); + end delete; + + procedure delete_for_object( + object_id in acs_objects.object_id%TYPE + ) + is + cursor journal_cur is + select journal_id from journal_entries where object_id = delete_for_object.object_id; + begin + for journal_rec in journal_cur loop + journal_entry.delete(journal_rec.journal_id); + end loop; + end delete_for_object; + +end journal_entry; +/ +show errors; + Index: openacs-4/packages/acs-kernel/sql/oracle/journal-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/journal-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/journal-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,20 @@ +-- +-- acs-kernel/sql/acs-objects-drop.sql +-- +-- DDL commands to purge the ACS Objects data model +-- +-- @author Lars Pind (lars@pinds.com) +-- @creation-date 2000-22-18 +-- @cvs-id $Id: journal-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ +-- + +begin + acs_object_type.drop_type( + object_type => 'journal_entry' + ); +end; +/ +show errors + +drop package journal_entry; +drop table journal_entries; Index: openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-body-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-body-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-body-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,155 @@ +-- +-- /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: rel-constraints-body-create.sql,v 1.1 2001/03/20 22:51:55 donb 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 Index: openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,489 @@ +-- +-- /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: rel-constraints-create.sql,v 1.1 2001/03/20 22:51:55 donb 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; + + +-- 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; + + +-- View: rc_all_constraints +-- +-- Question: Given group :group_id and rel_type :rel_type . . . +-- +-- What segments must a party be in +-- if the party were to be on side :rel_side of a relation of +-- type :rel_type to group :group_id ? +-- +-- Answer: select required_rel_segment +-- from rc_all_constraints +-- where group_id = :group_id +-- and rel_type = :rel_type +-- and rel_side = :rel_side +-- +-- Notes: we take special care not to get identity rows, where group_id and +-- rel_type are equivalent to segment_id. This can happen if there are some +-- funky constraints in the system, such as membership to Arsdigita requires +-- user_profile to Arsdigita. Then you could get rows from the +-- rc_all_constraints view saying that: +-- user_profile to Arsdigita +-- requires being in the segment of Arsdigita Users. +-- +-- This happens because user_profile is a type of memebrship, and there's a +-- constraint saying that membership to Arsdigita requires being in the +-- Arsdigita Users segment. We eliminate such rows from the rc_all_constraints +-- view with the "not (...)" clause below. +-- +create or replace view rc_all_constraints as +select group_rel_types.group_id, + group_rel_types.rel_type, + rel_constraints.rel_segment, + rel_constraints.rel_side, + required_rel_segment + from rel_constraints, + rel_segment_group_rel_type_map group_rel_types, + rel_segments req_seg + where rel_constraints.rel_segment = group_rel_types.segment_id + and rel_constraints.required_rel_segment = req_seg.segment_id + and not (req_seg.group_id = group_rel_types.group_id and + req_seg.rel_type = group_rel_types.rel_type); + +create or replace view rc_all_distinct_constraints as +select distinct + group_id, rel_type, rel_segment, rel_side, required_rel_segment +from rc_all_constraints; + + +-- THIS VIEW IS FOR COMPATIBILITY WITH EXISTING CODE +-- New code should use rc_all_constraints instead! +-- +-- 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 distinct group_id, rel_type, required_rel_segment +from rc_all_constraints +where 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_combos.group_id, + group_rel_type_combos.rel_type, + parties.party_id +from rc_required_rel_segments, + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type from acs_object_types + start with object_type = 'membership_rel' + or object_type = 'composition_rel' + connect by supertype = prior object_type) comp_or_member_rel_types + ) group_rel_type_combos, + parties +where rc_required_rel_segments.group_id(+) = group_rel_type_combos.group_id + and rc_required_rel_segments.rel_type(+) = group_rel_type_combos.rel_type + and rc_required_rel_segments.group_id is null; + + +-- View: rc_valid_rel_types +-- +-- Question: What types of membership or composition are "valid" +-- for group :group_id ? A membership or composition +-- type R is "valid" when no relational constraints would +-- be violated if a party were to belong to group :group_id +-- through a rel of type R. +-- +-- Answer: select rel_type +-- from rc_valid_rel_types +-- where group_id = :group_id +-- +-- +create or replace view rc_valid_rel_types as +select side_one_constraints.group_id, + side_one_constraints.rel_type + from (select required_segs.group_id, + required_segs.rel_type, + count(*) as num_satisfied + from rc_all_constraints required_segs, + rel_segment_party_map map + where required_segs.rel_side = 'one' + and required_segs.required_rel_segment = map.segment_id + and required_segs.group_id = map.party_id + group by required_segs.group_id, + required_segs.rel_type) side_one_constraints, + (select group_id, rel_type, count(*) as total + from rc_all_constraints + where rel_side = 'one' + group by group_id, rel_type) total_side_one_constraints + where side_one_constraints.group_id = total_side_one_constraints.group_id + and side_one_constraints.rel_type = total_side_one_constraints.rel_type + and side_one_constraints.num_satisfied = total_side_one_constraints.total +UNION ALL +select group_rel_type_combos.group_id, + group_rel_type_combos.rel_type +from (select * from rc_all_constraints where rel_side='one') rc_all_constraints, + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type from acs_object_types + start with object_type = 'membership_rel' + or object_type = 'composition_rel' + connect by supertype = prior object_type) comp_or_member_rel_types + ) group_rel_type_combos +where rc_all_constraints.group_id(+) = group_rel_type_combos.group_id + and rc_all_constraints.rel_type(+) = group_rel_type_combos.rel_type + and rc_all_constraints.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.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, r.object_id_two + 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 r.object_id_two = s.object_id_two + and cons.rel_segment = map.segment_id + and cons.required_rel_segment = s.segment_id; + + +-- View: rc_segment_required_seg_map +-- +-- Question: Given a relational segment :rel_segment . . . +-- +-- What are all the segments in the system that a party has to +-- be in if the party were to be on side :rel_side of a relation +-- in segement :rel_segment? +-- +-- We want not only the direct required_segments (which we could +-- get from the rel_constraints table directly), but also the +-- indirect ones (i.e., the segments that are required by the +-- required segments, and so on). +-- +-- Answer: select required_rel_segment +-- from rc_segment_required_seg_map +-- where rel_segment = :rel_segment +-- and rel_side = :rel_side +-- +-- +create or replace view rc_segment_required_seg_map as +select rc.rel_segment, rc.rel_side, rc_required.required_rel_segment +from rel_constraints rc, rel_constraints rc_required +where rc.rel_segment in ( + select rel_segment + from rel_constraints + start with rel_segment = rc_required.rel_segment + connect by required_rel_segment = prior rel_segment + and prior rel_side = 'two' + ); + +-- View: rc_segment_dependency_levels +-- +-- This view is designed to determine what order of segments is safe +-- to use when adding a party to multiple segments. +-- +-- Question: Given a table or view called segments_I_want_to_be_in, +-- which segments can I add a party to first, without violating +-- any relational constraints? +-- +-- Answer: select segment_id +-- from segments_I_want_to_be_in s, +-- rc_segment_dependency_levels dl +-- where s.segment_id = dl.segment_id(+) +-- order by nvl(dl.dependency_level, 0) +-- +-- Note: dependency_level = 1 is the minimum dependency level. +-- dependency_level = N means that you cannot add a party to the +-- segment until you first add the party to some +-- segment of dependency_level N-1 (this view doesn't +-- tell you which segment -- you can get that info +-- from rel_constraints table or other views. +-- +-- Another Note: not all segemnts in rel_segemnts are returned by this view. +-- This view only returns segments S that have at least one rel_constraints row +-- where rel_segment = S. Segments that have no constraints defined on them +-- can be said to have dependency_level=0, hence the outer join and nvl in the +-- example query above (see "Answer:"). I could have embeded that logic into +-- this view, but that would unnecessarily degrade performance. +-- +create or replace view rc_segment_dependency_levels as + select rel_segment as segment_id, + max(tree_level) as dependency_level + from (select rel_segment, level as tree_level + from rel_constraints + connect by required_rel_segment = prior rel_segment + and prior rel_side = 'two') + group by rel_segment +; + + +-------------- +-- PACKAGES -- +-------------- + +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 precense 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 Index: openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/rel-constraints-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,21 @@ +-- +-- /packages/acs-kernel/sql/rel-constraints-drop.sql +-- +-- @author Oumi Mehrotra +-- @creation-date 2000-11-22 +-- @cvs-id $Id: rel-constraints-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ + + +begin +acs_rel_type.drop_type('rel_constraint'); +end; +/ +show errors + +drop view rel_constraints_violated_one; +drop view rel_constraints_violated_two; +drop view rc_required_rel_segments; +drop view rc_parties_in_required_segs; +drop view rc_violations_by_removing_rel; +drop table rel_constraints; +drop package rel_constraint; Index: openacs-4/packages/acs-kernel/sql/oracle/rel-segments-body-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/rel-segments-body-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/rel-segments-body-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,159 @@ +-- +-- packages/acs-kernel/sql/rel-segments-create.sql +-- +-- @author Oumi Mehrotra oumi@arsdigita.com +-- @creation-date 2000-11-22 +-- @cvs-id $Id: rel-segments-body-create.sql,v 1.1 2001/03/20 22:51:55 donb 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 + Index: openacs-4/packages/acs-kernel/sql/oracle/rel-segments-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/rel-segments-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/rel-segments-create.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,273 @@ +-- +-- packages/acs-kernel/sql/rel-segments-create.sql +-- +-- @author Oumi Mehrotra oumi@arsdigita.com +-- @creation-date 2000-11-22 +-- @cvs-id $Id: rel-segments-create.sql,v 1.1 2001/03/20 22:51:55 donb 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, + group_element_map gem + where gem.group_id = rs.group_id + and rs.rel_type in (select object_type + from acs_object_types + start with object_type = gem.rel_type + connect by prior supertype = object_type); + + +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 /*+ ordered */ + rs.segment_id, gem.element_id as member_id, gem.rel_id, gem.rel_type, + gem.group_id, gem.container_id + from membership_rels mr, group_element_map gem, rel_segments rs + where rs.group_id = gem.group_id + and rs.rel_type in (select object_type + from acs_object_types + start with object_type = gem.rel_type + connect by prior supertype = object_type) + and mr.rel_id = gem.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; + +-- View: rel_segment_group_rel_type_map +-- +-- Result Set: the set of triples (:segment_id, :group_id, :rel_type) such that +-- +-- IF a party were to be in :group_id +-- through a relation of type :rel_type, +-- THEN the party would necessarily be in segment :segemnt_id. +-- +-- +create or replace view rel_segment_group_rel_type_map as +select s.segment_id, + gcm.component_id as group_id, + acs_rel_types.rel_type as rel_type +from rel_segments s, + (select group_id, component_id + from group_component_map + UNION ALL + select group_id, group_id as component_id + from groups) gcm, + acs_rel_types +where s.group_id = gcm.group_id + and s.rel_type in (select object_type from acs_object_types + start with object_type = acs_rel_types.rel_type + connect by prior supertype = object_type); + Index: openacs-4/packages/acs-kernel/sql/oracle/rel-segments-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/rel-segments-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/rel-segments-drop.sql 20 Mar 2001 22:51:55 -0000 1.1 @@ -0,0 +1,30 @@ +-- +-- packages/acs-kernel/sql/rel-segments-drop.sql +-- +-- @author oumi@arsdigita.com +-- @creation-date 2000-11-22 +-- @cvs-id $Id: rel-segments-drop.sql,v 1.1 2001/03/20 22:51:55 donb Exp $ + + +begin + for r in (select segment_id from rel_segments) loop + rel_segment.delete(r.segment_id); + end loop; + + acs_object_type.drop_type('rel_segment'); +end; +/ +show errors + + +drop view party_element_map; +drop view party_approved_member_map; +drop view party_member_map; +drop view rel_seg_distinct_member_map; +drop view rel_seg_approved_member_map; +drop view rel_segment_member_map; +drop view rel_segment_distinct_party_map; +drop view rel_segment_party_map; +drop index rel_segments_rel_type_idx; +drop table rel_segments; +drop package rel_segment; Index: openacs-4/packages/acs-kernel/sql/oracle/security-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/security-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/security-create.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,53 @@ +-- +-- /packages/acs-kernel/sql/security-create.sql +-- +-- ACS Security data model +-- +-- @author Jon Salz (jsalz@mit.edu) +-- @author Kai Wu (kai@arsdigita.com) +-- @author Richard Li (richardl@arsdigita.com) +-- +-- @creation-date 2000/02/02 +-- @cvs-id $Id: security-create.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ + +create table sec_session_properties ( + session_id integer + constraint sec_session_prop_session_id_nn + not null, + module varchar2(50) + constraint sec_session_prop_module_nn + not null, + property_name varchar2(50) + constraint sec_session_prop_prop_name_nn + not null, + property_value varchar2(4000), + -- transmitted only across secure connections? + secure_p char(1) + constraint sec_session_prop_secure_p_ck + check(secure_p in ('t','f')), + last_hit integer + constraint sec_session_date_nn + not null, + primary key(session_id, module, property_name) +) nologging storage ( + initial 50m + next 50m + pctincrease 0) + parallel; + +create index sec_property_names on sec_session_properties(property_name); + +create table secret_tokens ( + token_id integer + constraint secret_tokens_token_id_pk primary key, + token char(40), + timestamp date +); + +create sequence sec_security_token_id_seq cache 100; + +-- Due to the nature of DDL, the increment by 100 parameter needs to +-- be hard-coded into the sec_allocate_session procedure. Don't change +-- the increment here without changing the procedure! + +create sequence sec_id_seq cache 100 increment by 100; Index: openacs-4/packages/acs-kernel/sql/oracle/security-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/security-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/security-drop.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,15 @@ +-- +-- /packages/acs-kernel/sql/security-drop.sql +-- +-- DDL statements to purge the Security data model +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- @creation-date 2000-07-27 +-- @cvs-id $Id: security-drop.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +drop sequence sec_id_seq; +drop sequence sec_security_token_id_seq; +drop table sec_session_properties; +drop index sec_sessions_by_server; +drop table secret_tokens; Index: openacs-4/packages/acs-kernel/sql/oracle/site-nodes-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/site-nodes-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/site-nodes-create.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,258 @@ +-- +-- packages/acs-kernel/sql/site-nodes-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-09-05 +-- @cvs-id $Id: site-nodes-create.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +begin + acs_object_type.create_type ( + object_type => 'site_node', + pretty_name => 'Site Node', + pretty_plural => 'Site Nodes', + table_name => 'site_nodes', + id_column => 'node_id', + package_name => 'site_node' + ); +end; +/ +show errors + +-- This table allows urls to be mapped to a node_ids. + +create table site_nodes ( + node_id constraint site_nodes_node_id_fk + references acs_objects (object_id) + constraint site_nodes_node_id_pk + primary key, + parent_id constraint site_nodes_parent_id_fk + references site_nodes (node_id), + name varchar2(100) + constraint site_nodes_name_ck + check (name not like '%/%'), + constraint site_nodes_un + unique (parent_id, name), + -- Is it legal to create a child node? + directory_p char(1) not null + constraint site_nodes_directory_p_ck + check (directory_p in ('t', 'f')), + -- Should urls that are logical children of this node be + -- mapped to this node? + pattern_p char(1) default 'f' not null + constraint site_nodes_pattern_p_ck + check (pattern_p in ('t', 'f')), + object_id constraint site_nodes_object_id_fk + references acs_objects (object_id) +); + +create index site_nodes_object_id_idx on site_nodes (object_id); + +create or replace package site_node +as + + -- Create a new site node. If you set directory_p to be 'f' then you + -- cannot create nodes that have this node as their parent. + + function new ( + node_id in site_nodes.node_id%TYPE default null, + parent_id in site_nodes.node_id%TYPE default null, + name in site_nodes.name%TYPE, + object_id in site_nodes.object_id%TYPE default null, + directory_p in site_nodes.directory_p%TYPE, + pattern_p in site_nodes.pattern_p%TYPE default 'f', + creation_user in acs_objects.creation_user%TYPE default null, + creation_ip in acs_objects.creation_ip%TYPE default null + ) return site_nodes.node_id%TYPE; + + -- Delete a site node. + + procedure delete ( + node_id in site_nodes.node_id%TYPE + ); + + -- Return the node_id of a url. If the url begins with '/' then the + -- parent_id must be null. This will raise the no_data_found + -- exception if there is no mathing node in the site_nodes table. + -- This will match directories even if no trailing slash is included + -- in the url. + + function node_id ( + url in varchar2, + parent_id in site_nodes.node_id%TYPE default null + ) return site_nodes.node_id%TYPE; + + -- Return the url of a node_id. + + function url ( + node_id in site_nodes.node_id%TYPE + ) return varchar2; + +end; +/ +show errors + +create or replace package body site_node +as + + function new ( + node_id in site_nodes.node_id%TYPE default null, + parent_id in site_nodes.node_id%TYPE default null, + name in site_nodes.name%TYPE, + object_id in site_nodes.object_id%TYPE default null, + directory_p in site_nodes.directory_p%TYPE, + pattern_p in site_nodes.pattern_p%TYPE default 'f', + creation_user in acs_objects.creation_user%TYPE default null, + creation_ip in acs_objects.creation_ip%TYPE default null + ) return site_nodes.node_id%TYPE + is + v_node_id site_nodes.node_id%TYPE; + v_directory_p site_nodes.directory_p%TYPE; + begin + if parent_id is not null then + select directory_p into v_directory_p + from site_nodes + where node_id = new.parent_id; + + if v_directory_p = 'f' then + raise_application_error ( + -20000, + 'Node ' || parent_id || ' is not a directory' + ); + end if; + end if; + + v_node_id := acs_object.new ( + object_id => node_id, + object_type => 'site_node', + creation_user => creation_user, + creation_ip => creation_ip + ); + + insert into site_nodes + (node_id, parent_id, name, object_id, directory_p, pattern_p) + values + (v_node_id, new.parent_id, new.name, new.object_id, + new.directory_p, new.pattern_p); + + return v_node_id; + end; + + procedure delete ( + node_id in site_nodes.node_id%TYPE + ) + is + begin + delete from site_nodes + where node_id = site_node.delete.node_id; + + acs_object.delete(node_id); + end; + + function find_pattern ( + node_id in site_nodes.node_id%TYPE + ) return site_nodes.node_id%TYPE + is + v_pattern_p site_nodes.pattern_p%TYPE; + v_parent_id site_nodes.node_id%TYPE; + begin + if node_id is null then + raise no_data_found; + end if; + + select pattern_p, parent_id into v_pattern_p, v_parent_id + from site_nodes + where node_id = find_pattern.node_id; + + if v_pattern_p = 't' then + return node_id; + else + return find_pattern(v_parent_id); + end if; + end; + + function node_id ( + url in varchar2, + parent_id in site_nodes.node_id%TYPE default null + ) return site_nodes.node_id%TYPE + is + v_pos integer; + v_first site_nodes.name%TYPE; + v_rest varchar2(4000); + v_node_id integer; + v_pattern_p site_nodes.pattern_p%TYPE; + v_url varchar2(4000); + v_directory_p site_nodes.directory_p%TYPE; + v_trailing_slash_p char(1); + begin + v_url := url; + + if substr(v_url, length(v_url), 1) = '/' then + -- It ends with a / so it must be a directory. + v_trailing_slash_p := 't'; + v_url := substr(v_url, 1, length(v_url) - 1); + end if; + + v_pos := 1; + + while v_pos <= length(v_url) and substr(v_url, v_pos, 1) != '/' loop + v_pos := v_pos + 1; + end loop; + + if v_pos = length(v_url) then + v_first := v_url; + v_rest := null; + else + v_first := substr(v_url, 1, v_pos - 1); + v_rest := substr(v_url, v_pos + 1); + end if; + + begin + -- Is there a better way to do these freaking null compares? + select node_id, directory_p into v_node_id, v_directory_p + from site_nodes + where nvl(parent_id, 3.14) = nvl(site_node.node_id.parent_id, 3.14) + and nvl(name, chr(10)) = nvl(v_first, chr(10)); + exception + when no_data_found then + return find_pattern(parent_id); + end; + + if v_rest is null then + if v_trailing_slash_p = 't' and v_directory_p = 'f' then + return find_pattern(parent_id); + else + return v_node_id; + end if; + else + return node_id(v_rest, v_node_id); + end if; + end; + + function url ( + node_id in site_nodes.node_id%TYPE + ) return varchar2 + is + v_parent_id site_nodes.node_id%TYPE; + v_name site_nodes.name%TYPE; + v_directory_p site_nodes.directory_p%TYPE; + begin + if node_id is null then + return ''; + end if; + + select parent_id, name, directory_p into + v_parent_id, v_name, v_directory_p + from site_nodes + where node_id = url.node_id; + + if v_directory_p = 't' then + return url(v_parent_id) || v_name || '/'; + else + return url(v_parent_id) || v_name; + end if; + end; + +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/site-nodes-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/site-nodes-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/site-nodes-drop.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,16 @@ +-- +-- packages/acs-kernel/sql/site-nodes-drop.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-09-06 +-- @cvs-id $Id: site-nodes-drop.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +drop package site_node; +drop table site_nodes; + +begin + acs_object_type.drop_type ('site_node'); +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/utilities-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/utilities-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/utilities-create.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,95 @@ +-- +-- /packages/acs-kernel/sql/utilities-create.sql +-- +-- Useful PL/SQL utility routines. +-- +-- @author Jon Salz (jsalz@mit.edu) +-- @creation-date 12 Aug 2000 +-- @cvs-id $Id: utilities-create.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +create or replace package util +as + function multiple_nextval( + v_sequence_name in varchar2, + v_count in integer) + return varchar2; + + function computehash_raw( + v_value IN varchar2 ) + return raw; + + function computehash( + v_value IN varchar2) + return varchar2; + + function logical_negation ( + true_or_false IN varchar2) + return varchar2; +end util; +/ +show errors + +create or replace package body util +as + -- Retrieves v_count (not necessarily consecutive) nextval values from the + -- sequence named v_sequence_name. + function multiple_nextval( + v_sequence_name in varchar2, + v_count in integer + ) + return varchar2 + is + a_sequence_values varchar2(4000); + begin + execute immediate ' + declare + a_nextval integer; + begin + for counter in 1..:v_count loop + select ' || v_sequence_name || '.nextval into a_nextval from dual; + :a_sequence_values := :a_sequence_values || '','' || a_nextval; + end loop; + end; + ' using in v_count, in out a_sequence_values; + return substr(a_sequence_values, 2); + end; + + -- This is for Password Hashing. + -- Make sure to run: 'loadjava -user username/password Security.class' + -- before running this. + -- Make sure you have javasyspriv and javauserpriv granted for the user. + + function computehash_raw( v_value IN varchar2 ) + return raw + as language java + name 'Security.computeSHA(java.lang.String) returns java.lang.byte[]'; + + -- The hashing function can be changed to MD5 by using computeMD5. + + function computehash (v_value IN varchar2) + return varchar2 + as + v_hashed char(40); + begin + select RAWTOHEX(computehash_raw(v_value)) into v_hashed from dual; + return v_hashed; + end computehash; + + function logical_negation ( + true_or_false IN varchar2) + return varchar2 + as + begin + IF true_or_false is null THEN + return null; + ELSIF true_or_false = 'f' THEN + return 't'; + ELSE + return 'f'; + END IF; + END logical_negation; + +end util; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/utilities-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/utilities-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/utilities-drop.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,11 @@ +-- +-- /packages/acs-kernel/sql/utilities-drop.sql +-- +-- Purges useful PL/SQL utility routines. +-- +-- @author Jon Salz (jsalz@mit.edu) +-- @creation-date 12 Aug 2000 +-- @cvs-id $Id: utilities-drop.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +drop package util; Index: openacs-4/packages/acs-kernel/sql/oracle/test/acs-objects-test.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test/acs-objects-test.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test/acs-objects-test.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,298 @@ +-- +-- acs-kernel/sql/acs-objects-test.sql +-- +-- PL/SQL regression tests for the acs-objects system +-- +-- Note: These tests use the utPLSQL regression package available at: +-- ftp://ftp.oreilly.com/published/oreilly/oracle/utplsql/utplsql.zip +-- +-- @author Richard Li (richardl@arsdigita.com) +-- +-- @creation-date 19 September 2000 +-- +-- @cvs-id $Id: acs-objects-test.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ + +-- In order for utPLSQL to work, you need to grant +-- specific permissions to your user: +-- +-- grant create public synonym to servicename; +-- grant drop public synonym to servicename; +-- grant execute on dbms_pipe to servicename; +-- grant drop any table to servicename; +-- grant create any table to servicename; + +-- In order to execute the test, you need to set things up +-- in your SQL*PLUS session. First type: +-- +-- set serveroutput on size 1000000 format wrapped +-- +-- Now, if you have the UTL_FILE PL/SQL package installed, type: +-- +-- exec utplsql.setdir('/web/richard/packages/acs-kernel/sql'); +-- +-- Otherwise, you'll have to disable autocompilation and manually +-- compile: +-- +-- exec utplsql.autocompile (false); +-- @acs-objects-test +-- +-- To actually execute the test, type: +-- +-- exec utplsql.test('acs_object'); + + +-- we need these here or else the PL/SQL won't compile. +drop table ut_acs_objects; +create table ut_acs_objects as select * from acs_objects; +create table test_objects (test_id integer primary key, data varchar2(100)); + +create or replace package ut#acs_object +as + + procedure setup; + + procedure teardown; + + procedure new; + + procedure delete; + + procedure name; + + procedure default_name; + + procedure set_attribute; + + procedure get_attribute; + +end ut#acs_object; +/ +show errors + +create or replace package body ut#acs_object +as + + procedure setup + is + attr_id acs_attributes.attribute_id%TYPE; + begin + teardown; + dbms_output.put_line('Setting up...'); + + -- create a copy of the table + execute immediate 'create table ut_acs_objects as + select * from acs_objects'; + + execute immediate 'create table test_objects (test_id integer primary key, data varchar2(100))'; + + -- create the test_object type + acs_object_type.create_type ( + supertype => 'acs_object', + object_type => 'test_object', + pretty_name => 'Test Object', + pretty_plural => 'Test Objects', + table_name => 'test_objects', + id_column => 'test_id' + ); + + -- no API available for this yet + insert into acs_object_type_tables (object_type, table_name, id_column) + values ('test_object','test_objects','test_id'); + + -- create the attribute + attr_id := acs_attribute.create_attribute ( + object_type => 'test_object', + attribute_name => 'data', + pretty_name => 'Data', + pretty_plural => 'Mo Data', + datatype => 'string', + table_name => 'test_objects', + column_name => 'data' + ); + + utplsql.setpkg('acs_object'); + utplsql.addtest('new'); + utplsql.addtest('delete'); + utplsql.addtest('name'); + utplsql.addtest('default_name'); + utplsql.addtest('set_attribute'); + utplsql.addtest('get_attribute'); + end; + + procedure teardown + is + begin + dbms_output.put_line('Tearing down...'); + -- delete the test object + delete from acs_attributes where object_type = 'test_object'; + delete from acs_objects where object_type = 'test_object'; + delete from acs_object_type_tables where object_type = 'test_object'; + + begin + execute immediate 'drop table test_objects'; + exception + when others + then + null; + end; + + -- clean out the test data + begin + execute immediate 'drop table ut_acs_objects'; + exception + when others + then + null; + end; + + -- delete the object_type + delete from acs_object_types where object_type = 'test_object'; + end; + + procedure new + is + begin + dbms_output.put_line('Testing new...'); + -- Tests just the common functionality of the API. + + utassert.eq ( + msg_in => 'Creating a new test object', + check_this_in => acs_object.new(object_id => -1000, object_type => 'test_object'), + against_this_in => -1000 + ); + + -- create an object + insert into ut_acs_objects(object_id, object_type, creation_date, security_inherit_p, last_modified) + values(-1000, 'test_object', sysdate, 't', sysdate); + + -- Verify that the API does the correct insert. + utassert.eqtable ( + msg_in => 'Comparing created data for object', + check_this_in => 'acs_objects', + against_this_in => 'ut_acs_objects' + ); + + utresult.show; + + end; + + procedure delete + is + begin + dbms_output.put_line('Testing delete...'); + + -- create a new object to delete; note that this test assumes that + -- the .new operator works. + utassert.eq ( + msg_in => 'Creating a new test object', + check_this_in => acs_object.new(object_id => -1001, object_type => 'test_object'), + against_this_in => -1001 + ); + + -- delete the row. + acs_object.delete(object_id => -1001); + + -- verify object not there. + utassert.eqtable ( + msg_in => 'Delete verification', + check_this_in => 'acs_objects', + against_this_in => 'ut_acs_objects' + ); + + utresult.show; + + end; + + procedure name + is + begin + dbms_output.put_line('Testing name...'); + + utassert.eq ( + msg_in => 'Creating a name', + check_this_in => acs_object.name(object_id => -1000), + against_this_in => 'Test Object -1000' + ); + + utresult.show; + + end; + + procedure default_name + is + begin + dbms_output.put_line('Testing default_name...'); + + utassert.eq ( + msg_in => 'Creating a name', + check_this_in => acs_object.default_name(object_id => -1000), + against_this_in => 'Test Object -1000' + ); + + utresult.show; + + end; + + procedure set_attribute + is + v_sql_result test_objects.data%TYPE; + begin + dbms_output.put_line('Testing set_attribute'); + + utassert.eq ( + msg_in => 'Creating a new test object', + check_this_in => acs_object.new(object_id => -1003, object_type => 'test_object'), + against_this_in => -1003 + ); + + -- since we didn't create a test object new constructor + -- we're going to insert into attributes here. + insert into test_objects(test_id) values(-1003); + + acs_object.set_attribute(object_id_in => -1003, + attribute_name_in => 'data', + value_in => '2702'); + + -- since utassert isn't powerful enough right now, we do this + -- comparison manually + select data into v_sql_result from test_objects where test_id = -1003; + + if v_sql_result = 2702 then + dbms_output.put_line('SUCCESS: set_attribute'); + else + dbms_output.put_line('Verifying attribute data FAILED'); + end if; + + utresult.show; + + end; + + procedure get_attribute + is + v_attr_value varchar2(4000); + begin + dbms_output.put_line('Testing get_attribute'); + + -- we assume that set attribute works. since i'm lazy + -- i'm going to recycle the -1003 object. + acs_object.set_attribute(object_id_in => -1003, + attribute_name_in => 'data', + value_in => 'sugarwen'); + + v_attr_value := acs_object.get_attribute(object_id_in => -1003, + attribute_name_in => 'data'); + + if v_attr_value = 'sugarwen' then + dbms_output.put_line('SUCCESS: get_attribute'); + else + dbms_output.put_line('Verifying get attribute data FAILED'); + end if; + + utresult.show; + + end; + +end ut#acs_object; +/ +show errors + Index: openacs-4/packages/acs-kernel/sql/oracle/test/groups-test.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test/groups-test.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test/groups-test.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,119 @@ +-- +-- packages/acs-kernel/sql/test/groups-test.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-10-07 +-- @cvs-id $Id: groups-test.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +set serveroutput on + +declare + A integer; + B integer; + C integer; + D integer; + E integer; + F integer; + G integer; + + joe integer; + jane integer; + bob integer; + betty integer; + jack integer; + jill integer; + sven integer; + stacy integer; + + rel_id integer; +begin + -- Create the test groups. + A := acs_group.new(group_name => 'A'); + B := acs_group.new(group_name => 'B'); + C := acs_group.new(group_name => 'C'); + D := acs_group.new(group_name => 'D'); + E := acs_group.new(group_name => 'E'); + F := acs_group.new(group_name => 'F'); + G := acs_group.new(group_name => 'G'); + + -- Create the test members. + joe := acs_user.new(email => 'joe@asdf.com', + first_names => 'Joe', last_name => 'Smith', + password => 'assword', salt => 'p'); + jane := acs_user.new(email => 'jane@asdf.com', + first_names => 'Jane', last_name => 'Smith', + password => 'assword', salt => 'p'); + bob := acs_user.new(email => 'bob@asdf.com', + first_names => 'Bob', last_name => 'Smith', + password => 'assword', salt => 'p'); + betty := acs_user.new(email => 'betty@asdf.com', + first_names => 'Betty', last_name => 'Smith', + password => 'assword', salt => 'p'); + jack := acs_user.new(email => 'jack@asdf.com', + first_names => 'Jack', last_name => 'Smith', + password => 'assword', salt => 'p'); + jill := acs_user.new(email => 'jill@asdf.com', + first_names => 'Jill', last_name => 'Smith', + password => 'assword', salt => 'p'); + sven := acs_user.new(email => 'sven@asdf.com', + first_names => 'Sven', last_name => 'Smith', + password => 'assword', salt => 'p'); + stacy := acs_user.new(email => 'stacy@asdf.com', + first_names => 'Stacy', last_name => 'Smith', + password => 'assword', salt => 'p'); + + -- Make a couple of compositions. + + rel_id := composition_rel.new(object_id_one => A, object_id_two => B); + rel_id := composition_rel.new(object_id_one => A, object_id_two => C); + rel_id := composition_rel.new(object_id_one => A, object_id_two => D); + + rel_id := composition_rel.new(object_id_one => E, object_id_two => A); + rel_id := composition_rel.new(object_id_one => F, object_id_two => A); + rel_id := composition_rel.new(object_id_one => G, object_id_two => A); + + -- Make a couple of memberships. + + rel_id := membership_rel.new(object_id_one => B, object_id_two => joe); + rel_id := membership_rel.new(object_id_one => B, object_id_two => jane); + rel_id := membership_rel.new(object_id_one => B, object_id_two => betty); + rel_id := membership_rel.new(object_id_one => A, object_id_two => bob); + rel_id := membership_rel.new(object_id_one => A, object_id_two => betty); + rel_id := membership_rel.new(object_id_one => E, object_id_two => betty); + + delete from acs_logs; + + for g in (select * from groups) loop + if acs_group.check_representation(g.group_id) = 'f' then + dbms_output.put_line('Group ' || g.group_name || ' (' || g.group_id || + ') failed.'); + end if; + end loop; + + -- Remove the test groups. + acs_group.delete(G); + acs_group.delete(F); + acs_group.delete(E); + acs_group.delete(D); + acs_group.delete(C); + acs_group.delete(B); + acs_group.delete(A); + + -- Remove the test members. + acs_user.delete(joe); + acs_user.delete(jane); + acs_user.delete(bob); + acs_user.delete(betty); + acs_user.delete(jack); + acs_user.delete(jill); + acs_user.delete(sven); + acs_user.delete(stacy); +end; +/ +show errors + + +select log_level, log_key, message +from acs_logs +where log_key = 'error'; Index: openacs-4/packages/acs-kernel/sql/oracle/test/rel-constraints-test.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test/rel-constraints-test.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test/rel-constraints-test.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,318 @@ +-- +-- packages/acs-kernel/sql/test/rel-constraints-test.sql +-- +-- @author oumi@arsdigita.com +-- @creation-date 2000-12-02 +-- @cvs-id $Id: rel-constraints-test.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +set serveroutput on + +create or replace procedure rel_constraint_dump_views +is +begin + + dbms_output.put_line(' '); + dbms_output.put_line('Contents of view ''rel_constraints_violated_one'':'); + + for r in (select * from rel_constraints_violated_one) loop + dbms_output.put_line(rpad(r.constraint_id, 10) || + rpad(r.rel_id, 10) || + rpad(acs_object.name(r.container_id), 20) || + rpad(acs_object.name(r.party_id), 20)); + end loop; + + + dbms_output.put_line(' '); + dbms_output.put_line('Contents of view ''rel_constraints_violated_two'':'); + + for r in (select * from rel_constraints_violated_two) loop + dbms_output.put_line(rpad(r.constraint_id, 10) || + rpad(r.rel_id, 10) || + rpad(acs_object.name(r.container_id), 20) || + rpad(acs_object.name(r.party_id), 20)); + end loop; + +end rel_constraint_dump_views; +/ +show errors + +create or replace procedure rel_constraint_test_check ( + rel_id integer, + expect_violation_p char +) +is + v_violation_msg varchar(4000); + v_violation_p char; + v_object_id_one integer; + v_object_id_two integer; + v_rel_type acs_rels.rel_type%TYPE; +begin + + v_violation_p := 'f'; + + v_violation_msg := rel_constraint.violation(rel_id); + + if v_violation_msg is not null then + v_violation_p := 't'; + end if; + + if v_violation_p != expect_violation_p then + + 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 = rel_constraint_test_check.rel_id; + + acs_log.error('rel_constraint_test_check', + 'Relation ' || acs_object.name(rel_id) || + ' (' || rel_id || ')' || + ' failed (violation_p = ' || v_violation_p || '). ' || + 'Rel info: type = ' || v_rel_type || ', object one = ' || + acs_object.name(v_object_id_one) || + ' (' || v_object_id_one || ')' || ', object two = ' || + acs_object.name(v_object_id_two) || + ' (' || v_object_id_two || ').'); + + dbms_output.put_line('Relation ' || acs_object.name(rel_id) || + ' (' || rel_id || ')' || + ' failed (violation_p = ' || v_violation_p || '). ' || + 'Rel info: type = ' || v_rel_type || ', object one = ' || + acs_object.name(v_object_id_one) || + ' (' || v_object_id_one || ')' || ', object two = ' || + acs_object.name(v_object_id_two) || + ' (' || v_object_id_two || ').'); + + dbms_output.put_line('Violation Message:'); + dbms_output.put_line(v_violation_msg); + + + end if; + +end rel_constraint_test_check; +/ +show errors + +-- creates blah_member_rel and yippe_member_rel relationships +@rel-segments-test-types-create.sql + +declare + A integer; + B integer; + C integer; + D integer; + E integer; + F integer; + G integer; + + joe integer; + jane integer; + bob integer; + betty integer; + jack integer; + jill integer; + sven integer; + stacy integer; + + reg_users integer; + + rel_id integer; + + side_one_constraint integer; + side_two_constraint integer; + + v_count integer; + +begin + -- Create the test groups. + A := acs_group.new(group_name => 'A'); + B := acs_group.new(group_name => 'B'); + C := acs_group.new(group_name => 'C'); + D := acs_group.new(group_name => 'D'); + E := acs_group.new(group_name => 'E'); + F := acs_group.new(group_name => 'F'); + G := acs_group.new(group_name => 'G'); + + -- Create the test members. + joe := acs_user.new(email => 'joe@asdf.com', + first_names => 'Joe', last_name => 'Smith', + password => 'assword', salt => 'p'); + jane := acs_user.new(email => 'jane@asdf.com', + first_names => 'Jane', last_name => 'Smith', + password => 'assword', salt => 'p'); + bob := acs_user.new(email => 'bob@asdf.com', + first_names => 'Bob', last_name => 'Smith', + password => 'assword', salt => 'p'); + betty := acs_user.new(email => 'betty@asdf.com', + first_names => 'Betty', last_name => 'Smith', + password => 'assword', salt => 'p'); + jack := acs_user.new(email => 'jack@asdf.com', + first_names => 'Jack', last_name => 'Smith', + password => 'assword', salt => 'p'); + jill := acs_user.new(email => 'jill@asdf.com', + first_names => 'Jill', last_name => 'Smith', + password => 'assword', salt => 'p'); + sven := acs_user.new(email => 'sven@asdf.com', + first_names => 'Sven', last_name => 'Smith', + password => 'assword', salt => 'p'); + stacy := acs_user.new(email => 'stacy@asdf.com', + first_names => 'Stacy', last_name => 'Smith', + password => 'assword', salt => 'p'); + + -- Make a couple of compositions. + + reg_users := acs.magic_object_id('registered_users'); + + rel_id := composition_rel.new(object_id_one => A, object_id_two => B); + rel_id := composition_rel.new(object_id_one => A, object_id_two => C); + rel_id := composition_rel.new(object_id_one => A, object_id_two => D); + + rel_id := composition_rel.new(object_id_one => E, object_id_two => A); + rel_id := composition_rel.new(object_id_one => E, object_id_two => F); + + rel_id := composition_rel.new(object_id_one=>reg_users, object_id_two=>E); + rel_id := composition_rel.new(object_id_one=>reg_users, object_id_two=>G); + + -- define a few segments. + + -- define a few relational constraints. + + side_two_constraint := rel_constraint.new( + constraint_name => 'Yippe: side 2 must be a ''blah'' of A', + rel_segment => acs_rel_segment.get_or_new(reg_users, 'yippe_member_rel'), + rel_side => 'two', + required_rel_segment => acs_rel_segment.get_or_new(A,'blah_member_rel') + ); + + side_one_constraint := rel_constraint.new( + constraint_name => 'Yippe: side 1 must be a component of E', + rel_segment => acs_rel_segment.get_or_new(reg_users, 'yippe_member_rel'), + rel_side => 'one', + required_rel_segment => acs_rel_segment.get_or_new(E, 'composition_rel') + ); + + + delete from acs_logs; + + + -- Make a couple of memberships. + + -- LEGAL MEMBERSHIPS: + + -- textbook case: + -- joe is a blah of A, and F is component of E, so its legal to make joe + -- a yippe of F. + rel_id := blah_member_rel.new(object_id_one => A, object_id_two => joe); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 'f'); + + rel_id := yippe_member_rel.new(object_id_one => F, object_id_two => joe); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 'f'); + + -- do constraints respect group hierarchy? If so, this will be legal: + rel_id := blah_member_rel.new(object_id_one => B, object_id_two => jane); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 'f'); + + rel_id := yippe_member_rel.new(object_id_one => F, object_id_two => jane); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 'f'); + + -- ILLEGAL MEMBERSHIPS: + + -- G is not a component of F, therefore no one can be a yippe of G + -- This should violated 2 constraints (object one and object two are both + -- invalid). + rel_id := yippe_member_rel.new(object_id_one => G, object_id_two => bob); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 't'); + + -- betty is not a blah of A, therefore she cannot be a yippe of F. + rel_id := yippe_member_rel.new(object_id_one => F, object_id_two => betty); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 't'); + + -- make sven be a regular member of A. Sven cannot be a yippe of F. + rel_id := membership_rel.new(object_id_one => A, object_id_two => sven); + rel_id := yippe_member_rel.new(object_id_one => F, object_id_two => sven); + + rel_constraint_test_check(rel_id => rel_id, + expect_violation_p => 't'); + + -- TEST THE VIEWS (there should be 4 violated constraints, + -- 1 side one violation and 3 side two violations. + + select count(*) into v_count + from rel_constraints_violated_one; + + if v_count != 1 then + dbms_output.put_line ('rel_constraints_violated_one should have 1 row.' || + ' Found ' || v_count || ' rows.'); + rel_constraint_dump_views; + end if; + + select count(*) into v_count + from rel_constraints_violated_two; + + if v_count != 3 then + dbms_output.put_line ('rel_constraints_violated_two should have 2 rows.' || + ' Found ' || v_count || ' rows.'); + rel_constraint_dump_views; + end if; + + + -- Remove the constraints + rel_constraint.delete(side_one_constraint); + rel_constraint.delete(side_two_constraint); + + -- Remove the test memebership relations + for r in (select * from blah_member_rels) loop + blah_member_rel.delete(r.rel_id); + end loop; + + for r in (select * from yippe_member_rels) loop + yippe_member_rel.delete(r.rel_id); + end loop; + + -- Remove the test segments. + acs_rel_segment.delete(acs_rel_segment.get(A,'blah_member_rel')); + acs_rel_segment.delete(acs_rel_segment.get(E,'composition_rel')); + acs_rel_segment.delete(acs_rel_segment.get(reg_users,'yippe_member_rel')); + + -- Remove the test groups. + acs_group.delete(G); + acs_group.delete(F); + acs_group.delete(E); + acs_group.delete(D); + acs_group.delete(C); + acs_group.delete(B); + acs_group.delete(A); + + -- Remove the test members. + acs_user.delete(joe); + acs_user.delete(jane); + acs_user.delete(bob); + acs_user.delete(betty); + acs_user.delete(jack); + acs_user.delete(jill); + acs_user.delete(sven); + acs_user.delete(stacy); +end; +/ +show errors + + +drop procedure rel_constraint_test_check; + +@rel-segments-test-types-drop.sql + +select log_level, log_key, message +from acs_logs +where log_key = 'error'; Index: openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-create.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,177 @@ +begin + acs_rel_type.create_type ( + supertype => 'membership_rel', + rel_type => 'blah_member_rel', + pretty_name => 'Blah Membership Relationship', + pretty_plural => 'Blah Membership Relationships', + table_name => 'blah_member_rels', + id_column => 'rel_id', + package_name => 'blah_member_rel', + object_type_one => 'group', + min_n_rels_one => 0, max_n_rels_one => null, + object_type_two => 'party', role_two => 'member', + min_n_rels_two => 0, max_n_rels_two => null + ); + + + acs_rel_type.create_type ( + supertype => 'membership_rel', + rel_type => 'yippe_member_rel', + pretty_name => 'Yippe Membership Relationship', + pretty_plural => 'Yippe Membership Relationships', + table_name => 'yippe_member_rels', + id_column => 'rel_id', + package_name => 'yippe_member_rel', + object_type_one => 'group', + min_n_rels_one => 0, max_n_rels_one => null, + object_type_two => 'party', role_two => 'member', + min_n_rels_two => 0, max_n_rels_two => null + ); +end; +/ +show errors + +create table blah_member_rels ( + rel_id constraint blah_member_rel_id_fk + references membership_rels (rel_id) + constraint blah_member_rel_pk + primary key +); + +create table yippe_member_rels ( + rel_id constraint yippe_member_rel_id_fk + references membership_rels (rel_id) + constraint yippe_member_rel_pk + primary key +); + + +create or replace package blah_member_rel +is + function new ( + rel_id in blah_member_rels.rel_id%TYPE + default null, + rel_type in acs_rels.rel_type%TYPE + default 'blah_member_rel', + object_id_one in groups.group_id%TYPE, + object_id_two in parties.party_id%TYPE + ) return blah_member_rels.rel_id%TYPE; + + procedure delete ( + rel_id in blah_member_rels.rel_id%TYPE + ); +end blah_member_rel; +/ +show errors + +create or replace package body blah_member_rel +is + function new ( + rel_id in blah_member_rels.rel_id%TYPE + default null, + rel_type in acs_rels.rel_type%TYPE + default 'blah_member_rel', + object_id_one in groups.group_id%TYPE, + object_id_two in parties.party_id%TYPE + ) return blah_member_rels.rel_id%TYPE + is + v_rel_id blah_member_rels.rel_id%TYPE; + begin + + v_rel_id := membership_rel.new( + rel_id => rel_id, + rel_type => rel_type, + object_id_one => object_id_one, + object_id_two => object_id_two + ); + + + insert into blah_member_rels + (rel_id) + values + (v_rel_id); + + return v_rel_id; + + end new; + + procedure delete ( + rel_id in blah_member_rels.rel_id%TYPE + ) + is + begin + + delete from blah_member_rels where rel_id = rel_id; + + membership_rel.delete(rel_id); + + end delete; +end blah_member_rel; +/ +show errors + + + +create or replace package yippe_member_rel +is + function new ( + rel_id in yippe_member_rels.rel_id%TYPE + default null, + rel_type in acs_rels.rel_type%TYPE + default 'yippe_member_rel', + object_id_one in groups.group_id%TYPE, + object_id_two in parties.party_id%TYPE + ) return yippe_member_rels.rel_id%TYPE; + + procedure delete ( + rel_id in yippe_member_rels.rel_id%TYPE + ); +end yippe_member_rel; +/ +show errors + +create or replace package body yippe_member_rel +is + function new ( + rel_id in yippe_member_rels.rel_id%TYPE + default null, + rel_type in acs_rels.rel_type%TYPE + default 'yippe_member_rel', + object_id_one in groups.group_id%TYPE, + object_id_two in parties.party_id%TYPE + ) return yippe_member_rels.rel_id%TYPE + is + v_rel_id yippe_member_rels.rel_id%TYPE; + begin + + v_rel_id := membership_rel.new( + rel_id => rel_id, + rel_type => rel_type, + object_id_one => object_id_one, + object_id_two => object_id_two + ); + + + insert into yippe_member_rels + (rel_id) + values + (v_rel_id); + + return v_rel_id; + + end new; + + procedure delete ( + rel_id in yippe_member_rels.rel_id%TYPE + ) + is + begin + + delete from yippe_member_rels where rel_id = rel_id; + + membership_rel.delete(rel_id); + + end delete; +end yippe_member_rel; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test-types-drop.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,16 @@ + +drop package blah_member_rel; +drop package yippe_member_rel; + +drop table blah_member_rels; +drop table yippe_member_rels; + +begin + + acs_rel_type.drop_type('blah_member_rel'); + + acs_rel_type.drop_type('yippe_member_rel'); + +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test/rel-segments-test.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,264 @@ +-- +-- packages/acs-kernel/sql/test/rel-segments-test.sql +-- +-- @author oumi@arsdigita.com +-- @creation-date 2000-12-01 +-- @cvs-id $Id: rel-segments-test.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +set serveroutput on + +-- creates blah_member_rel and yippe_member_rel relationships +@rel-segments-test-types-create.sql + + +create or replace function rel_segment_test_check ( + segment_id integer, + party_id integer, + container_id integer +) return char +is + v_pass_p char(1); +begin + + select decode(count(*), 0, 'f', 't') into v_pass_p + from rel_segment_party_map + where segment_id = rel_segment_test_check.segment_id + and party_id = rel_segment_test_check.party_id + and container_id = rel_segment_test_check.container_id; + + if v_pass_p = 'f' then + + dbms_output.put_line('Row missing from rel_segment_party_map for' || + ' segment ''' || acs_object.name(segment_id) || + ''' (' || segment_id || ')' || + ', party ''' || acs_object.name(party_id) || + ''' (' || party_id || ')' || + ', container ''' || acs_object.name(container_id) || + ''' (' ||container_id || ')'); + + acs_log.error('rel_segment_test_check', + 'Row missing from rel_segment_party_map for' || + ' segment ''' || acs_object.name(segment_id) || + ''' (' || segment_id || ')' || + ', party ''' || acs_object.name(party_id) || + ''' (' || party_id || ')' || + ', container ''' || acs_object.name(container_id) || + ''' (' ||container_id || ')'); + end if; + + + return v_pass_p; + +end; +/ +show errors + + +declare + A integer; + B integer; + C integer; + D integer; + E integer; + F integer; + G integer; + + joe integer; + jane integer; + bob integer; + betty integer; + jack integer; + jill integer; + sven integer; + stacy integer; + + seg_G_blahs integer; + seg_E_yippes integer; + + rel_id integer; +begin + -- Create the test groups. + A := acs_group.new(group_name => 'A'); + B := acs_group.new(group_name => 'B'); + C := acs_group.new(group_name => 'C'); + D := acs_group.new(group_name => 'D'); + E := acs_group.new(group_name => 'E'); + F := acs_group.new(group_name => 'F'); + G := acs_group.new(group_name => 'G'); + + -- Create the test members. + joe := acs_user.new(email => 'joe@asdf.com', + first_names => 'Joe', last_name => 'Smith', + password => 'assword', salt => 'p'); + jane := acs_user.new(email => 'jane@asdf.com', + first_names => 'Jane', last_name => 'Smith', + password => 'assword', salt => 'p'); + bob := acs_user.new(email => 'bob@asdf.com', + first_names => 'Bob', last_name => 'Smith', + password => 'assword', salt => 'p'); + betty := acs_user.new(email => 'betty@asdf.com', + first_names => 'Betty', last_name => 'Smith', + password => 'assword', salt => 'p'); + jack := acs_user.new(email => 'jack@asdf.com', + first_names => 'Jack', last_name => 'Smith', + password => 'assword', salt => 'p'); + jill := acs_user.new(email => 'jill@asdf.com', + first_names => 'Jill', last_name => 'Smith', + password => 'assword', salt => 'p'); + sven := acs_user.new(email => 'sven@asdf.com', + first_names => 'Sven', last_name => 'Smith', + password => 'assword', salt => 'p'); + stacy := acs_user.new(email => 'stacy@asdf.com', + first_names => 'Stacy', last_name => 'Smith', + password => 'assword', salt => 'p'); + + -- Make a couple of compositions. + + rel_id := composition_rel.new(object_id_one => A, object_id_two => B); + rel_id := composition_rel.new(object_id_one => A, object_id_two => C); + rel_id := composition_rel.new(object_id_one => A, object_id_two => D); + + rel_id := composition_rel.new(object_id_one => E, object_id_two => A); + rel_id := composition_rel.new(object_id_one => F, object_id_two => A); + rel_id := composition_rel.new(object_id_one => G, object_id_two => A); + + -- Make a couple of memberships. + + rel_id := blah_member_rel.new(object_id_one => B, object_id_two => joe); + rel_id := yippe_member_rel.new(object_id_one => B, object_id_two => jane); + rel_id := blah_member_rel.new(object_id_one => B, object_id_two => betty); + rel_id := yippe_member_rel.new(object_id_one => A, object_id_two => bob); + rel_id := blah_member_rel.new(object_id_one => A, object_id_two => betty); + rel_id := yippe_member_rel.new(object_id_one => E, object_id_two => betty); + + + -- define a few segments. + + -- the segment of all parties that are blah members of G + seg_G_blahs := acs_rel_segment.new(segment_name => 'Blahs of Group G', + group_id => G, + rel_type => 'blah_member_rel'); + + -- the segment of all parties that are yippe members of E + seg_E_yippes := acs_rel_segment.new(segment_name => 'Yippes of Group E', + group_id => E, + rel_type => 'yippe_member_rel'); + + + delete from acs_logs; + + +-- group_element_index_dump; +-- rel_segment_party_map_dump; + + + + -- Expectations: + -- 1. seg_G_blahs should include joe and betty + -- 2. seg_E_yippes should include bob, and jane, betty + + -- check: seg_G_blahs contains joe with container B + if rel_segment_test_check(seg_G_blahs, joe, B) = 'f' then + dbms_output.put_line('Segment ' || acs_object.name(seg_G_blahs) || + '(' || seg_G_blahs || ') failed. Group_id = ' || G); + end if; + + -- check: seg_G_blahs contains betty with container B + if rel_segment_test_check(seg_G_blahs, betty, B) = 'f' then + dbms_output.put_line('Segment ' || acs_object.name(seg_G_blahs) || + '(' || seg_G_blahs || ') failed. Group_id = ' || G); + end if; + + -- check: seg_G_blahs contains betty with container A + if rel_segment_test_check(seg_G_blahs, betty, A) = 'f' then + dbms_output.put_line('Segment ' || acs_object.name(seg_G_blahs) || + '(' || seg_G_blahs || ') failed. Group_id = ' || G); + end if; + + -- check: seg_E_yippes contains jane with container B + if rel_segment_test_check(seg_E_yippes, jane, B) = 'f' then + dbms_output.put_line('Segment ' || acs_object.name(seg_E_yippes) || + '(' || seg_E_yippes || ') failed. Group_id = ' || E); + end if; + + -- check: seg_E_yippes contains bob with container A + if rel_segment_test_check(seg_E_yippes, bob, A) = 'f' then + dbms_output.put_line('Segment ' || acs_object.name(seg_E_yippes) || + '(' || seg_E_yippes || ') failed. Group_id = ' || E); + end if; + + -- check: seg_E_yippes contains betty with container E + if rel_segment_test_check(seg_E_yippes, betty, E) = 'f' then + dbms_output.put_line('Segment ' || acs_object.name(seg_E_yippes) || + '(' || seg_E_yippes || ') failed. Group_id = ' || E); + end if; + + -- Now we test on-the-fly creation of rel-segments with the get_or_new + -- function: + + -- The segment of all memers of F should contain jane through group B + if rel_segment_test_check( + acs_rel_segment.get_or_new(F,'membership_rel'), jane, B) = 'f' then + dbms_output.put_line('Segment ' || + acs_object.name(acs_rel_segment.get(F,'membership_rel')) || + '(' || acs_rel_segment.get(F,'membership_rel') + || ') failed. Group_id = ' || F); + end if; + + -- The segment of all memers of F should contain betty through group A + if rel_segment_test_check( + acs_rel_segment.get_or_new(F,'membership_rel'), betty, A) = 'f' then + dbms_output.put_line('Segment ' || + acs_object.name(acs_rel_segment.get(F,'membership_rel')) || + '(' || acs_rel_segment.get(F,'membership_rel') + || ') failed. Group_id = ' || A); + end if; + + + + -- Remove the test segments. + acs_rel_segment.delete(seg_G_blahs); + acs_rel_segment.delete(seg_E_yippes); + acs_rel_segment.delete(acs_rel_segment.get(F,'membership_rel')); + + -- Remove the test memebership relations + for r in (select * from blah_member_rels) loop + blah_member_rel.delete(r.rel_id); + end loop; + + for r in (select * from yippe_member_rels) loop + yippe_member_rel.delete(r.rel_id); + end loop; + + + -- Remove the test groups. + acs_group.delete(G); + acs_group.delete(F); + acs_group.delete(E); + acs_group.delete(D); + acs_group.delete(C); + acs_group.delete(B); + acs_group.delete(A); + + -- Remove the test members. + acs_user.delete(joe); + acs_user.delete(jane); + acs_user.delete(bob); + acs_user.delete(betty); + acs_user.delete(jack); + acs_user.delete(jill); + acs_user.delete(sven); + acs_user.delete(stacy); +end; +/ +show errors + + +drop function rel_segment_test_check; + +@rel-segments-test-types-drop.sql + +select log_level, log_key, message +from acs_logs +where log_key = 'error'; Index: openacs-4/packages/acs-kernel/sql/oracle/test-harness/acs-core.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test-harness/acs-core.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test-harness/acs-core.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,35 @@ +-- +-- acs-core/sql/acs-core-test-harness.sql +-- +-- Test harness for ACS Core's PL/SQL API +-- +-- @author Michael Yoon (michael@arsdigita.com) +-- +-- @creation-date 2000-08-05 +-- +-- @cvs-id $Id: acs-core.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- + +declare + uid users.user_id%TYPE; +begin + dbms_output.put_line('Calling acs_user.new() to create user 1'); + + uid := + acs_user.new(email => 'jane.doe@arsdigita.com', + first_names => 'Jane', + last_name => 'Doe', + password => 'janedoerules', + creation_ip => '127.0.0.1', + user_id => 1); + + dbms_output.put_line('Calling acs_object.name() to get the name of user 1: ' || acs_object.name(1)); + + dbms_output.put_line('Calling acs_user.delete() to delete user 1'); + + acs_user.delete(1); +end; +/ +show errors + + Index: openacs-4/packages/acs-kernel/sql/oracle/test-harness/acs-permissions.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/test-harness/acs-permissions.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/test-harness/acs-permissions.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,253 @@ +-- file: packages/acs-kernel/sql/acs-permissions-test.sql +-- history: date email message +-- 2000-08-10 rhs@mit.edu initial version + +begin + -- Objects for testing. + insert into acs_object_types + (object_type, supertype, pretty_name, pretty_plural) + values + ('bboard', 'acs_object', 'BBoard', 'BBoards'); + + insert into acs_object_types + (object_type, supertype, pretty_name, pretty_plural) + values + ('bboard_message', 'acs_object', 'BBoard Message', 'BBoard Messages'); + + -------------------------------------------------------------- + -- Some privileges that will be fundamental to all objects. -- + -------------------------------------------------------------- + + insert into acs_privileges + (privilege) + values + ('read'); + + insert into acs_privileges + (privilege) + values + ('write'); + + insert into acs_privileges + (privilege) + values + ('create'); + + insert into acs_privileges + (privilege) + values + ('delete'); + + insert into acs_privileges + (privilege) + values + ('admin'); + + insert into acs_privileges + (privilege) + values + ('all'); + + ---------------------------------------------------------- + -- Some privileges that probably only apply to bboards. -- + ---------------------------------------------------------- + + insert into acs_privileges + (privilege) + values + ('moderate'); + + ------------------------------------------------- + -- Administrators can read, write, and create. -- + ------------------------------------------------- + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('admin', 'read'); + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('admin', 'write'); + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('admin', 'create'); + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('admin', 'delete'); + + ------------------------------------ + -- Moderators can read and write. -- + ------------------------------------ + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('moderate', 'read'); + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('moderate', 'write'); + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('all', 'admin'); + + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + ('all', 'moderate'); + + ------------------------ + -- Methods on bboards -- + ------------------------ + + insert into acs_methods + (object_type, method) + values + ('bboard', 'select_any_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard', 'update_any_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard', 'delete_any_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard', 'insert_bboard'); + + insert into acs_methods + (object_type, method) + values + ('bboard', 'update_bboard'); + + insert into acs_methods + (object_type, method) + values + ('bboard', 'select_bboard'); + + insert into acs_methods + (object_type, method) + values + ('bboard', 'delete_bboard'); + + --------------------------------- + -- Methods on bboard messages. -- + --------------------------------- + + insert into acs_methods + (object_type, method) + values + ('bboard_message', 'select_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard_message', 'update_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard_message', 'insert_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard_message', 'delete_message'); + + insert into acs_methods + (object_type, method) + values + ('bboard_message', 'foo'); + + ------------------------------------------------------------------------- + -- Mappings between privileges and methods on particular object types. -- + ------------------------------------------------------------------------- + + + -- Methods that correspond to read for a bboard + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('read', 'bboard', 'select_any_message'); + + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('read', 'bboard', 'select_bboard'); + + -- Methods that correspond to read for a bboard message. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('read', 'bboard_message', 'select_message'); + + -- Methods that correspond to write for a bboard. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('write', 'bboard', 'update_bboard'); + + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('write', 'bboard', 'update_any_message'); + + -- Methods that correspond to write for a bboard message. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('write', 'bboard_message', 'update_message'); + + -- Methods that correspond to create for a bboard. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('create', 'bboard', 'insert_bboard'); + + -- Methods that correspond to create for a bboard message. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('create', 'bboard_message', 'insert_message'); + + -- Methods that correspond to delete for a bboard. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('delete', 'bboard', 'delete_bboard'); + + -- Methods that correspond to delete for a bboard. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('delete', 'bboard', 'delete_any_message'); + + -- Methods that correspond to create for a bboard message. + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('delete', 'bboard_message', 'delete_message'); + + insert into acs_privilege_method_rules + (privilege, object_type, method) + values + ('all', 'bboard_message', 'foo'); + + commit; +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0-4.0.1.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0-4.0.1.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0-4.0.1.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,493 @@ +-- +-- /packages/acs-kernel/sql/upgrade/upgrade-4.0-4.0.1.sql +-- +-- Upgrades ACS 4.0 to ACS 4.0.1 +-- +-- @author Multiple +-- @creation-date Wed Nov 1 10:32:08 2000 +-- @cvs-id $Id: upgrade-4.0-4.0.1.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ + +-- upgrade security. + +create or replace package sec +as + + function allocate_sessions( + v_preallocated_server in varchar2, + v_sessions_to_allocate in integer + ) + return varchar2; +end sec; +/ +show errors + +create or replace package body sec +as + + -- Insert a bunch of rows into sec_sessions with a given preallocated_server. + function allocate_sessions( + v_preallocated_server in varchar2, + v_sessions_to_allocate in integer + ) + return varchar2 + is + -- Define table types for bulk inserts. + type int_tab is table of integer index by binary_integer; + + a_session_ids int_tab; + a_session_id_string varchar2(4000); + + a_count integer := 1; + pragma autonomous_transaction; + begin + while a_count <= v_sessions_to_allocate loop + select sec_id_seq.nextval into a_session_ids(a_session_ids.count + 1) from dual; + a_session_id_string := a_session_id_string || ',' || a_session_ids(a_session_ids.count); + a_count := a_count + 1; + end loop; + + forall i in 1..a_session_ids.count + insert into sec_sessions(session_id, preallocated_server) + values(a_session_ids(i), v_preallocated_server); + + commit; + + -- strip initial comma + return substr(a_session_id_string, 2); + end; +end sec; +/ +show errors + +drop table sec_browser_properties; +drop table sec_login_tokens; + +alter table sec_sessions drop column token; +alter table sec_sessions drop column secure_token; +alter table sec_sessions drop column browser_id; +alter table sec_sessions add (first_hit integer); +update sec_sessions set first_hit = last_hit where last_hit is not null; +alter table sec_sessions drop column last_hit; + +alter sequence sec_security_token_id_seq cache 100; +alter sequence sec_id_seq cache 1000; + +create index sec_property_names on sec_session_properties(property_name); + +-- upgrade parties + +update parties set email = lower(email); + +-- performance improvements + +create bitmap index acs_obj_types_supertype_idx on acs_object_types (supertype); + +-- update apm procedures +-- bquinn@arsdigita.com 11/18/2000 + +declare + none_null_p integer; + cursor all_pretty_names is + select pretty_name from apm_package_types; +begin + none_null_p := 1; + for cur_val in all_pretty_names + loop + if cur_val.pretty_name is not null then + none_null_p := 0; + end if; + end loop; + if none_null_p = 1 then + execute immediate 'alter table apm_package_types modify (pretty_name varchar2(100) not null)'; + end if; +end; +/ +show errors + +create or replace package body apm +as + procedure register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm_package_type.create_type( + package_key => register_package.package_key, + pretty_name => register_package.pretty_name, + pretty_plural => register_package.pretty_plural, + package_uri => register_package.package_uri, + package_type => register_package.package_type, + singleton_p => register_package.singleton_p, + spec_file_path => register_package.spec_file_path, + spec_file_mtime => spec_file_mtime + ); + end register_package; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + + return apm_package_type.update_type( + package_key => update_package.package_key, + pretty_name => update_package.pretty_name, + pretty_plural => update_package.pretty_plural, + package_uri => update_package.package_uri, + package_type => update_package.package_type, + singleton_p => update_package.singleton_p, + spec_file_path => update_package.spec_file_path, + spec_file_mtime => update_package.spec_file_mtime + ); + + end update_package; + + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ) + is + begin + apm_package_type.drop_type( + package_key => unregister_package.package_key, + cascade_p => unregister_package.cascade_p + ); + end unregister_package; + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_register_p integer; + begin + select decode(count(*),0,0,1) into v_register_p from apm_package_types + where package_key = register_p.package_key; + return v_register_p; + end register_p; + + procedure register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm.register_package( + package_key => register_application.package_key, + pretty_name => register_application.pretty_name, + pretty_plural => register_application.pretty_plural, + package_uri => register_application.package_uri, + package_type => 'apm_application', + singleton_p => register_application.singleton_p, + spec_file_path => register_application.spec_file_path, + spec_file_mtime => register_application.spec_file_mtime + ); + end register_application; + + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_application.package_key, + cascade_p => unregister_application.cascade_p + ); + end unregister_application; + + procedure register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm.register_package( + package_key => register_service.package_key, + pretty_name => register_service.pretty_name, + pretty_plural => register_service.pretty_plural, + package_uri => register_service.package_uri, + package_type => 'apm_service', + singleton_p => register_service.singleton_p, + spec_file_path => register_service.spec_file_path, + spec_file_mtime => register_service.spec_file_mtime + ); + end register_service; + + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_service.package_key, + cascade_p => unregister_service.cascade_p + ); + end unregister_service; + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE + is + v_parameter_id apm_parameters.parameter_id%TYPE; + cursor all_parameters is + select ap.package_id, p.parameter_id, p.default_value + from apm_parameters p, apm_parameter_values v, apm_packages ap + where p.package_key = ap.package_key + and p.parameter_id = v.parameter_id (+) + and v.attr_value is null + and p.package_key = register_parameter.package_key; + begin + -- Create the new parameter. + v_parameter_id := acs_object.new( + object_id => parameter_id, + object_type => 'apm_parameter' + ); + + insert into apm_parameters + (parameter_id, parameter_name, description, package_key, datatype, + default_value, section_name, min_n_values, max_n_values) + values + (v_parameter_id, register_parameter.parameter_name, register_parameter.description, + register_parameter.package_key, register_parameter.datatype, + register_parameter.default_value, register_parameter.section_name, + register_parameter.min_n_values, register_parameter.max_n_values); + -- Propagate parameter to new instances. + for cur_val in all_parameters + loop + apm.set_value( + package_id => cur_val.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + return v_parameter_id; + end register_parameter; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE + is + begin + update apm_parameters + set parameter_name = nvl(update_parameter.parameter_name, parameter_name), + default_value = nvl(update_parameter.default_value, default_value), + datatype = nvl(update_parameter.datatype, datatype), + description = nvl(update_parameter.description, description), + section_name = nvl(update_parameter.section_name, section_name), + min_n_values = nvl(update_parameter.min_n_values, min_n_values), + max_n_values = nvl(update_parameter.max_n_values, max_n_values) + where parameter_id = update_parameter.parameter_id; + return parameter_id; + end; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer + is + v_parameter_p integer; + begin + select decode(count(*),0,0,1) into v_parameter_p + from apm_parameters + where package_key = parameter_p.package_key + and parameter_name = parameter_p.parameter_name; + return v_parameter_p; + end parameter_p; + + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ) + is + begin + delete from apm_parameter_values + where parameter_id = unregister_parameter.parameter_id; + delete from apm_parameters + where parameter_id = unregister_parameter.parameter_id; + acs_object.delete(parameter_id); + end unregister_parameter; + + function id_for_name ( + parameter_name in apm_parameters.parameter_name%TYPE, + package_key in apm_parameters.package_key%TYPE + ) return apm_parameters.parameter_id%TYPE + is + a_parameter_id apm_parameters.parameter_id%TYPE; + begin + select parameter_id into a_parameter_id + from apm_parameters p + where p.parameter_name = id_for_name.parameter_name and + p.package_key = id_for_name.package_key; + return a_parameter_id; + end id_for_name; + + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + value apm_parameter_values.attr_value%TYPE; + begin + select attr_value into value from apm_parameter_values v + where v.package_id = get_value.package_id + and parameter_id = get_value.parameter_id; + return value; + end get_value; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = get_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = get_value.package_id); + return apm.get_value( + parameter_id => v_parameter_id, + package_id => get_value.package_id + ); + end get_value; + + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + -- Determine if the value exists + select value_id into v_value_id from apm_parameter_values + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + update apm_parameter_values set attr_value = set_value.attr_value + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + exception + when NO_DATA_FOUND + then + v_value_id := apm_parameter_value.new( + package_id => set_value.package_id, + parameter_id => set_value.parameter_id, + attr_value => set_value.attr_value + ); + end set_value; + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = set_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = set_value.package_id); + apm.set_value( + parameter_id => v_parameter_id, + package_id => set_value.package_id, + attr_value => set_value.attr_value + ); + exception + when NO_DATA_FOUND + then + RAISE_APPLICATION_ERROR(-20000, 'The specified package ' || set_value.package_id || + ' does not exist in the system.'); + end set_value; +end apm; +/ +show errors + +declare + file_type_p integer; +begin + select decode(count(*), 0, 0, 1) into file_type_p from apm_package_file_types + where file_type_key = 'sqlj_code'; + if file_type_p != 1 then + insert into apm_package_file_types(file_type_key, pretty_name) values('sqlj_code', 'SQLJ Library'); + commit; + end if; +end; +/ +show errors Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0.1-4.1b.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0.1-4.1b.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0.1-4.1b.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,3796 @@ +-- +-- /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.1 2001/03/20 22:51:56 donb 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.1 2001/03/20 22:51:56 donb 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.1 2001/03/20 22:51:56 donb 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 waht 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 precense 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 permissable 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 permissable 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.1 2001/03/20 22:51:56 donb 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 permissable 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.1 2001/03/20 22:51:56 donb 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.1 2001/03/20 22:51:56 donb 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 + + Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0b2-4.0rc0.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0b2-4.0rc0.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0b2-4.0rc0.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,1942 @@ +create or replace package acs +as + + function add_user ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't', + member_state in membership_rels.member_state%TYPE default 'approved' + ) + return users.user_id%TYPE; + + procedure nuke_user ( + user_id in users.user_id%TYPE + ); + + procedure remove_user ( + user_id in users.user_id%TYPE + ); + + function magic_object_id ( + name in acs_magic_objects.name%TYPE + ) return acs_objects.object_id%TYPE; + +end acs; +/ +show errors + +create or replace package body acs +as + + function add_user ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't', + member_state in membership_rels.member_state%TYPE default 'approved' + ) return users.user_id%TYPE + is + v_user_id users.user_id%TYPE; + v_rel_id membership_rels.rel_id%TYPE; + begin + v_user_id := acs_user.new (user_id, object_type, creation_date, + creation_user, creation_ip, email, + url, first_names, last_name, password, + salt, password_question, password_answer, + screen_name, email_verified_p); + + v_rel_id := membership_rel.new ( + object_id_two => v_user_id, + object_id_one => acs.magic_object_id('registered_users'), + member_state => member_state); + + acs_permission.grant_permission ( + object_id => v_user_id, + grantee_id => v_user_id, + privilege => 'read' + ); + + acs_permission.grant_permission ( + object_id => v_user_id, + grantee_id => v_user_id, + privilege => 'write' + ); + + return v_user_id; + end; + + procedure nuke_user ( + user_id in users.user_id%TYPE + ) + is + begin + -- Delete all relationships. + for cur_val in (select m.rel_id from acs_rels r, membership_rels m + where r.rel_id = m.rel_id + and r.object_id_two = nuke_user.user_id) + loop + membership_rel.delete(cur_val.rel_id); + end loop; + + -- Delete all permissions + for cur_val in (select object_id, grantee_id, privilege + from acs_permissions + where grantee_id = nuke_user.user_id) + loop + acs_permission.revoke_permission( + object_id => cur_val.object_id, + grantee_id => cur_val.grantee_id, + privilege => cur_val.privilege + ); + end loop; + + acs_user.delete(user_id); + end; + + procedure remove_user ( + user_id in users.user_id%TYPE + ) + is + begin + delete from users + where user_id = remove_user.user_id; + end; + + function magic_object_id ( + name in acs_magic_objects.name%TYPE + ) return acs_objects.object_id%TYPE + is + object_id acs_objects.object_id%TYPE; + begin + select object_id + into magic_object_id.object_id + from acs_magic_objects + where name = magic_object_id.name; + + return object_id; + end magic_object_id; + +end acs; +/ +show errors + +declare + schema_user varchar2(100); + jobnum integer; +begin + select user into schema_user from dual; + + dbms_job.submit ( + jobnum, + 'dbms_stats.gather_schema_stats (''' || schema_user || ''', 10, cascade => true);', + trunc(sysdate+1) + 4/24, + 'sysdate + 1' + ); +end; +/ +show errors + +create or replace package apm +as + function register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ); + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + -- Informs the APM that this application is available for use. + function register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE; + + -- Remove the application from the system. + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this application. + cascade_p in char default 'f' + ); + + function register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE; + + -- Remove the service from the system. + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this service. + cascade_p in char default 'f' + ); + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer; + + -- Remove any uses of this parameter. + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ); + + -- Return the value of this parameter for a specific package and parameter. + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + +end apm; +/ +show errors + +create or replace package apm_package +as + +function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ); + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2; + + -- Enable a package to be utilized by a subsite. + procedure enable ( + package_id in apm_packages.package_id%TYPE + ); + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ); + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE; + +end apm_package; +/ +show errors + +create or replace package 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; + + procedure delete ( + version_id in apm_packages.package_id%TYPE + ); + + procedure enable ( + version_id in apm_package_versions.version_id%TYPE + ); + + procedure disable ( + version_id in apm_package_versions.version_id%TYPE + ); + + 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; + + -- Add a file to the indicated version. + 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; + + -- 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 + ); + + -- 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; + + procedure remove_interface( + interface_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- 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; + + procedure remove_dependency( + dependency_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- Given a version_name (e.g. 3.2a), return + -- something that can be lexicographically sorted. + function sortable_version_name ( + version_name in apm_package_versions.version_name%TYPE + ) return varchar2; + + -- Given two version names, return 1 if one > two, -1 if two > one, 0 otherwise. + -- Deprecate? + 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; + + 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; + + procedure upgrade( + version_id in apm_package_versions.version_id%TYPE + ); + +end apm_package_version; +/ +show errors + +create or replace package apm_package_type +as + function create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ) return apm_package_types.package_type%TYPE; + + function update_type ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ); + + function num_parameters ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + +end apm_package_type; +/ +show errors + + + +-- Private APM System API for managing parameter values. +create or replace package apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ); + end apm_parameter_value; +/ +show errors + +create or replace package apm_application +as + +function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + + +create or replace package apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + +create or replace package body apm +as + function register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + return apm_package_type.create_type( + package_key => register_package.package_key, + pretty_name => register_package.pretty_name, + pretty_plural => register_package.pretty_plural, + package_uri => register_package.package_uri, + package_type => register_package.package_type, + singleton_p => register_package.singleton_p, + spec_file_path => register_package.spec_file_path, + spec_file_mtime => spec_file_mtime + ); + end register_package; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + + return apm_package_type.update_type( + package_key => update_package.package_key, + pretty_name => update_package.pretty_name, + pretty_plural => update_package.pretty_plural, + package_uri => update_package.package_uri, + package_type => update_package.package_type, + singleton_p => update_package.singleton_p, + spec_file_path => update_package.spec_file_path, + spec_file_mtime => update_package.spec_file_mtime + ); + + end update_package; + + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ) + is + begin + apm_package_type.drop_type( + package_key => unregister_package.package_key, + cascade_p => unregister_package.cascade_p + ); + end unregister_package; + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_register_p integer; + begin + select decode(count(*),0,0,1) into v_register_p from apm_package_types + where package_key = register_p.package_key; + return v_register_p; + end register_p; + + function register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE + is + begin + return apm.register_package( + package_key => register_application.package_key, + pretty_name => register_application.pretty_name, + pretty_plural => register_application.pretty_plural, + package_uri => register_application.package_uri, + package_type => 'apm_application', + singleton_p => register_application.singleton_p, + spec_file_path => register_application.spec_file_path, + spec_file_mtime => register_application.spec_file_mtime + ); + end register_application; + + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_application.package_key, + cascade_p => unregister_application.cascade_p + ); + end unregister_application; + + function register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE + is + begin + return apm.register_package( + package_key => register_service.package_key, + pretty_name => register_service.pretty_name, + pretty_plural => register_service.pretty_plural, + package_uri => register_service.package_uri, + package_type => 'apm_service', + singleton_p => register_service.singleton_p, + spec_file_path => register_service.spec_file_path, + spec_file_mtime => register_service.spec_file_mtime + ); + end register_service; + + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_service.package_key, + cascade_p => unregister_service.cascade_p + ); + end unregister_service; + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE + is + v_parameter_id apm_parameters.parameter_id%TYPE; + begin + + v_parameter_id := acs_object.new( + object_id => parameter_id, + object_type => 'apm_parameter' + ); + insert into apm_parameters + (parameter_id, parameter_name, description, package_key, datatype, + default_value, section_name, min_n_values, max_n_values) + values + (v_parameter_id, register_parameter.parameter_name, register_parameter.description, + register_parameter.package_key, register_parameter.datatype, + register_parameter.default_value, register_parameter.section_name, + register_parameter.min_n_values, register_parameter.max_n_values); + + return v_parameter_id; + -- XXX: create an attribute using the metadata system. + + end register_parameter; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE + is + begin + update apm_parameters + set parameter_name = nvl(update_parameter.parameter_name, parameter_name), + default_value = nvl(update_parameter.default_value, default_value), + datatype = nvl(update_parameter.datatype, datatype), + description = nvl(update_parameter.description, description), + section_name = nvl(update_parameter.section_name, section_name), + min_n_values = nvl(update_parameter.min_n_values, min_n_values), + max_n_values = nvl(update_parameter.max_n_values, max_n_values) + where parameter_id = update_parameter.parameter_id; + return parameter_id; + end; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer + is + v_parameter_p integer; + begin + select decode(count(*),0,0,1) into v_parameter_p + from apm_parameters + where package_key = parameter_p.package_key + and parameter_name = parameter_p.parameter_name; + return v_parameter_p; + end parameter_p; + + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ) + is + begin + delete from apm_parameter_values + where parameter_id = unregister_parameter.parameter_id; + delete from apm_parameters + where parameter_id = unregister_parameter.parameter_id; + acs_object.delete(parameter_id); + end unregister_parameter; + + function id_for_name ( + parameter_name in apm_parameters.parameter_name%TYPE, + package_key in apm_parameters.package_key%TYPE + ) return apm_parameters.parameter_id%TYPE + is + a_parameter_id apm_parameters.parameter_id%TYPE; + begin + select parameter_id into a_parameter_id + from apm_parameters p + where p.parameter_name = id_for_name.parameter_name and + p.package_key = id_for_name.package_key; + return a_parameter_id; + end id_for_name; + + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + value apm_parameter_values.attr_value%TYPE; + begin + select attr_value into value from apm_parameter_values v + where v.package_id = get_value.package_id + and parameter_id = get_value.parameter_id; + return value; + end get_value; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = get_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = get_value.package_id); + return apm.get_value( + parameter_id => v_parameter_id, + package_id => get_value.package_id + ); + end get_value; + + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + -- Determine if the value exists + select value_id into v_value_id from apm_parameter_values + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + update apm_parameter_values set attr_value = set_value.attr_value + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + exception + when NO_DATA_FOUND + then + v_value_id := apm_parameter_value.new( + package_id => package_id, + parameter_id => parameter_id, + attr_value => attr_value + ); + end set_value; + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = set_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = set_value.package_id); + apm.set_value( + parameter_id => v_parameter_id, + package_id => set_value.package_id, + attr_value => set_value.attr_value + ); + end set_value; +end apm; +/ +show errors + +create or replace package body apm_package +as + procedure initialize_parameters ( + package_id in apm_packages.package_id%TYPE, + package_key in apm_package_types.package_key%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + cursor cur is + select parameter_id, default_value + from apm_parameters + where package_key = initialize_parameters.package_key; + begin + -- need to initialize all params for this type + for cur_val in cur + loop + v_value_id := apm_parameter_value.new( + package_id => initialize_parameters.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + end initialize_parameters; + + function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE + is + v_singleton_p integer; + v_package_type apm_package_types.package_type%TYPE; + v_num_instances integer; + v_package_id apm_packages.package_id%TYPE; + v_instance_name apm_packages.instance_name%TYPE; + begin + v_singleton_p := apm_package.singleton_p( + package_key => apm_package.new.package_key + ); + v_num_instances := apm_package.num_instances( + package_key => apm_package.new.package_key + ); + + if v_singleton_p = 1 and v_num_instances >= 1 then + select package_id into v_package_id + from apm_packages + where package_key = apm_package.new.package_key; + return v_package_id; + else + v_package_id := acs_object.new( + object_id => package_id, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + if instance_name is null then + v_instance_name := package_key || ' ' || v_package_id; + else + v_instance_name := instance_name; + end if; + + select package_type into v_package_type + from apm_package_types + where package_key = apm_package.new.package_key; + + insert into apm_packages + (package_id, package_key, instance_name) + values + (v_package_id, package_key, v_instance_name); + + if v_package_type = 'apm_application' then + insert into apm_applications + (application_id) + values + (v_package_id); + else + insert into apm_services + (service_id) + values + (v_package_id); + end if; + + initialize_parameters( + package_id => v_package_id, + package_key => apm_package.new.package_key + ); + return v_package_id; + + end if; +end new; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ) + is + cursor all_values is + select value_id from apm_parameter_values + where package_id = apm_package.delete.package_id; + cursor all_site_nodes is + select node_id from site_nodes + where object_id = apm_package.delete.package_id; + begin + -- Delete all parameters. + for cur_val in all_values loop + apm_parameter_value.delete(value_id => cur_val.value_id); + end loop; + delete from apm_applications where application_id = apm_package.delete.package_id; + delete from apm_services where service_id = apm_package.delete.package_id; + delete from apm_packages where package_id = apm_package.delete.package_id; + -- Delete the site nodes for the objects. + for cur_val in all_site_nodes loop + site_node.delete(cur_val.node_id); + end loop; + -- Delete the object. + acs_object.delete ( + object_id => package_id + ); + end delete; + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer + is + v_singleton_p integer; + begin + select 1 into v_singleton_p + from apm_package_types + where package_key = singleton_p.package_key + and singleton_p = 't'; + return v_singleton_p; + + exception + when NO_DATA_FOUND + then + return 0; + end singleton_p; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_num_instances integer; + begin + select count(*) into v_num_instances + from apm_packages + where package_key = num_instances.package_key; + return v_num_instances; + + exception + when NO_DATA_FOUND + then + return 0; + end num_instances; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2 + is + v_result apm_packages.instance_name%TYPE; + begin + select instance_name into v_result + from apm_packages + where package_id = name.package_id; + + return v_result; + end name; + + procedure enable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 't' + where package_id = enable.package_id; + end enable; + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 'f' + where package_id = disable.package_id; + end disable; + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE + is + v_version_id apm_package_versions.version_id%TYPE; + begin + select version_id into v_version_id + from apm_package_version_info i + where apm_package_version.sortable_version_name(version_name) = + (select max(apm_package_version.sortable_version_name(v.version_name)) + from apm_package_version_info v where v.package_key = highest_version.package_key) + and package_key = highest_version.package_key; + return v_version_id; + exception + when NO_DATA_FOUND + then + return 0; + end highest_version; +end apm_package; +/ +show errors + +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 => 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 + raise_application_error(-20000, 'Expected number at position ' || a_start); + end if; + if a_end - a_start > 4 then + 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.'; + else + -- uhoh... some wacky character. bomb + -- raise_application_error(-20000, 'Illegal character ''' || a_char || + -- ' in version name ' || version_name || ''''); + a_order := a_order || ' OD.'; + end if; + + -- can't have something like 3.3a1b2 - just one letter allowed! + if a_seen_letter = 't' then + 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 + +create or replace package body apm_package_type +as + function create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ) return apm_package_types.package_type%TYPE + is + begin + insert into apm_package_types + (package_key, pretty_name, pretty_plural, package_uri, package_type, + spec_file_path, spec_file_mtime, singleton_p) + values + (create_type.package_key, create_type.pretty_name, create_type.pretty_plural, + create_type.package_uri, create_type.package_type, create_type.spec_file_path, + create_type.spec_file_mtime, create_type.singleton_p); + return create_type.package_key; + end create_type; + + function update_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + UPDATE apm_package_types SET + pretty_name = nvl(update_type.pretty_name, pretty_name), + pretty_plural = nvl(update_type.pretty_plural, pretty_plural), + package_uri = nvl(update_type.package_uri, package_uri), + package_type = nvl(update_type.package_type, package_type), + spec_file_path = nvl(update_type.spec_file_path, spec_file_path), + spec_file_mtime = nvl(update_type.spec_file_mtime, spec_file_mtime), + singleton_p = nvl(update_type.singleton_p, singleton_p) + where package_key = update_type.package_key; + return update_type.package_key; + end update_type; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + cursor all_package_ids is + select package_id + from apm_packages + where package_key = drop_type.package_key; + + cursor all_parameters is + select parameter_id from apm_parameters + where package_key = drop_type.package_key; + + cursor all_versions is + select version_id from apm_package_versions + where package_key = drop_type.package_key; + begin + if cascade_p = 't' then + for cur_val in all_package_ids + loop + apm_package.delete( + package_id => cur_val.package_id + ); + end loop; + -- Unregister all parameters. + for cur_val in all_parameters + loop + apm.unregister_parameter(parameter_id => cur_val.parameter_id); + end loop; + + -- Unregister all versions + for cur_val in all_versions + loop + apm_package_version.delete(version_id => cur_val.version_id); + end loop; + end if; + delete from apm_package_types + where package_key = drop_type.package_key; + end drop_type; + + function num_parameters ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_count integer; + begin + select count(*) into v_count + from apm_parameters + where package_key = num_parameters.package_key; + return v_count; + end num_parameters; + +end apm_package_type; + + +/ +show errors + +create or replace package body apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + v_value_id := acs_object.new( + object_id => value_id, + object_type => 'apm_parameter_value' + ); + insert into apm_parameter_values + (value_id, package_id, parameter_id, attr_value) + values + (v_value_id, apm_parameter_value.new.package_id, + apm_parameter_value.new.parameter_id, + apm_parameter_value.new.attr_value); + return v_value_id; + end new; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ) + is + begin + delete from apm_parameter_values + where value_id = apm_parameter_value.delete.value_id; + acs_object.delete(value_id); + end delete; + + end apm_parameter_value; +/ +show errors; + +create or replace package body apm_application +as + + function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_application_id integer; + begin + v_application_id := apm_package.new ( + package_id => application_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_application_id; + end new; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_applications + where application_id = apm_application.delete.application_id; + apm_package.delete( + package_id => application_id); + end delete; + +end; +/ +show errors + +create or replace package body apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_service_id integer; + begin + v_service_id := apm_package.new ( + package_id => service_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_service_id; + end new; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_services + where service_id = apm_service.delete.service_id; + apm_package.delete( + package_id => service_id + ); + end delete; + +end; +/ +show errors + +alter table group_member_index drop constraint group_member_index_pk; +alter table group_member_index add constraint group_member_index_pk primary key (member_id, group_id, rel_id); + +@@security-drop.sql +@@security-create.sql + +create or replace view acs_messages_all as + select m.message_id, m.reply_to, o.context_id, r.title, r.publish_date, + r.mime_type, r.content, o.creation_user + from acs_objects o, cr_items i, cr_revisions r, acs_messages m + where o.object_id = m.message_id and i.item_id = m.message_id + and r.revision_id = i.live_revision; + +@@../../acs-content-repository/sql/packages-create +@@../../acs-workflow/sql/workflow-case-package +@@../../acs-workflow/sql/workflow-package Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0rc0-4.0.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0rc0-4.0.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.0rc0-4.0.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,1788 @@ +-- +-- /web/bquinn/packages/acs-kernel/sql/upgrade-4.0rc0-4.0.sql +-- +-- Upgrade script from ACS 4.0 RC#0 to ACS 4.0 Production +-- +-- @author Bryan Quinn (bquinn@arsdigita.com) +-- @creation-date Mon Oct 23 10:26:18 2000 +-- @cvs-id $Id: upgrade-4.0rc0-4.0.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ + +-- Update the Content Repository +@@ ../../acs-content-repository/sql/content-update.sql + +-- Update APM Procedures + +-- Public Programmer level API. +create or replace package apm +as + procedure register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ); + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ); + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + -- Informs the APM that this application is available for use. + procedure register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ); + + -- Remove the application from the system. + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this application. + cascade_p in char default 'f' + ); + + procedure register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ); + + -- Remove the service from the system. + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this service. + cascade_p in char default 'f' + ); + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer; + + -- Remove any uses of this parameter. + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ); + + -- Return the value of this parameter for a specific package and parameter. + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + +end apm; +/ +show errors + +create or replace package apm_package +as + +function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ); + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2; + + -- Enable a package to be utilized by a subsite. + procedure enable ( + package_id in apm_packages.package_id%TYPE + ); + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ); + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE; + +end apm_package; +/ +show errors + +create or replace package 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; + + procedure delete ( + version_id in apm_packages.package_id%TYPE + ); + + procedure enable ( + version_id in apm_package_versions.version_id%TYPE + ); + + procedure disable ( + version_id in apm_package_versions.version_id%TYPE + ); + + 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; + + -- Add a file to the indicated version. + 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; + + -- 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 + ); + + -- 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; + + procedure remove_interface( + interface_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- 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; + + procedure remove_dependency( + dependency_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- Given a version_name (e.g. 3.2a), return + -- something that can be lexicographically sorted. + function sortable_version_name ( + version_name in apm_package_versions.version_name%TYPE + ) return varchar2; + + -- Given two version names, return 1 if one > two, -1 if two > one, 0 otherwise. + -- Deprecate? + 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; + + 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; + + procedure upgrade( + version_id in apm_package_versions.version_id%TYPE + ); + +end apm_package_version; +/ +show errors + +create or replace package apm_package_type +as + procedure create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ); + + function update_type ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ); + + function num_parameters ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + +end apm_package_type; +/ +show errors + + + +-- Private APM System API for managing parameter values. +create or replace package apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ); + end apm_parameter_value; +/ +show errors + +create or replace package apm_application +as + +function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + + +create or replace package apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + +create or replace package body apm +as + procedure register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm_package_type.create_type( + package_key => register_package.package_key, + pretty_name => register_package.pretty_name, + pretty_plural => register_package.pretty_plural, + package_uri => register_package.package_uri, + package_type => register_package.package_type, + singleton_p => register_package.singleton_p, + spec_file_path => register_package.spec_file_path, + spec_file_mtime => spec_file_mtime + ); + end register_package; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + + return apm_package_type.update_type( + package_key => update_package.package_key, + pretty_name => update_package.pretty_name, + pretty_plural => update_package.pretty_plural, + package_uri => update_package.package_uri, + package_type => update_package.package_type, + singleton_p => update_package.singleton_p, + spec_file_path => update_package.spec_file_path, + spec_file_mtime => update_package.spec_file_mtime + ); + + end update_package; + + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ) + is + begin + apm_package_type.drop_type( + package_key => unregister_package.package_key, + cascade_p => unregister_package.cascade_p + ); + end unregister_package; + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_register_p integer; + begin + select decode(count(*),0,0,1) into v_register_p from apm_package_types + where package_key = register_p.package_key; + return v_register_p; + end register_p; + + procedure register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm.register_package( + package_key => register_application.package_key, + pretty_name => register_application.pretty_name, + pretty_plural => register_application.pretty_plural, + package_uri => register_application.package_uri, + package_type => 'apm_application', + singleton_p => register_application.singleton_p, + spec_file_path => register_application.spec_file_path, + spec_file_mtime => register_application.spec_file_mtime + ); + end register_application; + + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_application.package_key, + cascade_p => unregister_application.cascade_p + ); + end unregister_application; + + procedure register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) + is + begin + apm.register_package( + package_key => register_service.package_key, + pretty_name => register_service.pretty_name, + pretty_plural => register_service.pretty_plural, + package_uri => register_service.package_uri, + package_type => 'apm_service', + singleton_p => register_service.singleton_p, + spec_file_path => register_service.spec_file_path, + spec_file_mtime => register_service.spec_file_mtime + ); + end register_service; + + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_service.package_key, + cascade_p => unregister_service.cascade_p + ); + end unregister_service; + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE + is + v_parameter_id apm_parameters.parameter_id%TYPE; + cursor all_parameters is + select ap.package_id, v.parameter_id, p.default_value + from apm_parameters p, apm_parameter_values v, apm_packages ap + where p.package_key = ap.package_key + and v.package_id = ap.package_id + and p.parameter_id = v.parameter_id + and v.attr_value is null + and p.package_key = register_parameter.package_key; + begin + -- Create the new parameter. + v_parameter_id := acs_object.new( + object_id => parameter_id, + object_type => 'apm_parameter' + ); + + insert into apm_parameters + (parameter_id, parameter_name, description, package_key, datatype, + default_value, section_name, min_n_values, max_n_values) + values + (v_parameter_id, register_parameter.parameter_name, register_parameter.description, + register_parameter.package_key, register_parameter.datatype, + register_parameter.default_value, register_parameter.section_name, + register_parameter.min_n_values, register_parameter.max_n_values); + -- Propagate parameter to new instances. + for cur_val in all_parameters + loop + apm.set_value( + package_id => cur_val.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + return v_parameter_id; + end register_parameter; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE + is + begin + update apm_parameters + set parameter_name = nvl(update_parameter.parameter_name, parameter_name), + default_value = nvl(update_parameter.default_value, default_value), + datatype = nvl(update_parameter.datatype, datatype), + description = nvl(update_parameter.description, description), + section_name = nvl(update_parameter.section_name, section_name), + min_n_values = nvl(update_parameter.min_n_values, min_n_values), + max_n_values = nvl(update_parameter.max_n_values, max_n_values) + where parameter_id = update_parameter.parameter_id; + return parameter_id; + end; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer + is + v_parameter_p integer; + begin + select decode(count(*),0,0,1) into v_parameter_p + from apm_parameters + where package_key = parameter_p.package_key + and parameter_name = parameter_p.parameter_name; + return v_parameter_p; + end parameter_p; + + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ) + is + begin + delete from apm_parameter_values + where parameter_id = unregister_parameter.parameter_id; + delete from apm_parameters + where parameter_id = unregister_parameter.parameter_id; + acs_object.delete(parameter_id); + end unregister_parameter; + + function id_for_name ( + parameter_name in apm_parameters.parameter_name%TYPE, + package_key in apm_parameters.package_key%TYPE + ) return apm_parameters.parameter_id%TYPE + is + a_parameter_id apm_parameters.parameter_id%TYPE; + begin + select parameter_id into a_parameter_id + from apm_parameters p + where p.parameter_name = id_for_name.parameter_name and + p.package_key = id_for_name.package_key; + return a_parameter_id; + end id_for_name; + + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + value apm_parameter_values.attr_value%TYPE; + begin + select attr_value into value from apm_parameter_values v + where v.package_id = get_value.package_id + and parameter_id = get_value.parameter_id; + return value; + end get_value; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = get_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = get_value.package_id); + return apm.get_value( + parameter_id => v_parameter_id, + package_id => get_value.package_id + ); + end get_value; + + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + -- Determine if the value exists + select value_id into v_value_id from apm_parameter_values + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + update apm_parameter_values set attr_value = set_value.attr_value + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + exception + when NO_DATA_FOUND + then + v_value_id := apm_parameter_value.new( + package_id => package_id, + parameter_id => parameter_id, + attr_value => attr_value + ); + end set_value; + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = set_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = set_value.package_id); + apm.set_value( + parameter_id => v_parameter_id, + package_id => set_value.package_id, + attr_value => set_value.attr_value + ); + exception + when NO_DATA_FOUND + then + RAISE_APPLICATION_ERROR(-20000, 'The specified package ' || set_value.package_id || + ' does not exist in the system.'); + end set_value; +end apm; +/ +show errors + +create or replace package body apm_package +as + procedure initialize_parameters ( + package_id in apm_packages.package_id%TYPE, + package_key in apm_package_types.package_key%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + cursor cur is + select parameter_id, default_value + from apm_parameters + where package_key = initialize_parameters.package_key; + begin + -- need to initialize all params for this type + for cur_val in cur + loop + v_value_id := apm_parameter_value.new( + package_id => initialize_parameters.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + end initialize_parameters; + + function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE + is + v_singleton_p integer; + v_package_type apm_package_types.package_type%TYPE; + v_num_instances integer; + v_package_id apm_packages.package_id%TYPE; + v_instance_name apm_packages.instance_name%TYPE; + begin + v_singleton_p := apm_package.singleton_p( + package_key => apm_package.new.package_key + ); + v_num_instances := apm_package.num_instances( + package_key => apm_package.new.package_key + ); + + if v_singleton_p = 1 and v_num_instances >= 1 then + select package_id into v_package_id + from apm_packages + where package_key = apm_package.new.package_key; + return v_package_id; + else + v_package_id := acs_object.new( + object_id => package_id, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + if instance_name is null then + v_instance_name := package_key || ' ' || v_package_id; + else + v_instance_name := instance_name; + end if; + + select package_type into v_package_type + from apm_package_types + where package_key = apm_package.new.package_key; + + insert into apm_packages + (package_id, package_key, instance_name) + values + (v_package_id, package_key, v_instance_name); + + if v_package_type = 'apm_application' then + insert into apm_applications + (application_id) + values + (v_package_id); + else + insert into apm_services + (service_id) + values + (v_package_id); + end if; + + initialize_parameters( + package_id => v_package_id, + package_key => apm_package.new.package_key + ); + return v_package_id; + + end if; +end new; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ) + is + cursor all_values is + select value_id from apm_parameter_values + where package_id = apm_package.delete.package_id; + cursor all_site_nodes is + select node_id from site_nodes + where object_id = apm_package.delete.package_id; + begin + -- Delete all parameters. + for cur_val in all_values loop + apm_parameter_value.delete(value_id => cur_val.value_id); + end loop; + delete from apm_applications where application_id = apm_package.delete.package_id; + delete from apm_services where service_id = apm_package.delete.package_id; + delete from apm_packages where package_id = apm_package.delete.package_id; + -- Delete the site nodes for the objects. + for cur_val in all_site_nodes loop + site_node.delete(cur_val.node_id); + end loop; + -- Delete the object. + acs_object.delete ( + object_id => package_id + ); + end delete; + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer + is + v_singleton_p integer; + begin + select 1 into v_singleton_p + from apm_package_types + where package_key = singleton_p.package_key + and singleton_p = 't'; + return v_singleton_p; + + exception + when NO_DATA_FOUND + then + return 0; + end singleton_p; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_num_instances integer; + begin + select count(*) into v_num_instances + from apm_packages + where package_key = num_instances.package_key; + return v_num_instances; + + exception + when NO_DATA_FOUND + then + return 0; + end num_instances; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2 + is + v_result apm_packages.instance_name%TYPE; + begin + select instance_name into v_result + from apm_packages + where package_id = name.package_id; + + return v_result; + end name; + + procedure enable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 't' + where package_id = enable.package_id; + end enable; + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 'f' + where package_id = disable.package_id; + end disable; + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE + is + v_version_id apm_package_versions.version_id%TYPE; + begin + select version_id into v_version_id + from apm_package_version_info i + where apm_package_version.sortable_version_name(version_name) = + (select max(apm_package_version.sortable_version_name(v.version_name)) + from apm_package_version_info v where v.package_key = highest_version.package_key) + and package_key = highest_version.package_key; + return v_version_id; + exception + when NO_DATA_FOUND + then + return 0; + end highest_version; +end apm_package; +/ +show errors + +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 => 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 + raise_application_error(-20000, 'Expected number at position ' || a_start); + end if; + if a_end - a_start > 4 then + 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 + 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 + +create or replace package body apm_package_type +as + procedure create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ) + is + begin + insert into apm_package_types + (package_key, pretty_name, pretty_plural, package_uri, package_type, + spec_file_path, spec_file_mtime, singleton_p) + values + (create_type.package_key, create_type.pretty_name, create_type.pretty_plural, + create_type.package_uri, create_type.package_type, create_type.spec_file_path, + create_type.spec_file_mtime, create_type.singleton_p); + end create_type; + + function update_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + UPDATE apm_package_types SET + pretty_name = nvl(update_type.pretty_name, pretty_name), + pretty_plural = nvl(update_type.pretty_plural, pretty_plural), + package_uri = nvl(update_type.package_uri, package_uri), + package_type = nvl(update_type.package_type, package_type), + spec_file_path = nvl(update_type.spec_file_path, spec_file_path), + spec_file_mtime = nvl(update_type.spec_file_mtime, spec_file_mtime), + singleton_p = nvl(update_type.singleton_p, singleton_p) + where package_key = update_type.package_key; + return update_type.package_key; + end update_type; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + cursor all_package_ids is + select package_id + from apm_packages + where package_key = drop_type.package_key; + + cursor all_parameters is + select parameter_id from apm_parameters + where package_key = drop_type.package_key; + + cursor all_versions is + select version_id from apm_package_versions + where package_key = drop_type.package_key; + begin + if cascade_p = 't' then + for cur_val in all_package_ids + loop + apm_package.delete( + package_id => cur_val.package_id + ); + end loop; + -- Unregister all parameters. + for cur_val in all_parameters + loop + apm.unregister_parameter(parameter_id => cur_val.parameter_id); + end loop; + + -- Unregister all versions + for cur_val in all_versions + loop + apm_package_version.delete(version_id => cur_val.version_id); + end loop; + end if; + delete from apm_package_types + where package_key = drop_type.package_key; + end drop_type; + + function num_parameters ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_count integer; + begin + select count(*) into v_count + from apm_parameters + where package_key = num_parameters.package_key; + return v_count; + end num_parameters; + +end apm_package_type; + + +/ +show errors + +create or replace package body apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + v_value_id := acs_object.new( + object_id => value_id, + object_type => 'apm_parameter_value' + ); + insert into apm_parameter_values + (value_id, package_id, parameter_id, attr_value) + values + (v_value_id, apm_parameter_value.new.package_id, + apm_parameter_value.new.parameter_id, + apm_parameter_value.new.attr_value); + return v_value_id; + end new; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ) + is + begin + delete from apm_parameter_values + where value_id = apm_parameter_value.delete.value_id; + acs_object.delete(value_id); + end delete; + + end apm_parameter_value; +/ +show errors; + +create or replace package body apm_application +as + + function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_application_id integer; + begin + v_application_id := apm_package.new ( + package_id => application_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_application_id; + end new; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_applications + where application_id = apm_application.delete.application_id; + apm_package.delete( + package_id => application_id); + end delete; + +end; +/ +show errors + +create or replace package body apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_service_id integer; + begin + v_service_id := apm_package.new ( + package_id => service_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_service_id; + end new; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_services + where service_id = apm_service.delete.service_id; + apm_package.delete( + package_id => service_id + ); + end delete; + +end; +/ +show errors + Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1-4.1.1.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1-4.1.1.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1-4.1.1.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,189 @@ +-- +-- /packages/acs-kernel/sql/upgrade/upgrade-4.1-4.1.1.sql +-- +-- Upgrades ACS Kernel 4.1 to ACS Kernel 4.1.1 +-- +-- @author Multiple +-- @creation-date 2001-01-23 +-- @cvs-id $Id: upgrade-4.1-4.1.1.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ + + +-------------------------------------------------------------- +-- Relational Constraints Views +-- oumi@arsdigita.com +-- 1/23/2001 +-- +-- CHANGES +-- Added some views and modified one view to fix minor bugs +-- and make it possible to fix some UI issues in ACS Subsites +-------------------------------------------------------------- + +-- View: rc_all_constraints +-- +-- Question: Given group :group_id and rel_type :rel_type . . . +-- +-- What segments must a party be in +-- if the party were to be on side :rel_side of a relation of +-- type :rel_type to group :group_id ? +-- +-- Answer: select required_rel_segment +-- from rc_all_constraints +-- where group_id = :group_id +-- and rel_type = :rel_type +-- and rel_side = :rel_side +-- +create or replace view rc_all_constraints as +select group_ancestor_map.group_id, + type_map.object_type as rel_type, + rel_constraints.rel_segment, + rel_constraints.rel_side, + required_rel_segment + from rel_constraints, + rel_segments, + (select object_type, ancestor_type + from acs_object_type_supertype_map + union all + select object_type, object_type + from acs_object_types) type_map, + (select component_id as group_id, + group_id as ancestor_group_id + from group_component_map + union all + select group_id as component_group_id, + group_id as ancestor_group_id + from groups) group_ancestor_map + where rel_constraints.rel_segment = rel_segments.segment_id + and rel_segments.group_id = group_ancestor_map.ancestor_group_id + and rel_segments.rel_type = type_map.ancestor_type; + + +create or replace view rc_all_distinct_constraints as +select distinct + group_id, rel_type, rel_segment, rel_side, required_rel_segment +from rc_all_constraints; + + +-- THIS VIEW IS FOR COMPATIBILITY WITH EXISTING CODE +-- New code should use rc_all_constraints instead! +-- +-- 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 distinct group_id, rel_type, required_rel_segment +from rc_all_constraints +where 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_combos.group_id, + group_rel_type_combos.rel_type, + parties.party_id +from rc_required_rel_segments, + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type from acs_object_types + start with object_type = 'membership_rel' + or object_type = 'composition_rel' + connect by supertype = prior object_type) comp_or_member_rel_types + ) group_rel_type_combos, + parties +where rc_required_rel_segments.group_id(+) = group_rel_type_combos.group_id + and rc_required_rel_segments.rel_type(+) = group_rel_type_combos.rel_type + and rc_required_rel_segments.group_id is null; + + +-- View: rc_valid_rel_types +-- +-- Question: What types of membership or composition are "valid" +-- for group :group_id ? A membership or composition +-- type R is "valid" when no relational constraints would +-- be violated if a party were to belong to group :group_id +-- through a rel of type R. +-- +-- Answer: select rel_type +-- from rc_valid_rel_types +-- where group_id = :group_id +-- +-- +create or replace view rc_valid_rel_types as +select side_one_constraints.group_id, + side_one_constraints.rel_type + from (select required_segs.group_id, + required_segs.rel_type, + count(*) as num_satisfied + from rc_all_constraints required_segs, + rel_segment_party_map map + where required_segs.rel_side = 'one' + and required_segs.required_rel_segment = map.segment_id + and required_segs.group_id = map.party_id + group by required_segs.group_id, + required_segs.rel_type) side_one_constraints, + (select group_id, rel_type, count(*) as total + from rc_all_constraints + where rel_side = 'one' + group by group_id, rel_type) total_side_one_constraints + where side_one_constraints.group_id = total_side_one_constraints.group_id + and side_one_constraints.rel_type = total_side_one_constraints.rel_type + and side_one_constraints.num_satisfied = total_side_one_constraints.total +UNION ALL +select group_rel_type_combos.group_id, + group_rel_type_combos.rel_type +from rc_all_constraints, + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type from acs_object_types + start with object_type = 'membership_rel' + or object_type = 'composition_rel' + connect by supertype = prior object_type) comp_or_member_rel_types + ) group_rel_type_combos +where rc_all_constraints.group_id(+) = group_rel_type_combos.group_id + and rc_all_constraints.rel_type(+) = group_rel_type_combos.rel_type + and rc_all_constraints.group_id is null; + Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1.1-4.2.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1.1-4.2.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1.1-4.2.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,1086 @@ +create or replace package site_node +as + + -- Create a new site node. If you set directory_p to be 'f' then you + -- cannot create nodes that have this node as their parent. + + function new ( + node_id in site_nodes.node_id%TYPE default null, + parent_id in site_nodes.node_id%TYPE default null, + name in site_nodes.name%TYPE, + object_id in site_nodes.object_id%TYPE default null, + directory_p in site_nodes.directory_p%TYPE, + pattern_p in site_nodes.pattern_p%TYPE default 'f', + creation_user in acs_objects.creation_user%TYPE default null, + creation_ip in acs_objects.creation_ip%TYPE default null + ) return site_nodes.node_id%TYPE; + + -- Delete a site node. + + procedure delete ( + node_id in site_nodes.node_id%TYPE + ); + + -- Return the node_id of a url. If the url begins with '/' then the + -- parent_id must be null. This will raise the no_data_found + -- exception if there is no mathing node in the site_nodes table. + -- This will match directories even if no trailing slash is included + -- in the url. + + function node_id ( + url in varchar2, + parent_id in site_nodes.node_id%TYPE default null + ) return site_nodes.node_id%TYPE; + + -- Return the url of a node_id. + + function url ( + node_id in site_nodes.node_id%TYPE + ) return varchar2; + +end; +/ +show errors + +create or replace package body site_node +as + + function new ( + node_id in site_nodes.node_id%TYPE default null, + parent_id in site_nodes.node_id%TYPE default null, + name in site_nodes.name%TYPE, + object_id in site_nodes.object_id%TYPE default null, + directory_p in site_nodes.directory_p%TYPE, + pattern_p in site_nodes.pattern_p%TYPE default 'f', + creation_user in acs_objects.creation_user%TYPE default null, + creation_ip in acs_objects.creation_ip%TYPE default null + ) return site_nodes.node_id%TYPE + is + v_node_id site_nodes.node_id%TYPE; + v_directory_p site_nodes.directory_p%TYPE; + begin + if parent_id is not null then + select directory_p into v_directory_p + from site_nodes + where node_id = new.parent_id; + + if v_directory_p = 'f' then + raise_application_error ( + -20000, + 'Node ' || parent_id || ' is not a directory' + ); + end if; + end if; + + v_node_id := acs_object.new ( + object_id => node_id, + object_type => 'site_node', + creation_user => creation_user, + creation_ip => creation_ip + ); + + insert into site_nodes + (node_id, parent_id, name, object_id, directory_p, pattern_p) + values + (v_node_id, new.parent_id, new.name, new.object_id, + new.directory_p, new.pattern_p); + + return v_node_id; + end; + + procedure delete ( + node_id in site_nodes.node_id%TYPE + ) + is + begin + delete from site_nodes + where node_id = site_node.delete.node_id; + + acs_object.delete(node_id); + end; + + function find_pattern ( + node_id in site_nodes.node_id%TYPE + ) return site_nodes.node_id%TYPE + is + v_pattern_p site_nodes.pattern_p%TYPE; + v_parent_id site_nodes.node_id%TYPE; + begin + if node_id is null then + raise no_data_found; + end if; + + select pattern_p, parent_id into v_pattern_p, v_parent_id + from site_nodes + where node_id = find_pattern.node_id; + + if v_pattern_p = 't' then + return node_id; + else + return find_pattern(v_parent_id); + end if; + end; + + function node_id ( + url in varchar2, + parent_id in site_nodes.node_id%TYPE default null + ) return site_nodes.node_id%TYPE + is + v_pos integer; + v_first site_nodes.name%TYPE; + v_rest varchar2(4000); + v_node_id integer; + v_pattern_p site_nodes.pattern_p%TYPE; + v_url varchar2(4000); + v_directory_p site_nodes.directory_p%TYPE; + v_trailing_slash_p char(1); + begin + v_url := url; + + if substr(v_url, length(v_url), 1) = '/' then + -- It ends with a / so it must be a directory. + v_trailing_slash_p := 't'; + v_url := substr(v_url, 1, length(v_url) - 1); + end if; + + v_pos := 1; + + while v_pos <= length(v_url) and substr(v_url, v_pos, 1) != '/' loop + v_pos := v_pos + 1; + end loop; + + if v_pos = length(v_url) then + v_first := v_url; + v_rest := null; + else + v_first := substr(v_url, 1, v_pos - 1); + v_rest := substr(v_url, v_pos + 1); + end if; + + begin + -- Is there a better way to do these freaking null compares? + select node_id, directory_p into v_node_id, v_directory_p + from site_nodes + where nvl(parent_id, 3.14) = nvl(site_node.node_id.parent_id, 3.14) + and nvl(name, chr(10)) = nvl(v_first, chr(10)); + exception + when no_data_found then + return find_pattern(parent_id); + end; + + if v_rest is null then + if v_trailing_slash_p = 't' and v_directory_p = 'f' then + return find_pattern(parent_id); + else + return v_node_id; + end if; + else + return node_id(v_rest, v_node_id); + end if; + end; + + function url ( + node_id in site_nodes.node_id%TYPE + ) return varchar2 + is + v_parent_id site_nodes.node_id%TYPE; + v_name site_nodes.name%TYPE; + v_directory_p site_nodes.directory_p%TYPE; + begin + if node_id is null then + return ''; + end if; + + select parent_id, name, directory_p into + v_parent_id, v_name, v_directory_p + from site_nodes + where node_id = url.node_id; + + if v_directory_p = 't' then + return url(v_parent_id) || v_name || '/'; + else + return url(v_parent_id) || v_name; + end if; + end; + +end; +/ +show errors + +-------------------------------------------------------------- +-- Relational Segments Views +-- oumi@arsdigita.com +-- 2/13/2001 +-- +-- CHANGES +-- Optimization improvement of rel_segment_party_map. +-- Added rel_segment_group_rel_type_map. This view simplifies +-- the logic in other queries and 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, + group_element_map gem + where gem.group_id = rs.group_id + and rs.rel_type in (select object_type + from acs_object_types + start with object_type = gem.rel_type + connect by prior supertype = object_type); + +create or replace view rel_seg_approved_member_map +as select /*+ ordered */ + rs.segment_id, gem.element_id as member_id, gem.rel_id, gem.rel_type, + gem.group_id, gem.container_id + from membership_rels mr, group_element_map gem, rel_segments rs + where rs.group_id = gem.group_id + and rs.rel_type in (select object_type + from acs_object_types + start with object_type = gem.rel_type + connect by prior supertype = object_type) + and mr.rel_id = gem.rel_id and mr.member_state = 'approved'; + + +-- View: rel_segment_group_rel_type_map +-- +-- Result Set: the set of triples (:segment_id, :group_id, :rel_type) such that +-- +-- IF a party were to be in :group_id +-- through a relation of type :rel_type, +-- THEN the party would necessarily be in segment :segemnt_id. +-- +-- +create or replace view rel_segment_group_rel_type_map as +select s.segment_id, + gcm.component_id as group_id, + acs_rel_types.rel_type as rel_type +from rel_segments s, + (select group_id, component_id + from group_component_map + UNION ALL + select group_id, group_id as component_id + from groups) gcm, + acs_rel_types +where s.group_id = gcm.group_id + and s.rel_type in (select object_type from acs_object_types + start with object_type = acs_rel_types.rel_type + connect by prior supertype = object_type); + + +-------------------------------------------------------------- +-- Relational Constraints Views +-- oumi@arsdigita.com +-- 2/9/2001 - 2/13/2001 +-- +-- CHANGES +-- +-- Added rc_segment_required_segment_map and +-- rc_dependency_levels (these views save us from having to +-- write, tune, and comment connect by queries on +-- rel_constraints in our application code). + +-- Rewrote rc_all_constraints to use the new +-- rel_segment_group_rel_type_map view. More importantly, the +-- rc_all_constraints view now avoids returning circular +-- constraints (see comments on the rc_all_constraints view). +-- +-- Fixed rc_valid_rel_types. The query under "UNION ALL" +-- wasn't limiting the all_constraints view to side one +-- constraints. The result was that fewer rows were returned +-- than what you might expect. +-------------------------------------------------------------- + +-- View: rc_all_constraints +-- +-- Question: Given group :group_id and rel_type :rel_type . . . +-- +-- What segments must a party be in +-- if the party were to be on side :rel_side of a relation of +-- type :rel_type to group :group_id ? +-- +-- Answer: select required_rel_segment +-- from rc_all_constraints +-- where group_id = :group_id +-- and rel_type = :rel_type +-- and rel_side = :rel_side +-- +-- Notes: we take special care not to get identity rows, where group_id and +-- rel_type are equivalent to segment_id. This can happen if there are some +-- funky constraints in the system, such as membership to Arsdigita requires +-- user_profile to Arsdigita. Then you could get rows from the +-- rc_all_constraints view saying that: +-- user_profile to Arsdigita +-- requires being in the segment of Arsdigita Users. +-- +-- This happens because user_profile is a type of memebrship, and there's a +-- constraint saying that membership to Arsdigita requires being in the +-- Arsdigita Users segment. We eliminate such rows from the rc_all_constraints +-- view with the "not (...)" clause below. +-- +create or replace view rc_all_constraints as +select group_rel_types.group_id, + group_rel_types.rel_type, + rel_constraints.rel_segment, + rel_constraints.rel_side, + required_rel_segment + from rel_constraints, + rel_segment_group_rel_type_map group_rel_types, + rel_segments req_seg + where rel_constraints.rel_segment = group_rel_types.segment_id + and rel_constraints.required_rel_segment = req_seg.segment_id + and not (req_seg.group_id = group_rel_types.group_id and + req_seg.rel_type = group_rel_types.rel_type); + +create or replace view rc_valid_rel_types as +select side_one_constraints.group_id, + side_one_constraints.rel_type + from (select required_segs.group_id, + required_segs.rel_type, + count(*) as num_satisfied + from rc_all_constraints required_segs, + rel_segment_party_map map + where required_segs.rel_side = 'one' + and required_segs.required_rel_segment = map.segment_id + and required_segs.group_id = map.party_id + group by required_segs.group_id, + required_segs.rel_type) side_one_constraints, + (select group_id, rel_type, count(*) as total + from rc_all_constraints + where rel_side = 'one' + group by group_id, rel_type) total_side_one_constraints + where side_one_constraints.group_id = total_side_one_constraints.group_id + and side_one_constraints.rel_type = total_side_one_constraints.rel_type + and side_one_constraints.num_satisfied = total_side_one_constraints.total +UNION ALL +select group_rel_type_combos.group_id, + group_rel_type_combos.rel_type +from (select * from rc_all_constraints where rel_side='one') rc_all_constraints, + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type from acs_object_types + start with object_type = 'membership_rel' + or object_type = 'composition_rel' + connect by supertype = prior object_type) comp_or_member_rel_types + ) group_rel_type_combos +where rc_all_constraints.group_id(+) = group_rel_type_combos.group_id + and rc_all_constraints.rel_type(+) = group_rel_type_combos.rel_type + and rc_all_constraints.group_id is null; + + +-- View: rc_segment_required_seg_map +-- +-- Question: Given a relational segment :rel_segment . . . +-- +-- What are all the segments in the system that a party has to +-- be in if the party were to be on side :rel_side of a relation +-- in segement :rel_segment? +-- +-- We want not only the direct required_segments (which we could +-- get from the rel_constraints table directly), but also the +-- indirect ones (i.e., the segments that are required by the +-- required segments, and so on). +-- +-- Answer: select required_rel_segment +-- from rc_segment_required_seg_map +-- where rel_segment = :rel_segment +-- and rel_side = :rel_side +-- +-- +create or replace view rc_segment_required_seg_map as +select rc.rel_segment, rc.rel_side, rc_required.required_rel_segment +from rel_constraints rc, rel_constraints rc_required +where rc.rel_segment in ( + select rel_segment + from rel_constraints + start with rel_segment = rc_required.rel_segment + connect by required_rel_segment = prior rel_segment + and prior rel_side = 'two' + ); + +-- View: rc_segment_dependency_levels +-- +-- This view is designed to determine what order of segments is safe +-- to use when adding a party to multiple segments. +-- +-- Question: Given a table or view called segments_I_want_to_be_in, +-- which segments can I add a party to first, without violating +-- any relational constraints? +-- +-- Answer: select segment_id +-- from segments_I_want_to_be_in s, +-- rc_segment_dependency_levels dl +-- where s.segment_id = dl.segment_id(+) +-- order by nvl(dl.dependency_level, 0) +-- +-- Note: dependency_level = 1 is the minimum dependency level. +-- dependency_level = N means that you cannot add a party to the +-- segment until you first add the party to some +-- segment of dependency_level N-1 (this view doesn't +-- tell you which segment -- you can get that info +-- from rel_constraints table or other views. +-- +-- Another Note: not all segemnts in rel_segemnts are returned by this view. +-- This view only returns segments S that have at least one rel_constraints row +-- where rel_segment = S. Segments that have no constraints defined on them +-- can be said to have dependency_level=0, hence the outer join and nvl in the +-- example query above (see "Answer:"). I could have embeded that logic into +-- this view, but that would unnecessarily degrade performance. +-- +create or replace view rc_segment_dependency_levels as + select rel_segment as segment_id, + max(tree_level) as dependency_level + from (select rel_segment, level as tree_level + from rel_constraints + connect by required_rel_segment = prior rel_segment + and prior rel_side = 'two') + group by rel_segment +; + +-------------------------------------------------------------- +-- Relationship Type Views +-- oumi@arsdigita.com +-- 2/9/2001 +-- +-- created in acs-relationships-create.sql +-------------------------------------------------------------- + +-- These views are handy for metadata driven UI + +-- View: rel_types_valid_obj_one_types +-- +-- Question: Given rel_type :rel_type, +-- +-- What are all the valid object_types for object_id_one of +-- a relation of type :rel_type +-- +-- Answer: select object_type +-- from rel_types_valid_obj__one_types +-- where rel_type = :rel_type +-- +create or replace view rel_types_valid_obj_one_types as +select rt.rel_type, th.object_type +from acs_rel_types rt, + (select object_type, ancestor_type + from acs_object_type_supertype_map + UNION ALL + select object_type, object_type as ancestor_type + from acs_object_types) th +where rt.object_type_one = th.ancestor_type; + + +-- View: rel_types_valid_obj_two_types +-- +-- Question: Given rel_type :rel_type, +-- +-- What are all the valid object_types for object_id_two of +-- a relation of type :rel_type +-- +-- Answer: select object_type +-- from rel_types_valid_obj_two_types +-- where rel_type = :rel_type +-- +create or replace view rel_types_valid_obj_two_types as +select rt.rel_type, th.object_type +from acs_rel_types rt, + (select object_type, ancestor_type + from acs_object_type_supertype_map + UNION ALL + select object_type, object_type as ancestor_type + from acs_object_types) th +where rt.object_type_two = th.ancestor_type; + + +-------------------------------------------------------------- +-- community-core.sql +-- oumi@arsdigita.com +-- 2/13/2001 +-- +-- CHANGES +-- Added first_names and last_name as attributes of a person. +-- The subsite pages use this metadata to generate forms for +-- adding parties to a subsite. +-------------------------------------------------------------- + +declare + attr_id integer; +begin + + attr_id := acs_attribute.create_attribute ( + object_type => 'person', + attribute_name => 'first_names', + datatype => 'string', + pretty_name => 'First Names', + pretty_plural => 'First Names', + min_n_values => 0, + max_n_values => 1 + ); + + attr_id := acs_attribute.create_attribute ( + object_type => 'person', + attribute_name => 'last_name', + datatype => 'string', + pretty_name => 'Last Name', + pretty_plural => 'Last Names', + min_n_values => 0, + max_n_values => 1 + ); + +end; +/ +show errors + + +-------------------------------------------------------------- +-- groups-create.sql +-- oumi@arsdigita.com +-- 2/22/2001 +-- +-- Changes: +-- Added rel_type to the group_approved_member_map view. +-- Fixed the approval policy / default new member policy stuff +-------------------------------------------------------------- + +/* Restrict membership to persons. Previously, a group could be a member + * of another group. Now, only a person can be a member of a group. + * A group can still be a component of another group through a composition + * relation + */ +update acs_rel_types +set object_type_two='person' +where rel_type = 'membership_rel'; + +create or replace view group_approved_member_map +as select gm.group_id, gm.member_id, gm.rel_id, gm.container_id, gm.rel_type + from group_member_map gm, membership_rels mr + where gm.rel_id = mr.rel_id + and mr.member_state = 'approved'; + + +-- Replace approval_policy and default_new_member_policy with join_policy, +-- because the original columns didn't make much sense, had no check +-- constraints, weren't used by any code, etc. +alter table group_types add ( + default_join_policy varchar2(30) default 'open' not null + constraint group_types_join_policy_ck + check (default_join_policy in + ('open', 'needs approval', 'closed')) +); +alter table group_types drop column approval_policy; +alter table group_types drop column default_new_member_policy; + +alter table groups add ( + join_policy varchar2(30) default 'open' not null + constraint groups_join_policy_ck + check (join_policy in + ('open', 'needs approval', 'closed')) +); + +alter table membership_rels drop constraint membership_rel_mem_ck; +alter table membership_rels add constraint membership_rel_mem_ck + check (member_state in ('approved', 'needs approval', 'banned', 'rejected', 'deleted')); + +update membership_rels + set member_state = 'needs approval' +where member_state is null; + +commit; + +alter table membership_rels modify + member_state not null; + + +-- Now we change the default member_state value in the pl/sql packages + +create or replace package 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 'approved', + 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; + + procedure ban ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure approve ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure reject ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure unapprove ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure deleted ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure delete ( + rel_id in membership_rels.rel_id%TYPE + ); + + function check_representation ( + rel_id in membership_rels.rel_id%TYPE + ) return char; + +end membership_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 'approved', + 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 = 'needs approval' + 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 + +-- Next, we add join_policy to the acs_group pl/sql package + +create or replace package 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, + join_policy in groups.join_policy%TYPE default null, + context_id in acs_objects.context_id%TYPE default null + ) return groups.group_id%TYPE; + + procedure delete ( + group_id in groups.group_id%TYPE + ); + + function name ( + group_id in groups.group_id%TYPE + ) return varchar2; + + function member_p ( + party_id in parties.party_id%TYPE + ) return char; + + function check_representation ( + group_id in groups.group_id%TYPE + ) return char; + +end acs_group; +/ +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, + join_policy in groups.join_policy%TYPE default null, + context_id in acs_objects.context_id%TYPE default null + ) + return groups.group_id%TYPE + is + v_group_id groups.group_id%TYPE; + v_group_type_exists_p integer; + v_join_policy groups.join_policy%TYPE; + begin + v_group_id := + party.new(group_id, object_type, creation_date, creation_user, + creation_ip, email, url, context_id); + + v_join_policy := join_policy; + + -- if join policy wasn't specified, select the default based on group type + if v_join_policy is null then + select count(*) into v_group_type_exists_p + from group_types + where group_type = object_type; + + if v_group_type_exists_p = 1 then + select default_join_policy into v_join_policy + from group_types + where group_type = object_type; + else + v_join_policy := 'open'; + end if; + end if; + + insert into groups + (group_id, group_name, join_policy) + values + (v_group_id, group_name, v_join_policy); + + + -- setup the permissable 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 varchar2(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 + +-------------------------------------------------------------- +-- acs-permissions-create.sql +-- oumi@arsdigita.com +-- 2/21/2001 +-- +-- CHANGES +-- +-- Modified acs_object_party_privilege_map to only map permissions on to +-- approved members of groups and segments, rather than all members. +-- +-- Added views to provide an alternative to +-- acs_object_party_privilege_map that may be faster in many +-- cases. +-------------------------------------------------------------- + +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_approved_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_seg_approved_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; + +create or replace view acs_grantee_party_map as + select -1 as grantee_id, 0 as party_id from dual + union all + select -1 as grantee_id, user_id as party_id + from users + union all + select party_id as grantee_id, party_id + from parties + union all + select segment_id as grantee_id, member_id + from rel_seg_approved_member_map + union all + select group_id as grantee_id, member_id as party_id + from group_approved_member_map; + + +-- This view is like acs_object_party_privilege_map, but does not +-- necessarily return distinct rows. It may be *much* faster to join +-- against this view instead of acs_object_party_privilege_map, and is +-- usually not much slower. The tradeoff for the performance boost is +-- increased complexity in your usage of the view. Example usage that I've +-- found works well is: +-- +-- select DISTINCT +-- my_table.* +-- from my_table, +-- (select object_id +-- from all_object_party_privilege_map +-- where party_id = :user_id and privilege = :privilege) oppm +-- where oppm.object_id = my_table.my_id; +-- + +create or replace view all_object_party_privilege_map as +select /*+ ORDERED */ + op.object_id, + pdm.descendant as privilege, + gpm.party_id as party_id + from acs_object_paths op, + acs_permissions p, + acs_privilege_descendant_map pdm, + acs_grantee_party_map gpm + where op.ancestor_id = p.object_id + and pdm.privilege = p.privilege + and gpm.grantee_id = p.grantee_id; Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1b-4.1.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1b-4.1.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-4.1b-4.1.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,229 @@ +-- +-- /packages/acs-kernel/sql/upgrade/upgrade-4.1b-4.1.sql +-- +-- Upgrades ACS Kernel 4.1 beta to ACS Kernel 4.1 +-- +-- @author Multiple +-- @creation-date 2001-01-19 +-- @cvs-id $Id: upgrade-4.1b-4.1.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ + + + +----------------------------- +-- PACKAGE ACS_OBJECT_TYPE +-- mbryzek@arsdigita.com +-- 1/19/2001 +-- +-- CHANGES +-- Add is_subtype_p function +----------------------------- +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; + + -- Returns 't' if object_type_2 is a subtype of object_type_1. Note + -- that this function will return 'f' if object_type_1 = + -- object_type_2 + function is_subtype_p ( + object_type_1 in acs_object_types.object_type%TYPE, + object_type_2 in acs_object_types.object_type%TYPE + ) return char; + +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; + + + function is_subtype_p ( + object_type_1 in acs_object_types.object_type%TYPE, + object_type_2 in acs_object_types.object_type%TYPE + ) return char + is + v_result integer; + begin + select count(*) into v_result + from dual + where exists (select 1 + from acs_object_types t + where t.object_type = is_subtype_p.object_type_2 + connect by prior t.object_type = t.supertype + start with t.supertype = is_subtype_p.object_type_1); + + if v_result > 0 then + return 't'; + end if; + + return 'f'; + + end is_subtype_p; + +end acs_object_type; +/ +show errors + + + +----------------------------- +-- View: rc_violations_by_removing_rel +-- mbryzek@arsdigita.com +-- 1/19/2001 +-- +-- CHANGES +-- Fix bug in join +----------------------------- + +-- 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.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, r.object_id_two + 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 r.object_id_two = s.object_id_two + and cons.rel_segment = map.segment_id + and cons.required_rel_segment = s.segment_id; + + + +------------------------------- +-- ACS_OBJECT_ATTRIBUTE_VIEW +-- mbryzek@arsdigita.com +-- 1/5/2001 +------------------------------- +-- Use union all instead of union + +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 ALL + 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; + Index: openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-beta-1-beta-2.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/oracle/upgrade/Attic/upgrade-beta-1-beta-2.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-beta-1-beta-2.sql 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,2344 @@ +-- +-- Upgrade script from Beta 1 to Beta 2. +-- +-- @author Richard Li (richardl@arsdigita.com) +-- @cvs-id $Id: upgrade-beta-1-beta-2.sql,v 1.1 2001/03/20 22:51:56 donb Exp $ +-- @creation-date 10 October 2000 + +@@ acs-logs-create + +create or replace package 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 + ); + + procedure revoke_permission ( + object_id acs_permissions.object_id%TYPE, + grantee_id acs_permissions.grantee_id%TYPE, + privilege acs_permissions.privilege%TYPE + ); + + function permission_p ( + object_id acs_objects.object_id%TYPE, + party_id parties.party_id%TYPE, + privilege acs_privileges.privilege%TYPE + ) return char; + +end acs_permission; +/ +show errors + +-- from acs-permissions + +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 + 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 in (permission_p.party_id, -1) + and privilege = permission_p.privilege); + return exists_p; + end; + +end acs_permission; +/ +show errors + +create or replace package acs_user +as + + function new ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't' + ) + return users.user_id%TYPE; + + function receives_alerts_p ( + user_id in users.user_id%TYPE + ) + return char; + + procedure approve_email ( + user_id in users.user_id%TYPE + ); + + procedure unapprove_email ( + user_id in users.user_id%TYPE + ); + + procedure delete ( + user_id in users.user_id%TYPE + ); + +end acs_user; +/ +show errors + +-- from community-core.sql + + + +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 + ) + 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); + + 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 + delete from parties + where party_id = party.delete.party_id; + + 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 + +create or replace package body acs_user +as + + function new ( + user_id in users.user_id%TYPE default null, + object_type in acs_objects.object_type%TYPE + default 'user', + 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, + first_names in persons.first_names%TYPE, + last_name in persons.last_name%TYPE, + password in users.password%TYPE, + salt in users.salt%TYPE, + password_question in users.password_question%TYPE default null, + password_answer in users.password_answer%TYPE default null, + screen_name in users.screen_name%TYPE default null, + email_verified_p in users.email_verified_p%TYPE default 't' + ) + return users.user_id%TYPE + is + v_user_id users.user_id%TYPE; + begin + v_user_id := + person.new(user_id, object_type, + creation_date, creation_user, creation_ip, + email, url, + first_names, last_name); + + insert into users + (user_id, password, salt, password_question, password_answer, screen_name, + email_verified_p) + values + (v_user_id, password, salt, password_question, password_answer, screen_name, + email_verified_p); + + insert into user_preferences + (user_id) + values + (v_user_id); + + return v_user_id; + end new; + + function receives_alerts_p ( + user_id in users.user_id%TYPE + ) + return char + is + counter char(1); + begin + select decode(count(*),0,'f','t') into counter + from users + where no_alerts_until >= sysdate + and user_id = acs_user.receives_alerts_p.user_id; + + return counter; + end receives_alerts_p; + + procedure approve_email ( + user_id in users.user_id%TYPE + ) + is + begin + update users + set email_verified_p = 't' + where user_id = approve_email.user_id; + end approve_email; + + + procedure unapprove_email ( + user_id in users.user_id%TYPE + ) + is + begin + update users + set email_verified_p = 'f' + where user_id = unapprove_email.user_id; + end unapprove_email; + + procedure delete ( + user_id in users.user_id%TYPE + ) + is + begin + delete from user_preferences + where user_id = acs_user.delete.user_id; + + delete from users + where user_id = acs_user.delete.user_id; + + person.delete(user_id); + end delete; + +end acs_user; +/ +show errors + +-- from acs-relationships-create.sql + +create or replace package 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; + + procedure delete ( + rel_id in acs_rels.rel_id%TYPE + ); + +end; +/ +show errors + +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 + delete from acs_rels + where rel_id = acs_rel.delete.rel_id; + + acs_object.delete(rel_id); + end; + +end; +/ +show errors + +-- from groups-create.sql + +create or replace package 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; + + procedure ban ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure approve ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure reject ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure unapprove ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure deleted ( + rel_id in membership_rels.rel_id%TYPE + ); + + procedure delete ( + rel_id in membership_rels.rel_id%TYPE + ); + +end membership_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 + delete from membership_rels + where rel_id = membership_rel.delete.rel_id; + + acs_rel.delete(rel_id); + end; + +end membership_rel; +/ +show errors + +create or replace package 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 + ) return groups.group_id%TYPE; + + procedure delete ( + group_id in groups.group_id%TYPE + ); + + function name ( + group_id in groups.group_id%TYPE + ) return varchar2; + + function member_p ( + party_id in parties.party_id%TYPE + ) return char; + +end acs_group; +/ +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 + ) + 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); + + insert into groups + (group_id, group_name) + values + (v_group_id, group_name); + + return v_group_id; + end new; + + procedure delete ( + group_id in groups.group_id%TYPE + ) + is + begin + + for row 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 + or r.object_id_two = group_id)) loop + membership_rel.delete(row.rel_id); + end loop; + + for row 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 + or r.object_id_two = group_id)) loop + composition_rel.delete(row.rel_id); + end loop; + + acs_object.delete(group_id); + end delete; + + function name ( + group_id in groups.group_id%TYPE + ) + return varchar2 + is + group_name varchar2(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; + +end acs_group; +/ +show errors + +-- from apm +create or replace package apm +as + function register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ); + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + -- Informs the APM that this application is available for use. + function register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE; + + -- Remove the application from the system. + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this application. + cascade_p in char default 'f' + ); + + function register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE; + + -- Remove the service from the system. + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + -- Delete all objects associated with this service. + cascade_p in char default 'f' + ); + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer; + + -- Remove any uses of this parameter. + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ); + + -- Return the value of this parameter for a specific package and parameter. + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE; + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ); + + +end apm; +/ +show errors + +create or replace package apm_package +as + +function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ); + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2; + + -- Enable a package to be utilized by a subsite. + procedure enable ( + package_id in apm_packages.package_id%TYPE + ); + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ); + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE; + +end apm_package; +/ +show errors + +create or replace package 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; + + procedure delete ( + version_id in apm_packages.package_id%TYPE + ); + + procedure enable ( + version_id in apm_package_versions.version_id%TYPE + ); + + procedure disable ( + version_id in apm_package_versions.version_id%TYPE + ); + + 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; + + -- Add a file to the indicated version. + 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; + + -- 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 + ); + + -- 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; + + procedure remove_interface( + interface_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- 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; + + procedure remove_dependency( + dependency_id in apm_package_dependencies.dependency_id%TYPE + ); + + 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 + ); + + -- Given a version_name (e.g. 3.2a), return + -- something that can be lexicographically sorted. + function sortable_version_name ( + version_name in apm_package_versions.version_name%TYPE + ) return varchar2; + + -- Given two version names, return 1 if one > two, -1 if two > one, 0 otherwise. + -- Deprecate? + function compare( + version_name_one in apm_package_versions.version_name%TYPE, + version_name_two in apm_package_versions.version_name%TYPE + ) return integer; + +end apm_package_version; +/ +show errors + +create or replace package apm_package_type +as + function create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ) return apm_package_types.package_type%TYPE; + + function update_type ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ); + +end apm_package_type; +/ +show errors + + + +-- Private APM System API for managing parameter values. +create or replace package apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ); + end apm_parameter_value; +/ +show errors + +create or replace package apm_application +as + +function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + + +create or replace package apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ); + +end; +/ +show errors + +create or replace package body apm +as + function register_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + return apm_package_type.create_type( + package_key => register_package.package_key, + pretty_name => register_package.pretty_name, + pretty_plural => register_package.pretty_plural, + package_uri => register_package.package_uri, + package_type => register_package.package_type, + singleton_p => register_package.singleton_p, + spec_file_path => register_package.spec_file_path, + spec_file_mtime => spec_file_mtime + ); + end register_package; + + function update_package ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE + default null, + pretty_plural in apm_package_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + + return apm_package_type.update_type( + package_key => update_package.package_key, + pretty_name => update_package.pretty_name, + pretty_plural => update_package.pretty_plural, + package_uri => update_package.package_uri, + package_type => update_package.package_type, + singleton_p => update_package.singleton_p, + spec_file_path => update_package.spec_file_path, + spec_file_mtime => update_package.spec_file_mtime + ); + + end update_package; + + + procedure unregister_package ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 't' + ) + is + begin + apm_package_type.drop_type( + package_key => unregister_package.package_key, + cascade_p => unregister_package.cascade_p + ); + end unregister_package; + + function register_p ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_register_p integer; + begin + select decode(count(*),0,0,1) into v_register_p from apm_package_types + where package_key = register_p.package_key; + return v_register_p; + end register_p; + + function register_application ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE + is + begin + return apm.register_package( + package_key => register_application.package_key, + pretty_name => register_application.pretty_name, + pretty_plural => register_application.pretty_plural, + package_uri => register_application.package_uri, + package_type => 'apm_application', + singleton_p => register_application.singleton_p, + spec_file_path => register_application.spec_file_path, + spec_file_mtime => register_application.spec_file_mtime + ); + end register_application; + + procedure unregister_application ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_application.package_key, + cascade_p => unregister_application.cascade_p + ); + end unregister_application; + + function register_service ( + package_key in apm_package_types.package_key%TYPE, + pretty_name in apm_package_types.pretty_name%TYPE, + pretty_plural in apm_package_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE + default 'f', + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_key%TYPE + is + begin + return apm.register_package( + package_key => register_service.package_key, + pretty_name => register_service.pretty_name, + pretty_plural => register_service.pretty_plural, + package_uri => register_service.package_uri, + package_type => 'apm_service', + singleton_p => register_service.singleton_p, + spec_file_path => register_service.spec_file_path, + spec_file_mtime => register_service.spec_file_mtime + ); + end register_service; + + procedure unregister_service ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + begin + apm.unregister_package ( + package_key => unregister_service.package_key, + cascade_p => unregister_service.cascade_p + ); + end unregister_service; + + -- Indicate to APM that a parameter is available to the system. + function register_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null, + package_key in apm_parameters.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_id%TYPE + is + v_parameter_id apm_parameters.parameter_id%TYPE; + begin + + v_parameter_id := acs_object.new( + object_id => parameter_id, + object_type => 'apm_parameter' + ); + insert into apm_parameters + (parameter_id, parameter_name, description, package_key, datatype, + default_value, section_name, min_n_values, max_n_values) + values + (v_parameter_id, register_parameter.parameter_name, register_parameter.description, + register_parameter.package_key, register_parameter.datatype, + register_parameter.default_value, register_parameter.section_name, + register_parameter.min_n_values, register_parameter.max_n_values); + + return v_parameter_id; + -- XXX: create an attribute using the metadata system. + + end register_parameter; + + function update_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + default null, + description in apm_parameters.description%TYPE + default null, + datatype in apm_parameters.datatype%TYPE + default 'string', + default_value in apm_parameters.default_value%TYPE + default null, + section_name in apm_parameters.section_name%TYPE + default null, + min_n_values in apm_parameters.min_n_values%TYPE + default 1, + max_n_values in apm_parameters.max_n_values%TYPE + default 1 + ) return apm_parameters.parameter_name%TYPE + is + begin + update apm_parameters + set parameter_name = nvl(update_parameter.parameter_name, parameter_name), + default_value = nvl(update_parameter.default_value, default_value), + datatype = nvl(update_parameter.datatype, datatype), + description = nvl(update_parameter.description, description), + section_name = nvl(update_parameter.section_name, section_name), + min_n_values = nvl(update_parameter.min_n_values, min_n_values), + max_n_values = nvl(update_parameter.max_n_values, max_n_values) + where parameter_id = update_parameter.parameter_id; + return parameter_id; + end; + + function parameter_p( + package_key in apm_package_types.package_key%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return integer + is + v_parameter_p integer; + begin + select decode(count(*),0,0,1) into v_parameter_p + from apm_parameters + where package_key = parameter_p.package_key + and parameter_name = parameter_p.parameter_name; + return v_parameter_p; + end parameter_p; + + procedure unregister_parameter ( + parameter_id in apm_parameters.parameter_id%TYPE + default null + ) + is + begin + delete from apm_parameter_values + where parameter_id = unregister_parameter.parameter_id; + delete from apm_parameters + where parameter_id = unregister_parameter.parameter_id; + acs_object.delete(parameter_id); + end unregister_parameter; + + function id_for_name ( + parameter_name in apm_parameters.parameter_name%TYPE, + package_key in apm_parameters.package_key%TYPE + ) return apm_parameters.parameter_id%TYPE + is + a_parameter_id apm_parameters.parameter_id%TYPE; + begin + select parameter_id into a_parameter_id + from apm_parameters p + where p.parameter_name = id_for_name.parameter_name and + p.package_key = id_for_name.package_key; + return a_parameter_id; + end id_for_name; + + function get_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + value apm_parameter_values.attr_value%TYPE; + begin + select attr_value into value from apm_parameter_values v + where v.package_id = get_value.package_id + and parameter_id = get_value.parameter_id; + return value; + end get_value; + + function get_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE + ) return apm_parameter_values.attr_value%TYPE + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = get_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = get_value.package_id); + return apm.get_value( + parameter_id => v_parameter_id, + package_id => get_value.package_id + ); + end get_value; + + + -- Sets a value for a parameter for a package instance. + procedure set_value ( + parameter_id in apm_parameter_values.parameter_id%TYPE, + package_id in apm_packages.package_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + -- Determine if the value exists + select value_id into v_value_id from apm_parameter_values + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + update apm_parameter_values set attr_value = set_value.attr_value + where parameter_id = set_value.parameter_id + and package_id = set_value.package_id; + exception + when NO_DATA_FOUND + then + v_value_id := apm_parameter_value.new( + package_id => package_id, + parameter_id => parameter_id, + attr_value => attr_value + ); + end set_value; + + procedure set_value ( + package_id in apm_packages.package_id%TYPE, + parameter_name in apm_parameters.parameter_name%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) + is + v_parameter_id apm_parameter_values.parameter_id%TYPE; + begin + select parameter_id into v_parameter_id + from apm_parameters + where parameter_name = set_value.parameter_name + and package_key = (select package_key from apm_packages + where package_id = set_value.package_id); + apm.set_value( + parameter_id => v_parameter_id, + package_id => set_value.package_id, + attr_value => set_value.attr_value + ); + end set_value; +end apm; +/ +show errors + +create or replace package body apm_package +as + procedure initialize_parameters ( + package_id in apm_packages.package_id%TYPE, + package_key in apm_package_types.package_key%TYPE + ) + is + v_value_id apm_parameter_values.value_id%TYPE; + cursor cur is + select parameter_id, default_value + from apm_parameters + where package_key = initialize_parameters.package_key; + begin + -- need to initialize all params for this type + for cur_val in cur + loop + v_value_id := apm_parameter_value.new( + package_id => initialize_parameters.package_id, + parameter_id => cur_val.parameter_id, + attr_value => cur_val.default_value + ); + end loop; + end initialize_parameters; + + function new ( + package_id in apm_packages.package_id%TYPE + default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_packages.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_package', + 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, + context_id in acs_objects.context_id%TYPE + default null + ) return apm_packages.package_id%TYPE + is + v_singleton_p integer; + v_package_type apm_package_types.package_type%TYPE; + v_num_instances integer; + v_package_id apm_packages.package_id%TYPE; + v_instance_name apm_packages.instance_name%TYPE; + begin + v_singleton_p := apm_package.singleton_p( + package_key => apm_package.new.package_key + ); + v_num_instances := apm_package.num_instances( + package_key => apm_package.new.package_key + ); + + if v_singleton_p = 1 and v_num_instances >= 1 then + select package_id into v_package_id + from apm_packages + where package_key = apm_package.new.package_key; + return v_package_id; + else + v_package_id := acs_object.new( + object_id => package_id, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + if instance_name is null then + v_instance_name := package_key || ' ' || v_package_id; + else + v_instance_name := instance_name; + end if; + + select package_type into v_package_type + from apm_package_types + where package_key = apm_package.new.package_key; + + insert into apm_packages + (package_id, package_key, instance_name) + values + (v_package_id, package_key, v_instance_name); + + if v_package_type = 'apm_application' then + insert into apm_applications + (application_id) + values + (v_package_id); + else + insert into apm_services + (service_id) + values + (v_package_id); + end if; + + initialize_parameters( + package_id => v_package_id, + package_key => apm_package.new.package_key + ); + return v_package_id; + + end if; +end new; + + procedure delete ( + package_id in apm_packages.package_id%TYPE + ) + is + cursor all_values is + select value_id from apm_parameter_values + where package_id = apm_package.delete.package_id; + cursor all_site_nodes is + select node_id from site_nodes + where object_id = apm_package.delete.package_id; + begin + -- Delete all parameters. + for cur_val in all_values loop + apm_parameter_value.delete(value_id => cur_val.value_id); + end loop; + delete from apm_applications where application_id = apm_package.delete.package_id; + delete from apm_services where service_id = apm_package.delete.package_id; + delete from apm_packages where package_id = apm_package.delete.package_id; + -- Delete the site nodes for the objects. + for cur_val in all_site_nodes loop + site_node.delete(cur_val.node_id); + end loop; + -- Delete the object. + acs_object.delete ( + object_id => package_id + ); + end delete; + + function singleton_p ( + package_key in apm_packages.package_key%TYPE + ) return integer + is + v_singleton_p integer; + begin + select 1 into v_singleton_p + from apm_package_types + where package_key = singleton_p.package_key + and singleton_p = 't'; + return v_singleton_p; + + exception + when NO_DATA_FOUND + then + return 0; + end singleton_p; + + function num_instances ( + package_key in apm_package_types.package_key%TYPE + ) return integer + is + v_num_instances integer; + begin + select count(*) into v_num_instances + from apm_packages + where package_key = num_instances.package_key; + return v_num_instances; + + exception + when NO_DATA_FOUND + then + return 0; + end num_instances; + + function name ( + package_id in apm_packages.package_id%TYPE + ) return varchar2 + is + v_result apm_packages.instance_name%TYPE; + begin + select instance_name into v_result + from apm_packages + where package_id = name.package_id; + + return v_result; + end name; + + procedure enable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 't' + where package_id = enable.package_id; + end enable; + + procedure disable ( + package_id in apm_packages.package_id%TYPE + ) + is + begin + update apm_packages + set enabled_p = 'f' + where package_id = disable.package_id; + end disable; + + function highest_version ( + package_key in apm_package_types.package_key%TYPE + ) return apm_package_versions.version_id%TYPE + is + v_version_id apm_package_versions.version_id%TYPE; + begin + select version_id into v_version_id + from apm_package_version_info i + where apm_package_version.sortable_version_name(version_name) = + (select max(apm_package_version.sortable_version_name(v.version_name)) + from apm_package_version_info v where v.package_key = highest_version.package_key) + and package_key = highest_version.package_key; + return v_version_id; + exception + when NO_DATA_FOUND + then + return 0; + end highest_version; +end apm_package; +/ +show errors + +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 => 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 + v_package_key apm_package_types.package_key%TYPE; + v_num_versions integer; + begin + select package_key into v_package_key + from apm_package_versions + where version_id = apm_package_version.delete.version_id; + 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); + select count(*) into v_num_versions + from apm_package_versions + where package_key = v_package_key; + if v_num_versions = 0 then + apm.unregister_package(package_key => v_package_key); + end if; + 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 + raise_application_error(-20000, 'Expected number at position ' || a_start); + end if; + if a_end - a_start > 4 then + 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.'; + else + -- uhoh... some wacky character. bomb + -- raise_application_error(-20000, 'Illegal character ''' || a_char || + -- ' in version name ' || version_name || ''''); + a_order := a_order || ' OD.'; + end if; + + -- can't have something like 3.3a1b2 - just one letter allowed! + if a_seen_letter = 't' then + 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 compare( + 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 compare; + + 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(v_path, instr(v_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 sortable_version_name(upgrade_p.initial_version_name) <= sortable_version_name(v_version_from) and + sortable_version_name(upgrade_p.final_version_name) >= sortable_version_name(v_version_to) then + return 1; + end if; + + return 0; + exception when others then + -- Invalid version number. + return 0; + end upgrade_p; + +end apm_package_version; +/ +show errors + +create or replace package body apm_package_type +as + function create_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE, + pretty_plural in acs_object_types.pretty_plural%TYPE, + package_uri in apm_package_types.package_uri%TYPE, + package_type in apm_package_types.package_type%TYPE, + singleton_p in apm_package_types.singleton_p%TYPE, + spec_file_path in apm_package_types.spec_file_path%TYPE default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE default null + ) return apm_package_types.package_type%TYPE + is + begin + insert into apm_package_types + (package_key, pretty_name, pretty_plural, package_uri, package_type, + spec_file_path, spec_file_mtime, singleton_p) + values + (create_type.package_key, create_type.pretty_name, create_type.pretty_plural, + create_type.package_uri, create_type.package_type, create_type.spec_file_path, + create_type.spec_file_mtime, create_type.singleton_p); + return create_type.package_key; + end create_type; + + function update_type( + package_key in apm_package_types.package_key%TYPE, + pretty_name in acs_object_types.pretty_name%TYPE + default null, + pretty_plural in acs_object_types.pretty_plural%TYPE + default null, + package_uri in apm_package_types.package_uri%TYPE + default null, + package_type in apm_package_types.package_type%TYPE + default null, + singleton_p in apm_package_types.singleton_p%TYPE + default null, + spec_file_path in apm_package_types.spec_file_path%TYPE + default null, + spec_file_mtime in apm_package_types.spec_file_mtime%TYPE + default null + ) return apm_package_types.package_type%TYPE + is + begin + UPDATE apm_package_types SET + pretty_name = nvl(update_type.pretty_name, pretty_name), + pretty_plural = nvl(update_type.pretty_plural, pretty_plural), + package_uri = nvl(update_type.package_uri, package_uri), + package_type = nvl(update_type.package_type, package_type), + spec_file_path = nvl(update_type.spec_file_path, spec_file_path), + spec_file_mtime = nvl(update_type.spec_file_mtime, spec_file_mtime), + singleton_p = nvl(update_type.singleton_p, singleton_p) + where package_key = update_type.package_key; + return update_type.package_key; + end update_type; + + procedure drop_type ( + package_key in apm_package_types.package_key%TYPE, + cascade_p in char default 'f' + ) + is + cursor all_package_ids is + select package_id + from apm_packages + where package_key = drop_type.package_key; + + cursor all_parameters is + select parameter_id from apm_parameters + where package_key = drop_type.package_key; + begin + if cascade_p = 't' then + for cur_val in all_package_ids + loop + apm_package.delete( + package_id => cur_val.package_id + ); + end loop; + -- Unregister all parameters. + for cur_val in all_parameters + loop + apm.unregister_parameter(parameter_id => cur_val.parameter_id); + end loop; + + end if; + delete from apm_package_types + where package_key = drop_type.package_key; + end drop_type; +end apm_package_type; +/ +show errors + +create or replace package body apm_parameter_value +as + function new ( + value_id in apm_parameter_values.value_id%TYPE default null, + package_id in apm_packages.package_id%TYPE, + parameter_id in apm_parameter_values.parameter_id%TYPE, + attr_value in apm_parameter_values.attr_value%TYPE + ) return apm_parameter_values.value_id%TYPE + is + v_value_id apm_parameter_values.value_id%TYPE; + begin + v_value_id := acs_object.new( + object_id => value_id, + object_type => 'apm_parameter_value' + ); + insert into apm_parameter_values + (value_id, package_id, parameter_id, attr_value) + values + (v_value_id, apm_parameter_value.new.package_id, + apm_parameter_value.new.parameter_id, + apm_parameter_value.new.attr_value); + return v_value_id; + end new; + + procedure delete ( + value_id in apm_parameter_values.value_id%TYPE default null + ) + is + begin + delete from apm_parameter_values + where value_id = apm_parameter_value.delete.value_id; + acs_object.delete(value_id); + end delete; + + end apm_parameter_value; +/ +show errors; + +create or replace package body apm_application +as + + function new ( + application_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE + default 'apm_application', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_application_id integer; + begin + v_application_id := apm_package.new ( + package_id => application_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_application_id; + end new; + + procedure delete ( + application_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_applications + where application_id = apm_application.delete.application_id; + apm_package.delete( + package_id => application_id); + end delete; + +end; +/ +show errors + +create or replace package body apm_service +as + + function new ( + service_id in acs_objects.object_id%TYPE default null, + instance_name in apm_packages.instance_name%TYPE + default null, + package_key in apm_package_types.package_key%TYPE, + object_type in acs_objects.object_type%TYPE default 'apm_service', + 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, + context_id in acs_objects.context_id%TYPE default null + ) return acs_objects.object_id%TYPE + is + v_service_id integer; + begin + v_service_id := apm_package.new ( + package_id => service_id, + instance_name => instance_name, + package_key => package_key, + object_type => object_type, + creation_date => creation_date, + creation_user => creation_user, + creation_ip => creation_ip, + context_id => context_id + ); + return v_service_id; + end new; + + procedure delete ( + service_id in acs_objects.object_id%TYPE + ) + is + begin + delete from apm_services + where service_id = apm_service.delete.service_id; + apm_package.delete( + package_id => service_id + ); + end delete; + +end; +/ +show errors + +-- security stuff. + +drop trigger users_update_login_token; + +@@ security-drop.sql +@@ security-create.sql Index: openacs-4/packages/acs-kernel/sql/postgresql/postgresql.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/postgresql.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/acs-kernel/sql/postgresql/postgresql.sql 19 Mar 2001 05:07:08 -0000 1.2 +++ openacs-4/packages/acs-kernel/sql/postgresql/postgresql.sql 20 Mar 2001 22:51:56 -0000 1.3 @@ -1,5 +1,5 @@ +create view dual as select now() as sysdate; - create function instr(varchar,char,integer,integer) returns integer as ' declare str alias for $1; Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test/acs-objects-test.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test/groups-test.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test/rel-constraints-test.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test/rel-segments-test-types-create.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test/rel-segments-test-types-drop.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test/rel-segments-test.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test-harness/acs-core.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/test-harness/acs-permissions.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.0-4.0.1.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.0.1-4.1b.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.0b2-4.0rc0.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.0rc0-4.0.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.1-4.1.1.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.1.1-4.2.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-4.1b-4.1.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/upgrade/upgrade-beta-1-beta-2.sql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-tcl/tcl/10-database-procs-oracle.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/Attic/10-database-procs-oracle.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-tcl/tcl/10-database-procs-oracle.tcl 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,366 @@ +ad_library { + + Oracle-specific database API and utility procs + + @creation-date 15 Apr 2000 + @author Jon Salz (jsalz@arsdigita.com) + @cvs-id $Id: 10-database-procs-oracle.tcl,v 1.1 2001/03/20 22:51:56 donb Exp $ +} + +# DRB: The following two routines are an attempt to abstract the notion of +# "NULL", since Oracle differs from SQL92-compliant RDBMS engines in +# treating the empty string as a null. Unfortunately, they're implemented +# naively and don't help. We'll keep them for now but eventually should +# root out calls to them and replace them with the empty string. + +ad_proc -public db_null {} { + Represents the SQL keyword null for use in SQL DML statements. +} { + return "" +} + +ad_proc -public db_nullify_empty_string { string } { + A convenience function that returns [db_null] if $string is the empty string. +} { + if { [empty_string_p $string] } { + return [db_null] + } else { + return $string + } +} + +proc_doc db_nextval { sequence } { Returns the next value for a sequence. This can utilize a pool of sequence values to save hits to the database. } { + return [db_string "nextval" "select $sequence.nextval from dual"] +} + +proc_doc db_exec_plsql { statement_name sql args } { + + Executes a PL/SQL statement, returning the variable of bind variable :1. + +} { + ad_arg_parser { bind_output } $args + if { [info exists bind_output] } { + return -code error "the -bind_output switch is not currently supported" + } + + db_with_handle db { + # Right now, use :1 as the output value if it occurs in the statement, + # or not otherwise. + if { [regexp {:1} $sql] } { + return [db_exec exec_plsql_bind $db $statement_name $sql 1 ""] + } else { + return [db_exec dml $db $statement_name $sql] + } + } +} + +ad_proc -private db_exec { type db statement_name sql args } { + + A helper procedure to execute a SQL statement, potentially binding + depending on the value of the $bind variable in the calling environment + (if set). + +} { + set start_time [clock clicks] + + set errno [catch { + upvar bind bind + if { [info exists bind] && [llength $bind] != 0 } { + if { [llength $bind] == 1 } { + return [eval [list ns_ora $type $db -bind $bind $sql] $args] + } else { + set bind_vars [ns_set create] + foreach { name value } $bind { + ns_set put $bind_vars $name $value + } + return [eval [list ns_ora $type $db -bind $bind_vars $sql] $args] + } + } else { + return [uplevel 2 [list ns_ora $type $db $sql] $args] + } + } error] + + ad_call_proc_if_exists ds_collect_db_call $db $type $statement_name $sql $start_time $errno $error + if { $errno == 2 } { + return $error + } + + global errorInfo errorCode + return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error +} + +proc_doc db_dml { statement_name sql args } { + Do a DML statement. +} { + ad_arg_parser { clobs blobs clob_files blob_files bind } $args + + # Only one of clobs, blobs, clob_files, and blob_files is allowed. + # Remember which one (if any) is provided. + set lob_argc 0 + set lob_argv [list] + set command "dml" + if { [info exists clobs] } { + set command "clob_dml" + set lob_argv $clobs + incr lob_argc + } + if { [info exists blobs] } { + set command "blob_dml" + set lob_argv $blobs + incr lob_argc + } + if { [info exists clob_files] } { + set command "clob_dml_file" + set lob_argv $clob_files + incr lob_argc + } + if { [info exists blob_files] } { + set command "blob_dml_file" + set lob_argv $blob_files + incr lob_argc + } + if { $lob_argc > 1 } { + error "Only one of -clobs, -blobs, -clob_files, or -blob_files may be specified as an argument to db_dml" + } + db_with_handle db { + if { $lob_argc == 1 } { + # Bind :1, :2, ..., :n as LOBs (where n = [llength $lob_argv]) + set bind_vars [list] + for { set i 1 } { $i <= [llength $lob_argv] } { incr i } { + lappend bind_vars $i + } + eval [list db_exec "${command}_bind" $db $statement_name $sql $bind_vars] $lob_argv + } else { + eval [list db_exec $command $db $statement_name $sql] $lob_argv + } + } +} + +proc_doc db_resultrows {} { Returns the number of rows affected by the last DML command. } { + global db_state + return [ns_ora resultrows $db_state(last_used)] +} + +ad_proc db_continue_transaction {} { + + If a transaction is set to be aborted, this procedure allows it to continue. + Intended for use only within a db_transaction on_error code block. +} { + global db_state + db_with_handle db { + # The error has been handled, set the flag to false. + set db_state(db_abort_p,$db) 0 + } +} + +ad_proc db_write_clob { statement_name sql args } { + ad_arg_parser { bind } $args + + db_with_handle db { + db_exec write_clob $db $statement_name $sql + } +} + +ad_proc db_write_blob { statement_name sql args } { + ad_arg_parser { bind } $args + + db_with_handle db { + db_exec write_blob $db $statement_name $sql + } +} + +ad_proc db_blob_get_file { statement_name sql args } { + ad_arg_parser { bind file args } $args + + db_with_handle db { + eval [list db_exec blob_get_file $db $statement_name $sql $file] $args + } +} + +ad_proc db_get_sql_user { } { + + Returns a valid user@database/password string to access a database through sqlplus. + +} { + + set pool [lindex [nsv_get db_available_pools .] 0] + set datasource [ns_config ns/db/pool/$pool DataSource] + if { ![empty_string_p $datasource] && ![string is space $datasource] } { + return "[ns_config ns/db/pool/$pool User]/[ns_config ns/db/pool/$pool Password]@$datasource" + } else { + return "[ns_config ns/db/pool/$pool User]/[ns_config ns/db/pool/$pool Password]" + } +} + +ad_proc db_source_sql_file { {-callback apm_ns_write_callback} file } { + + Sources a SQL file (in SQL*Plus format). + +} { + + global env + set user_pass [db_get_sql_user] + set fp [open "|[file join $env(ORACLE_HOME) bin sqlplus] $user_pass @$file" "r"] + + while { [gets $fp line] >= 0 } { + # Don't bother writing out lines which are purely whitespace. + if { ![string is space $line] } { + apm_callback_and_log $callback "[ad_quotehtml $line]\n" + } + } + close $fp +} + + +ad_proc db_source_sqlj_file { {-callback apm_ns_write_callback} file } { + + Sources a SQLJ file using loadjava. + +} { + + global env + set user_pass [db_get_sql_user] + set fp [open "|[file join $env(ORACLE_HOME) bin loadjava] -verbose -user $user_pass $file" "r"] + + + # Despite the fact that this works, the text does not get written to the stream. + # The output is generated as an error when you attempt to close the input stream as + # done below. + while { [gets $fp line] >= 0 } { + # Don't bother writing out lines which are purely whitespace. + if { ![string is space $line] } { + apm_callback_and_log $callback "[ad_quotehtml $line]\n" + } + } + if { [catch { + close $fp + } errmsg] } { + apm_callback_and_log $callback "[ad_quotehtml $errmsg]\n" + } +} + +ad_proc -public db_tables { -pattern } { + Returns a Tcl list of all the tables owned by the connected user. + + @param pattern Will be used as LIKE 'pattern%' to limit the number of tables returned. + + @author Lars Pind lars@pinds.com + + @change-log yon@arsdigita.com 20000711 changed to return lower case table names +} { + set tables [list] + + if { [info exists pattern] } { + db_foreach table_names_with_pattern { + select lower(table_name) as table_name + from user_tables + where table_name like upper(:pattern) + } { + lappend tables $table_name + } + } else { + db_foreach table_names_without_pattern { + select lower(table_name) as table_name + from user_tables + } { + lappend tables $table_name + } + } + return $tables +} + + +ad_proc -public db_table_exists { table_name } { + Returns 1 if a table with the specified name exists in the database, otherwise 0. + + @author Lars Pind (lars@pinds.com) +} { + set n_rows [db_string table_count { + select count(*) from user_tables where table_name = upper(:table_name) + }] + return $n_rows +} + +ad_proc -public db_columns { table_name } { + Returns a Tcl list of all the columns in the table with the given name. + + @author Lars Pind lars@pinds.com + + @change-log yon@arsdigita.com 20000711 changed to return lower case column names +} { + set columns [list] + db_foreach table_column_names { + select lower(column_name) as column_name + from user_tab_columns + where table_name = upper(:table_name) + } { + lappend columns $column_name + } + return $columns +} + + +ad_proc -public db_column_exists { table_name column_name } { + Returns 1 if the row exists in the table, 0 if not. + + @author Lars Pind lars@pinds.com +} { + set columns [list] + set n_rows [db_string column_exists { + select count(*) + from user_tab_columns + where table_name = upper(:table_name) + and column_name = upper(:column_name) + }] + return [expr $n_rows > 0] +} + + +ad_proc -public db_column_type { table_name column_name } { + + Returns the Oracle Data Type for the specified column. + Returns -1 if the table or column doesn't exist. + + @author Yon Feldman (yon@arsdigita.com) + + @change-log 10 July, 2000: changed to return error + if column name doesn't exist + (mdettinger@arsdigita.com) + + @change-log 11 July, 2000: changed to return lower case data types + (yon@arsdigita.com) + + @change-log 11 July, 2000: changed to return error using the db_string default clause + (yon@arsdigita.com) + +} { + + return [db_string column_type_select " + select data_type as data_type + from user_tab_columns + where upper(table_name) = upper(:table_name) + and upper(column_name) = upper(:column_name) + " -default "-1"] + +} + +ad_proc -public ad_column_type { table_name column_name } { + + Returns 'numeric' for number type columns, 'text' otherwise + Throws an error if no such column exists. + + @author Yon Feldman (yon@arsdigita.com) + +} { + + set column_type [db_column_type $table_name $column_name] + + if { $column_type == -1 } { + return "Either table $table_name doesn't exist or column $column_name doesn't exist" + } elseif { [string compare $column_type "NUMBER"] } { + return "numeric" + } else { + return "text" + } + +} Index: openacs-4/packages/acs-tcl/tcl/10-database-procs-postgresql.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/Attic/10-database-procs-postgresql.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-tcl/tcl/10-database-procs-postgresql.tcl 20 Mar 2001 22:51:56 -0000 1.1 @@ -0,0 +1,326 @@ +ad_library { + + Postgres-specific database API and utility procs. + + @creation-date 15 Apr 2000 + @author Jon Salz (jsalz@arsdigita.com) + @cvs-id $Id: 10-database-procs-postgresql.tcl,v 1.1 2001/03/20 22:51:56 donb Exp $ +} + +proc_doc db_nextval { sequence } { Returns the next value for a sequence. This can utilize a pool of sequence values to save hits to the database. } { + return [db_string nextval "select nextval('$sequence')"] +} + +proc_doc db_exec_plsql { statement_name sql args } { + + Postgres doesn't have PL/SQL, of course, but it does have PL/pgSQL and + other procedural languages. Rather than assign the result to a bind + variable which is then returned to the caller, the Postgres version of + OpenACS requires the caller to perform a select query that returns + the value of the function. + +} { + ad_arg_parser { bind_output } $args + if { [info exists bind_output] } { + return -code error "the -bind_output switch is not currently supported" + } + + db_with_handle db { + return [db_string $statement_name $sql] + } +} + +ad_proc -private db_exec { type db statement_name sql args } { + + A helper procedure to execute a SQL statement, potentially binding + depending on the value of the $bind variable in the calling environment + (if set). + +} { + set start_time [clock clicks] + + set errno [catch { + upvar bind bind + if { [info exists bind] && [llength $bind] != 0 } { + if { [llength $bind] == 1 } { + return [eval [list ns_pg_bind $type $db -bind $bind $sql] $args] + } else { + set bind_vars [ns_set create] + foreach { name value } $bind { + ns_set put $bind_vars $name $value + } + return [eval [list ns_pg_bind $type $db -bind $bind_vars $sql] $args] + } + } else { + return [uplevel 2 [list ns_pg_bind $type $db $sql] $args] + } + } error] + + ad_call_proc_if_exists ds_collect_db_call $db $type $statement_name $sql $start_time $errno $error + if { $errno == 2 } { + return $error + } + + global errorInfo errorCode + return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error +} + +proc_doc db_dml { statement_name sql args } { + Do a DML statement. We don't have CLOBs in PG as PG 7.1 allows + unbounded compressed text columns. BLOBs are handled much differently, + to. +} { + ad_arg_parser { bind } $args + + db_with_handle db { + db_exec dml $db $statement_name $sql + } +} + +proc_doc db_resultrows {} { Returns the number of rows affected by the last DML command. } { + global db_state + return [ns_pg ntuples $db_state(last_used)] +} + +#ad_proc db_continue_transaction {} { +# +# If a transaction is set to be aborted, this procedure allows it to continue. +# Intended for use only within a db_transaction on_error code block. +# +# DRB: we can't emulate this in Postgres. The best we can do is a COMMIT +# followed by BEGIN. Commented out so caller will get an error. +# +#} { +# global db_state +# db_with_handle db { +# # The error has been handled, set the flag to false. +# set db_state(db_abort_p,$db) 0 +# } +#} + +ad_proc db_write_clob { statement_name sql args } { + ad_arg_parser { bind } $args + + db_with_handle db { + db_exec write_clob $db $statement_name $sql + } +} + +ad_proc db_write_blob { statement_name sql args } { + ad_arg_parser { bind } $args + + db_with_handle db { + db_exec write_blob $db $statement_name $sql + } +} + +ad_proc db_blob_get_file { statement_name sql args } { + ad_arg_parser { bind file args } $args + + db_with_handle db { + eval [list db_exec blob_get_file $db $statement_name $sql $file] $args + } +} + +ad_proc db_get_pgbin { } { + + Returns the database name from the first database pool. It assumes the + datasource is properly formatted since we've already verified that we + can connect to the pool. + +} { + + set pool [lindex [nsv_get db_available_pools .] 0] + set driver [ns_config ns/db/pool/$pool Driver] + return [ns_config ns/db/driver/$driver pgbin] +} + +ad_proc db_get_database { } { + + Returns the database name from the first database pool. It assumes the + datasource is properly formatted since we've already verified that we + can connect to the pool. + +} { + + set pool [lindex [nsv_get db_available_pools .] 0] + set datasource [ns_config ns/db/pool/$pool DataSource] + set last_colon_pos [string last ":" $datasource] + if { $last_colon_pos == -1 } { + ns_log Error "datasource contains no \":\"? datasource = $datasource" + return "" + } + return [string range $datasource [expr $last_colon_pos + 1] end] +} + +ad_proc db_source_sql_file { {-callback apm_ns_write_callback} file } { + + Sources a SQL file (in SQL*Plus format). + +} { + + set fp [open "|[file join [db_get_pgbin] psql] [db_get_database] -f $file" "r"] + + while { [gets $fp line] >= 0 } { + # Don't bother writing out lines which are purely whitespace. + if { ![string is space $line] } { + apm_callback_and_log $callback "[ad_quotehtml $line]\n" + } + } + + # PSQL dumps errors and notice information on stderr, and has no option to turn + # this off. So we have to chug through the "error" lines looking for those that + # really signal an error. + + set errno [ catch { + close $fp + } error] + + if { $errno == 2 } { + return $error + } + + # Just filter out the "NOTICE" lines, so we get the stack dump along with real + # ERRORs. This could be done with a couple of opaque-looking regexps... + + set error_found 0 + foreach line [split $error "\n"] { + if { [string first NOTICE $line] == -1 } { + append error_lines "$line\n" + set error_found [expr { $error_found || [string first ERROR $line] != -1 } ] + } + } + + if { $error_found } { + global errorCode + return -code error -errorinfo $error_lines -errorcode $errorCode + } +} + +ad_proc -public db_tables { -pattern } { + Returns a Tcl list of all the tables owned by the connected user. + + @param pattern Will be used as LIKE 'pattern%' to limit the number of tables returned. + + @author Don Baccus dhogaza@pacifier.com + +} { + set tables [list] + + if { [info exists pattern] } { + db_foreach table_names_with_pattern { + select relname + from pg_class + where relname like lower(:pattern) and + relname !~ '^pg_' and relkind = 'r' + } { + lappend tables $relname + } + } else { + db_foreach table_names_without_pattern { + select relname + from pg_class + where relname !~ '^pg_' and relkind = 'r' + } { + lappend tables $relname + } + } + return $tables +} + +ad_proc -public db_table_exists { table_name } { + Returns 1 if a table with the specified name exists in the database, otherwise 0. + + @author Don Baccus dhogaza@pacifier.com + +} { + set n_rows [db_string table_count { + select count(*) from pg_class + where relname = lower(:table_name) and + relname !~ '^pg_' and relkind = 'r' + }] + return $n_rows +} + +ad_proc -public db_columns { table_name } { + Returns a Tcl list of all the columns in the table with the given name. + + @author Lars Pind lars@pinds.com + + @change-log yon@arsdigita.com 20000711 changed to return lower case column names +} { + set columns [list] + db_foreach table_column_names { + select lower(column_name) as column_name + from user_tab_columns + where table_name = upper(:table_name) + } { + lappend columns $column_name + } + return $columns +} + + +ad_proc -public db_column_exists { table_name column_name } { + Returns 1 if the row exists in the table, 0 if not. + + @author Lars Pind lars@pinds.com +} { + set columns [list] + set n_rows [db_string column_exists { + select count(*) + from user_tab_columns + where table_name = upper(:table_name) + and column_name = upper(:column_name) + }] + return [expr $n_rows > 0] +} + + +ad_proc -public db_column_type { table_name column_name } { + + Returns the Oracle Data Type for the specified column. + Returns -1 if the table or column doesn't exist. + + @author Yon Feldman (yon@arsdigita.com) + + @change-log 10 July, 2000: changed to return error + if column name doesn't exist + (mdettinger@arsdigita.com) + + @change-log 11 July, 2000: changed to return lower case data types + (yon@arsdigita.com) + + @change-log 11 July, 2000: changed to return error using the db_string default clause + (yon@arsdigita.com) + +} { + + return [db_string column_type_select " + select data_type as data_type + from user_tab_columns + where upper(table_name) = upper(:table_name) + and upper(column_name) = upper(:column_name) + " -default "-1"] + +} + +ad_proc -public ad_column_type { table_name column_name } { + + Returns 'numeric' for number type columns, 'text' otherwise + Throws an error if no such column exists. + + @author Yon Feldman (yon@arsdigita.com) + +} { + + set column_type [db_column_type $table_name $column_name] + + if { $column_type == -1 } { + return "Either table $table_name doesn't exist or column $column_name doesn't exist" + } elseif { [string compare $column_type "NUMBER"] } { + return "numeric" + } else { + return "text" + } +} Index: openacs-4/packages/acs-tcl/tcl/10-database-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/Attic/10-database-procs.tcl,v diff -u -r1.1 -r1.2 --- openacs-4/packages/acs-tcl/tcl/10-database-procs.tcl 13 Mar 2001 22:59:26 -0000 1.1 +++ openacs-4/packages/acs-tcl/tcl/10-database-procs.tcl 20 Mar 2001 22:51:56 -0000 1.2 @@ -4,37 +4,21 @@ @creation-date 15 Apr 2000 @author Jon Salz (jsalz@arsdigita.com) - @cvs-id $Id$ + @cvs-id 10-database-procs.tcl,v 1.4.2.1 2000/11/20 18:23:12 brech Exp } -ad_proc -public db_null {} { - Represents the SQL keyword null for use in SQL DML statements. +proc_doc db_type { } { + Returns the RDBMS type (i.e. oracle, postgresql) this OpenACS installation is + using. The nsv ad_database_type is set up during the bootstrap process. } { - # Oracle coerces the empty string into null, in DML. - # - return "" + return [nsv_get ad_database_type .] } -ad_proc -public db_nullify_empty_string { string } { - A convenience function that returns [db_null] if $string is the empty string. -} { - if { [empty_string_p $string] } { - return [db_null] - } else { - return $string - } -} - proc_doc db_quote { string } { Quotes a string value to be placed in a SQL statement. } { regsub -all {'} "$string" {''} result return $result } -proc_doc db_nextval { sequence } { Returns the next value for a sequence. } { - return [db_string "nextval" "select $sequence.nextval from dual"] -} - - proc_doc db_nth_pool_name { n } { Returns the name of the pool used for the nth-nested selection (0-relative). } { @@ -47,31 +31,6 @@ return $pool } -# -# Initialize the list of available pools -# - -global apm_first_time_loading_p -if { [info exist apm_first_time_loading_p] && $apm_first_time_loading_p } { - set server_name [ns_info server] - append config_path "ns/server/$server_name/acs/database" - set the_set [ns_configsection $config_path] - set pools [list] - if {![empty_string_p $the_set]} { - for {set i 0} {$i < [ns_set size $the_set]} {incr i} { - if { [ns_set key $the_set $i] == "AvailablePool" } { - lappend pools [ns_set value $the_set $i] - } - } - } - if { [llength $pools] == 0 } { - set pools [ns_db pools] - } - ns_log Notice "Database API: The following pools are available: $pools" - nsv_set db_available_pools . $pools -} - - proc_doc db_with_handle { db code_block } { Places a usable database handle in $db and executes $code_block. @@ -138,27 +97,6 @@ } } -proc_doc db_exec_plsql { statement_name sql args } { - - Executes a PL/SQL statement, returning the variable of bind variable :1. - -} { - ad_arg_parser { bind_output } $args - if { [info exists bind_output] } { - return -code error "the -bind_output switch is not currently supported" - } - - db_with_handle db { - # Right now, use :1 as the output value if it occurs in the statement, - # or not otherwise. - if { [regexp {:1} $sql] } { - return [db_exec exec_plsql_bind $db $statement_name $sql 1 ""] - } else { - return [db_exec dml $db $statement_name $sql] - } - } -} - proc_doc db_release_unused_handles {} { Releases any database handles that are presently unused. @@ -205,41 +143,6 @@ return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error } -ad_proc -private db_exec { type db statement_name sql args } { - - A helper procedure to execute a SQL statement, potentially binding - depending on the value of the $bind variable in the calling environment - (if set). - -} { - set start_time [clock clicks] - - set errno [catch { - upvar bind bind - if { [info exists bind] && [llength $bind] != 0 } { - if { [llength $bind] == 1 } { - return [eval [list ns_ora $type $db -bind $bind $sql] $args] - } else { - set bind_vars [ns_set create] - foreach { name value } $bind { - ns_set put $bind_vars $name $value - } - return [eval [list ns_ora $type $db -bind $bind_vars $sql] $args] - } - } else { - return [uplevel 2 [list ns_ora $type $db $sql] $args] - } - } error] - - ad_call_proc_if_exists ds_collect_db_call $db $type $statement_name $sql $start_time $errno $error - if { $errno == 2 } { - return $error - } - - global errorInfo errorCode - return -code $errno -errorinfo $errorInfo -errorcode $errorCode $error -} - proc_doc db_string { statement_name sql args } { Returns the first column of the result of the SQL query $sql. @@ -511,58 +414,7 @@ } } -proc_doc db_dml { statement_name sql args } { - Do a DML statement. -} { - ad_arg_parser { clobs blobs clob_files blob_files bind } $args - # Only one of clobs, blobs, clob_files, and blob_files is allowed. - # Remember which one (if any) is provided. - set lob_argc 0 - set lob_argv [list] - set command "dml" - if { [info exists clobs] } { - set command "clob_dml" - set lob_argv $clobs - incr lob_argc - } - if { [info exists blobs] } { - set command "blob_dml" - set lob_argv $blobs - incr lob_argc - } - if { [info exists clob_files] } { - set command "clob_dml_file" - set lob_argv $clob_files - incr lob_argc - } - if { [info exists blob_files] } { - set command "blob_dml_file" - set lob_argv $blob_files - incr lob_argc - } - if { $lob_argc > 1 } { - error "Only one of -clobs, -blobs, -clob_files, or -blob_files may be specified as an argument to db_dml" - } - db_with_handle db { - if { $lob_argc == 1 } { - # Bind :1, :2, ..., :n as LOBs (where n = [llength $lob_argv]) - set bind_vars [list] - for { set i 1 } { $i <= [llength $lob_argv] } { incr i } { - lappend bind_vars $i - } - eval [list db_exec "${command}_bind" $db $statement_name $sql $bind_vars] $lob_argv - } else { - eval [list db_exec $command $db $statement_name $sql] $lob_argv - } - } -} - -proc_doc db_resultrows {} { Returns the number of rows affected by the last DML command. } { - global db_state - return [ns_ora resultrows $db_state(last_used)] -} - ad_proc db_0or1row { statement_name sql args } { Performs the SQL query $sql, setting variables to column values. Returns 1 if a row is returned, or 0 if no row is returned. @@ -854,104 +706,24 @@ } } -ad_proc db_continue_transaction {} { - - If a transaction is set to be aborted, this procedure allows it to continue. - Intended for use only within a db_transaction on_error code block. -} { - global db_state - db_with_handle db { - # The error has been handled, set the flag to false. - set db_state(db_abort_p,$db) 0 - } -} +ad_proc -public db_name { } { -ad_proc db_write_clob { statement_name sql args } { - ad_arg_parser { bind } $args + Returns the name of the database as reported by the driver. +} { db_with_handle db { - db_exec write_clob $db $statement_name $sql + set dbtype [ns_db dbtype $db] } + return $dbtype } -ad_proc db_write_blob { statement_name sql args } { - ad_arg_parser { bind } $args +# NSV db_pooled_sequences($sequence) is the number of sequence values for the +# sequence named $sequence that should be pooled. +# NSV db_pooled_nextvals($sequence) is a list of available sequence values for +# the sequence named $sequence. It is a ring buffer (values are added to the +# end and popped from the beginning). +# NSV db_pooled_nextvals(.mutex) is a mutex guarding the db_pooled_nextvals. - db_with_handle db { - db_exec write_blob $db $statement_name $sql - } -} - -ad_proc db_blob_get_file { statement_name sql args } { - ad_arg_parser { bind file args } $args - - db_with_handle db { - eval [list db_exec blob_get_file $db $statement_name $sql $file] $args - } -} - -ad_proc db_get_sql_user { } { - - Returns a valid user@database/password string to access a database through sqlplus. - -} { - - set pool [lindex [nsv_get db_available_pools .] 0] - set datasource [ns_config ns/db/pool/$pool DataSource] - if { ![empty_string_p $datasource] && ![string is space $datasource] } { - return "[ns_config ns/db/pool/$pool User]/[ns_config ns/db/pool/$pool Password]@$datasource" - } else { - return "[ns_config ns/db/pool/$pool User]/[ns_config ns/db/pool/$pool Password]" - } -} - -ad_proc db_source_sql_file { {-callback apm_ns_write_callback} file } { - - Sources a SQL file (in SQL*Plus format). - -} { - - global env - set user_pass [db_get_sql_user] - set fp [open "|[file join $env(ORACLE_HOME) bin sqlplus] $user_pass @$file" "r"] - - while { [gets $fp line] >= 0 } { - # Don't bother writing out lines which are purely whitespace. - if { ![string is space $line] } { - apm_callback_and_log $callback "[ad_quotehtml $line]\n" - } - } - close $fp -} - - -ad_proc db_source_sqlj_file { {-callback apm_ns_write_callback} file } { - - Sources a SQLJ file using loadjava. - -} { - - global env - set user_pass [db_get_sql_user] - set fp [open "|[file join $env(ORACLE_HOME) bin loadjava] -verbose -user $user_pass $file" "r"] - - - # Despite the fact that this works, the text does not get written to the stream. - # The output is generated as an error when you attempt to close the input stream as - # done below. - while { [gets $fp line] >= 0 } { - # Don't bother writing out lines which are purely whitespace. - if { ![string is space $line] } { - apm_callback_and_log $callback "[ad_quotehtml $line]\n" - } - } - if { [catch { - close $fp - } errmsg] } { - apm_callback_and_log $callback "[ad_quotehtml $errmsg]\n" - } -} - # global db_state(handles) is a list of handles that have been allocated. # # global db_state(n_handles_used) is the number of handles in this list that are Index: openacs-4/packages/acs-tcl/tcl/acs-kernel-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/acs-kernel-procs.tcl,v diff -u -r1.1 -r1.2 --- openacs-4/packages/acs-tcl/tcl/acs-kernel-procs.tcl 13 Mar 2001 22:59:26 -0000 1.1 +++ openacs-4/packages/acs-tcl/tcl/acs-kernel-procs.tcl 20 Mar 2001 22:51:56 -0000 1.2 @@ -28,13 +28,19 @@ } { # Obtain the id of the ACS Administration node. + + # DRB: this used to say "and rownum = 1" to limit the return to a single row, + # but this is Oracle-specific. It surprises me that the author thinks + # that more than one site_node might have object_id equal to the package_id being + # selected, but there's no harm in forcing the query to only return a single row + # no matter what. Using "min()" is portable, at least... + return [db_string acs_admin_node_p { - select node_id + select min(node_id) from site_nodes where object_id = (select package_id from apm_packages where package_key = 'acs-admin') - and rownum = 1 } -default 0] } Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-tcl/tcl/bootstrap.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-tcl/tcl/database-util-procs.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-tcl/tcl/installer-init.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.2 refers to a dead (removed) revision in file `openacs-4/packages/acs-tcl/tcl/installer.tcl'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/tcl/0-acs-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/tcl/0-acs-init.tcl,v diff -u -r1.1 -r1.2 --- openacs-4/tcl/0-acs-init.tcl 13 Mar 2001 22:59:26 -0000 1.1 +++ openacs-4/tcl/0-acs-init.tcl 20 Mar 2001 22:51:56 -0000 1.2 @@ -1,7 +1,7 @@ # /tcl/0-acs-init.tcl # # The very first file invoked when ACS is started up. Sources -# /packages/acs-tcl/tcl/bootstrap.tcl. +# /packages/acs-tcl/bootstrap/bootstrap.tcl. # # jsalz@mit.edu, 12 May 2000 # @@ -13,7 +13,7 @@ nsv_set acs_properties root_directory $root_directory ns_log "Notice" "Loading the ACS, rooted at $root_directory" -set bootstrap_file "$root_directory/packages/acs-tcl/tcl/bootstrap.tcl" +set bootstrap_file "$root_directory/packages/acs-tcl/bootstrap/bootstrap.tcl" ns_log "Notice" "Sourcing $bootstrap_file" if { [file isfile $bootstrap_file] } {