Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,310 @@ +-- +-- 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 varchar(100) + constraint acs_magic_objects_pk primary key, + object_id integer 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 +-- function add_user +create function acs__add_user (integer,varchar,timestamp,integer,varchar,varchar,varchar,varchar,varchar,char,char,varchar,varchar,varchar,boolean,varchar) +returns integer as ' +declare + user_id alias for $1; + object_type alias for $2; + creation_date alias for $3; + creation_user alias for $4; + creation_ip alias for $5; + email alias for $6; + url alias for $7; + first_names alias for $8; + last_name alias for $9; + password alias for $10; + salt alias for $11; + password_question alias for $12; + password_answer alias for $13; + screen_name alias for $14; + email_verified_p alias for $15; + member_state alias for $16; + 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,null); + + v_rel_id := membership_rel__new ( + null, + ''membership_rel'', + acs__magic_object_id(''registered_users''), + v_user_id, + member_state + null, + null); + + PERFORM acs_permission__grant_permission ( + v_user_id, + v_user_id, + ''read'' + ); + + PERFORM acs_permission__grant_permission ( + v_user_id, + v_user_id, + ''write'' + ); + + return v_user_id; + +end;' language 'plpgsql'; + + +-- procedure remove_user +create function acs__remove_user (integer) +returns integer as ' +declare + remove_user__user_id alias for $1; +begin + delete from users + where user_id = remove_user__user_id; + + return 0; +end;' language 'plpgsql'; + + +-- function magic_object_id +create function acs__magic_object_id (varchar) +returns integer as ' +declare + magic_object_id__name alias for $1; + magic_object_id__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 magic_object_id__object_id; + +end;' language 'plpgsql'; + + + +-- show errors + +-- ****************************************************************** +-- * Community Core API +-- ****************************************************************** + +create 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 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. + +create function inline_0 () +returns integer as ' +declare + root_id integer; +begin + + root_id := acs_object__new ( + 0, + ''acs_object'', + now(), + null, + null, + null + ); + + insert into acs_magic_objects + (name, object_id) + values + (''security_context_root'', 0); + + + return root_id; + +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +create function inline_1 () +returns integer as ' +begin + -------------------------------------------------------------- + -- Some privilege that will be fundamental to all objects. -- + -------------------------------------------------------------- + + PERFORM acs_privilege__create_privilege(''read'', null, null); + PERFORM acs_privilege__create_privilege(''write'', null, null); + PERFORM acs_privilege__create_privilege(''create'', null, null); + PERFORM acs_privilege__create_privilege(''delete'', null, null); + PERFORM acs_privilege__create_privilege(''admin'', null, null); + + --------------------------------------------------------- + -- Administrators can read, write, create, and delete. -- + --------------------------------------------------------- + + PERFORM acs_privilege__add_child(''admin'', ''read''); + PERFORM acs_privilege__add_child(''admin'', ''write''); + PERFORM acs_privilege__add_child(''admin'', ''create''); + PERFORM acs_privilege__add_child(''admin'', ''delete''); + + return 0; +end;' language 'plpgsql'; + +select inline_1 (); + +drop function inline_1 (); + + +-- show errors + +create function inline_2 () +returns integer as ' +declare + v_object_id integer; +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); + + return 0; +end;' language 'plpgsql'; + +select inline_2 (); + +drop function inline_2 (); + + +create function inline_3 () +returns integer as ' +declare + group_id integer; +begin + + group_id := acs_group__new ( + -2, + ''group'', + now(), + null, + null, + null, + null, + ''Registered Users'', + null, + null + ); + + insert into acs_magic_objects + (name, object_id) + values + (''registered_users'', -2); + + return 0; +end;' language 'plpgsql'; + +select inline_3 (); + +drop function inline_3 (); + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,14 @@ +-- +-- packages/acs-kernel/sql/acs-drop.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id acs-drop.sql,v 1.5 2000/10/24 22:26:18 bquinn Exp +-- + +drop view cc_users; +drop view registered_users; +\t +select drop_package('acs'); +\t +drop table acs_magic_objects; Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-install.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-install.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-install.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,169 @@ +-- +-- /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 acs-install.sql,v 1.9.2.1 2001/01/12 18:32:21 dennis Exp +-- + +create function inline_0 () +returns integer as ' +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 varchar(100); + jobnum integer; +begin + kernel_id := apm_service__new ( + null, + ''ACS Kernel'', + ''acs-kernel'', + ''apm_service'', + now(), + null, + null, + acs.magic_object_id(''default_context'') + ); + + + PERFORM apm_package__enable (kernel_id); + + main_site_id := apm_service__new( + null, + ''Main Site'', + ''acs-subsite'', + ''apm_service'', + now(), + null, + null, + acs__magic_object_id(''default_context'') + ); + + + PERFORM apm_package__enable (main_site_id); + + node_id := site_node__new ( + null, + null, + '''', + main_site_id, + ''t'', + ''t'', + null, + null + ); + + PERFORM acs_permission__grant_permission ( + main_site_id, + acs__magic_object_id(''the_public''), + ''read'' + ); + + admin_id := apm_service__new ( + null, + ''ACS Administration'', + ''acs-admin'', + ''apm_service'', + now(), + null, + null, + null + ); + + PERFORM apm_package__enable (admin_id); + + node_id := site_node__new ( + null, + site_node__node_id(''/'', null), + ''acs-admin'', + admin_id + ''t'', + ''t'', + null, + null + ); + + docs_id := apm_service__new ( + null, + ''ACS Core Documents'', + ''acs-core-docs'', + ''apm_service'', + now(), + null, + null, + main_site_id + ); + + node_id := site_node__new ( + null, + site_node.node_id(''/''), + ''doc'', + docs_id, + ''t'', + ''t'', + null, + null + ); + + api_doc_id := apm_service__new ( + null, + ''ACS API Browser'', + ''acs-api-browser'', + ''apm_service'', + now(), + null, + null, + main_site_id + ); + + PERFORM 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; + + PERFORM acs_permission__grant_permission ( + api_doc_id, + acs__magic_object_id (''registered_users''), + ''read'' + ); + + api_doc_id := site_node__new ( + null, + site_node.node_id(''/''), + ''api-doc'', + api_doc_id, + ''t'', + ''t'', + null, + null + ); + + -- 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' + ); + + + return null; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-kernel-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-kernel-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-kernel-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,34 @@ +-- +-- /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 acs-kernel-create.sql,v 1.7.2.1 2001/01/12 22:47:21 oumi Exp +-- + +-- set feedback off + +\i postgresql.sql +\i acs-logs-create.sql +\i acs-metadata-create.sql +\i acs-objects-create.sql +\i acs-relationships-create.sql +\i utilities-create.sql +\i community-core-create.sql +\i groups-create.sql +\i rel-segments-create.sql +\i rel-constraints-create.sql +\i groups-body-create.sql +\i rel-segments-body-create.sql +\i acs-permissions-create.sql +\i security-create.sql +\i journal-create.sql +\i site-nodes-create.sql +\i apm-create.sql + +\i acs-create.sql +-- + +-- set feedback on Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-kernel-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-kernel-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-kernel-drop.sql 14 Mar 2001 04:39:10 -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 acs-kernel-drop.sql,v 1.7.2.1 2001/01/12 22:52:29 oumi Exp +-- + +\i acs-drop.sql +\i journal-drop.sql +\i utilities-drop.sql +\i security-drop.sql +\i acs-permissions-drop.sql +\i rel-constraints-drop.sql +\i rel-segments-drop.sql +\i groups-drop.sql +\i site-nodes-drop.sql +\i community-core-drop.sql +\i acs-relationships-drop.sql +\i acs-objects-drop.sql +\i acs-metadata-drop.sql +\i apm-drop.sql +\i acs-logs-drop.sql Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-logs-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-logs-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-logs-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,119 @@ +-- +-- packages/acs-kernel/sql/acs-logs-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-10-02 +-- @cvs-id acs-logs-create.sql,v 1.6 2000/11/02 17:55:49 yon Exp +-- + +create sequence t_acs_log_id_seq; +create view acs_log_id_seq as +select nextval('t_acs_log_id_seq') as nextval; + +create table acs_logs ( + log_id integer + constraint acs_logs_pk + primary key, + log_date timestamp default now() not null, + log_level varchar(20) + constraint acs_logs_log_level_ck + check (log_level in ('notice', 'warn', 'error', + 'debug')), + log_key varchar(100) not null, + message text 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 +-- procedure notice +create function acs_log__notice (varchar,varchar) +returns integer as ' +declare + notice__log_key alias for $1; + notice__message alias for $2; +begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, ''notice'', notice__log_key, notice__message); + + return 0; +end;' language 'plpgsql'; + + +-- procedure warn +create function acs_log__warn (varchar,varchar) +returns integer as ' +declare + warn__log_key alias for $1; + warn__message alias for $2; +begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, ''warn'', warn__log_key, warn__message); + + return 0; +end;' language 'plpgsql'; + + +-- procedure error +create function acs_log__error (varchar,varchar) +returns integer as ' +declare + error__log_key alias for $1; + error__message alias for $2; +begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, ''error'', error__log_key, error__message); + + return 0; +end;' language 'plpgsql'; + + +-- procedure debug +create function acs_log__debug (varchar,varchar) +returns integer as ' +declare + debug__log_key alias for $1; + debug__message alias for $2; +begin + insert into acs_logs + (log_id, log_level, log_key, message) + values + (acs_log_id_seq.nextval, ''debug'', debug__log_key, debug__message); + + return 0; +end;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-logs-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-logs-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-logs-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,5 @@ + +select drop_package('acs_log'); +drop table acs_logs; +drop view acs_log_id_seq; +drop sequence t_acs_log_id_seq; Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-metadata-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-metadata-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-metadata-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,824 @@ +-- +-- 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 acs-metadata-create.sql,v 1.9.2.8 2001/01/22 20:23:46 mbryzek Exp +-- + +-- ****************************************************************** +-- * KNOWLEDGE LEVEL +-- ****************************************************************** + +------------------ +-- OBJECT TYPES -- +------------------ + +create table acs_object_types ( + object_type varchar(100) not null + constraint acs_object_types_pk primary key, + supertype varchar(100) constraint acs_object_types_supertype_fk + references acs_object_types (object_type), + abstract_p boolean default 'f' not null, + pretty_name varchar(100) not null + constraint acs_obj_types_pretty_name_un + unique, + pretty_plural varchar(100) not null + constraint acs_obj_types_pretty_plural_un + unique, + table_name varchar(30) not null + constraint acs_object_types_tbl_name_un unique, + id_column varchar(30) not null, + package_name varchar(30) not null + constraint acs_object_types_pkg_name_un unique, + name_method varchar(30) default '' not null, + type_extension_table varchar(30) default '' not null, + dynamic_p boolean default 'f', + tree_sortkey varchar(4000) +); + +create index acs_obj_types_supertype_idx on acs_object_types (supertype); +create index acs_obj_types_tree_skey_idx on acs_object_types (tree_sortkey); + +-- support for tree queries on acs_object_types + +create function acs_object_type_insert_tr () returns opaque as ' +declare + v_parent_sk varchar; + max_key varchar; +begin + select max(tree_sortkey) into max_key + from acs_object_types + where supertype = new.supertype; + + select coalesce(max(tree_sortkey),'''') into v_parent_sk + from acs_object_types + where object_type = new.supertype; + + new.tree_sortkey := v_parent_sk || ''/'' || tree_next_key(max_key); + + return new; + +end;' language 'plpgsql'; + +create trigger acs_object_type_insert_tr before insert +on acs_object_types for each row +execute procedure acs_object_type_insert_tr (); + +create function acs_object_type_update_tr () returns opaque as ' +declare + v_parent_sk varchar; + max_key varchar; + v_rec record; + clr_keys_p boolean default ''t''; +begin + if new.object_type = old.object_type and + new.supertype = old.supertype then + + return new; + + end if; + + for v_rec in select object_type + from acs_object_types + where tree_sortkey like new.tree_sortkey || ''%'' + order by tree_sortkey + LOOP + if clr_keys_p then + update acs_object_types set tree_sortkey = null + where tree_sortkey like new.tree_sortkey || ''%''; + clr_keys_p := ''f''; + end if; + + select max(tree_sortkey) into max_key + from acs_object_types + where supertype = (select supertype + from acs_object_types + where object_type = v_rec.object_type); + + select coalesce(max(tree_sortkey),'''') into v_parent_sk + from acs_object_types + where object_type = (select supertype + from acs_object_types + where object_type = v_rec.object_type); + + update acs_object_types + set tree_sortkey = v_parent_sk || ''/'' || tree_next_key(max_key) + where object_type = v_rec.object_type; + + end LOOP; + + return new; + +end;' language 'plpgsql'; + +create trigger acs_object_type_update_tr after update +on acs_object_types +for each row +execute procedure acs_object_type_update_tr (); + +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 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 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 ot2.object_type + from acs_object_types ot1, + acs_object_types ot2 + where o1.object_type = ot.supertype + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%')); + + +create table acs_object_type_tables ( + object_type varchar(100) not null + constraint acs_obj_type_tbls_obj_type_fk + references acs_object_types (object_type), + table_name varchar(30) not null, + id_column varchar(30) default '' not null, + constraint acs_object_type_tables_pk + primary key (object_type, table_name) +); + +create 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 varchar(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. +-- +create function inline_0 () +returns integer as ' +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); + + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + + +--create table acs_input_types ( +--); + +create sequence t_acs_attribute_id_seq; +create view acs_attribute_id_seq as +select nextval('t_acs_attribute_id_seq') as nextval; + +create table acs_attributes ( + attribute_id integer not null + constraint acs_attributes_pk + primary key, + object_type varchar(100) not null + constraint acs_attributes_object_type_fk + references acs_object_types (object_type), + table_name varchar(30), + constraint acs_attrs_obj_type_tbl_name_fk + foreign key (object_type, table_name) + references acs_object_type_tables, + attribute_name varchar(100) not null, + pretty_name varchar(100) not null, + pretty_plural varchar(100) default '' not null, + sort_order integer not null, + datatype varchar(50) not null + constraint acs_attributes_datatype_fk + references acs_datatypes (datatype), + default_value text default '' not null, + 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 varchar(13) default 'type_specific' + constraint acs_attributes_storage_ck + check (storage in ('type_specific', + 'generic')), + static_p boolean default 'f', + column_name varchar(30) default '' not null, + 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 index acs_attrs_obj_type_idx on acs_attributes (object_type); +create index acs_attrs_tbl_name_idx on acs_attributes (table_name); +create 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 integer not null + constraint asc_enum_values_attr_id_fk + references acs_attributes (attribute_id), + enum_value varchar(1000) default '' not null, + pretty_name varchar(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 varchar(100) not null constraint acs_attr_descs_obj_type_fk + references acs_object_types (object_type), + attribute_name varchar(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 varchar(100) default '' not null, + constraint acs_attribute_descriptions_pk + primary key (object_type, attribute_name, description_key), + description text not null +); + +create 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 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 +-- procedure create_type +create function acs_object_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar,boolean,varchar,varchar) +returns integer as ' +declare + create_type__object_type alias for $1; + create_type__pretty_name alias for $2; + create_type__pretty_plural alias for $3; + create_type__supertype alias for $4; + create_type__table_name alias for $5; + create_type__id_column alias for $6; + create_type__package_name alias for $7; + create_type__abstract_p alias for $8; + create_type__type_extension_table alias for $9; + create_type__name_method alias for $10; + v_package_name acs_object_types.package_name%TYPE; + v_name_method varchar; + v_idx integer; +begin + v_idx := position(''.'' in create_type__name_method); + if v_idx <> 0 then + v_name_method := substr(create_type__name_method,1,v_idx - 1) || ''__'' || substr(create_type__name_method, v_idx + 1); + else + v_name_method := create_type__name_method; + end if; + + if create_type__package_name is null then + v_package_name := create_type__object_type; + else + v_package_name := create_type__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 + (create_type__object_type, create_type__pretty_name, + create_type__pretty_plural, create_type__supertype, + create_type__table_name, create_type__id_column, + create_type__abstract_p, coalesce(create_type__type_extension_table,''''), + v_package_name, coalesce(v_name_method,'''')); + + return 0; +end;' language 'plpgsql'; + + +-- procedure drop_type +create function acs_object_type__drop_type (varchar,boolean) +returns integer as ' +declare + drop_type__object_type alias for $1; + drop_type__cascade_p alias for $2; + row record; +begin + + -- drop all the attributes associated with this type + for row in select attribute_name + from acs_attributes + where object_type = drop_type__object_type + loop + PERFORM 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; + + return 0; +end;' language 'plpgsql'; + + +-- function pretty_name +create function acs_object_type__pretty_name (varchar) +returns varchar as ' +declare + pretty_name__object_type alias for $1; + 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;' language 'plpgsql'; + + +-- function is_subtype_p +create function acs_object_type__is_subtype_p (varchar,varchar) +returns boolean as ' +declare + is_subtype_p__object_type_1 alias for $1; + is_subtype_p__object_type_2 alias for $2; + v_result integer; +begin + -- select count(*) into v_result + -- 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); + select count(*) + where exists (select 1 + from acs_object_types t + where t.object_type = is_subtype_p__object_type_2 + and tree_sortkey like (select tree_sortkey || '%' + from acs_object_types + where object_type = is_subtype_p__object_type_1 )); + + if v_result > 0 then + return ''t''; + end if; + + return ''f''; + +end;' language 'plpgsql'; + + + +-- show errors + + + +-- create or replace package body acs_attribute +-- function create_attribute +create function acs_attribute__create_attribute (varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer,integer,varchar,boolean) +returns integer as ' +declare + create_attribute__object_type alias for $1; + create_attribute__attribute_name alias for $2; + create_attribute__datatype alias for $3; + create_attribute__pretty_name alias for $4; + create_attribute__pretty_plural alias for $5; + create_attribute__table_name alias for $6; + create_attribute__column_name alias for $7; + create_attribute__default_value alias for $8; + create_attribute__min_n_values alias for $9; + create_attribute__max_n_values alias for $10; + create_attribute__sort_order alias for $11; + create_attribute__storage alias for $12; + create_attribute__static_p alias for $13; + + v_sort_order acs_attributes.sort_order%TYPE; + v_attribute_id acs_attributes.attribute_id%TYPE; +begin + if create_attribute__sort_order is null then + select coalesce(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 := create_attribute__sort_order; + end if; + + select acs_attribute_id_seq.nextval into v_attribute_id; + + 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, create_attribute__object_type, + create_attribute__table_name, coalesce(create_attribute__column_name,''''), + create_attribute__attribute_name, create_attribute__pretty_name, + coalesce(create_attribute__pretty_plural,''''), v_sort_order, + create_attribute__datatype, coalesce(create_attribute__default_value,''''), + create_attribute__min_n_values, create_attribute__max_n_values, + create_attribute__storage, create_attribute__static_p); + + return v_attribute_id; + +end;' language 'plpgsql'; + + +-- procedure drop_attribute +create function acs_attribute__drop_attribute (varchar,varchar) +returns integer as ' +declare + drop_attribute__object_type alias for $1; + drop_attribute__attribute_name alias for $2; +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; + + return 0; +end;' language 'plpgsql'; + + +-- procedure add_description +create function acs_attribute__add_description (varchar,varchar,varchar,text) +returns integer as ' +declare + add_description__object_type alias for $1; + add_description__attribute_name alias for $2; + add_description__description_key alias for $3; + add_description__description alias for $4; +begin + insert into acs_attribute_descriptions + (object_type, attribute_name, description_key, description) + values + (add_description__object_type, add_description__attribute_name, + coalesce(add_description__description_key,''''), add_description__description); + + return 0; +end;' language 'plpgsql'; + + +-- procedure drop_description +create function acs_attribute__drop_description (varchar,varchar,varchar) +returns integer as ' +declare + drop_description__object_type alias for $1; + drop_description__attribute_name alias for $2; + drop_description__description_key alias for $3; +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; + + return 0; +end;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-metadata-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-metadata-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-metadata-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,23 @@ +-- +-- 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 acs-metadata-drop.sql,v 1.5.2.1 2001/01/12 23:05:13 oumi Exp +-- +\t +select drop_package('acs_attribute'); +select drop_package('acs_object_type'); +\t +drop view acs_object_type_attributes; +drop table acs_attribute_descriptions; +drop table acs_enum_values; +drop table acs_attributes; +drop view acs_attribute_id_seq; +drop sequence t_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/postgresql/acs-objects-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-objects-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-objects-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,1240 @@ +-- +-- 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 acs-objects-create.sql,v 1.15.2.2 2001/01/12 22:54:24 oumi Exp +-- + +----------------------------- +-- PREDEFINED OBJECT TYPES -- +----------------------------- + +create function inline_0 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + -- + -- The ultimate supertype: object + -- + PERFORM acs_object_type__create_type ( + ''acs_object'', + ''Object'', + ''Objects'', + null, + ''acs_objects'', + ''object_id'', + ''acs_object'', + ''f'', + null, + ''acs_object.default_name'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''object_type'', + ''string'', + ''Object Type'', + ''Object Types'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''creation_date'', + ''date'', + ''Created Date'', + null, + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''creation_ip'', + ''string'', + ''Creation IP Address'', + null, + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''last_modified'', + ''date'', + ''Last Modified On'', + null, + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''modifying_ip'', + ''string'', + ''Modifying IP Address'', + null, + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''creation_user'', + ''integer'', + ''Creation user'', + ''Creation users'', + null, + null, + null, + 0, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''acs_object'', + ''context_id'', + ''integer'', + ''Context ID'', + ''Context IDs'', + null, + null, + null, + 0, + 1, + null, + ''type_specific'', + ''f'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +-- ****************************************************************** +-- * OPERATIONAL LEVEL +-- ****************************************************************** + +------------- +-- OBJECTS -- +------------- + +create sequence t_acs_object_id_seq; +create view acs_object_id_seq as +select nextval('t_acs_object_id_seq') as nextval; + +create table acs_objects ( + object_id integer not null + constraint acs_objects_pk primary key, + object_type varchar(100) not null + constraint acs_objects_object_type_fk + references acs_object_types (object_type), + context_id integer constraint acs_objects_context_id_fk + references acs_objects(object_id), + security_inherit_p boolean default 't' not null, + creation_user integer, + creation_date timestamp default now() not null, + creation_ip varchar(50) default '' not null, + last_modified timestamp default now() not null, + modifying_user integer, + modifying_ip varchar(50) default '' not null, + constraint acs_objects_context_object_un + unique (context_id, object_id) +); + +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 index acs_objects_object_type_idx on acs_objects (object_type); + +create function acs_objects_mod_ip_insert_tr () returns opaque as ' +begin + new.modifying_ip := new.creation_ip; + + return new; + +end;' language 'plpgsql'; + +create trigger acs_objects_mod_ip_insert_tr before insert on acs_objects +for each row execute procedure acs_objects_mod_ip_insert_tr (); + +-- show errors + +create function acs_objects_last_mod_update_tr () returns opaque as ' +begin + new.last_modified := now(); + + return new; + +end;' language 'plpgsql'; + +create trigger acs_objects_last_mod_update_tr before update on acs_objects +for each row execute procedure 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 integer not null + constraint acs_obj_context_idx_obj_id_fk + references acs_objects(object_id), + ancestor_id integer 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) +); + +create index acs_obj_ctx_idx_ancestor_idx on acs_object_context_index (ancestor_id); + +create view acs_object_paths +as select object_id, ancestor_id, n_generations + from acs_object_context_index; + +create view acs_object_contexts +as select object_id, ancestor_id, n_generations + from acs_object_context_index + where object_id != ancestor_id; + +create function acs_objects_context_id_in_tr () returns opaque as ' +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; + else if 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 if; + + return new; + +end;' language 'plpgsql'; + +create trigger acs_objects_context_id_in_tr after insert on acs_objects +for each row execute procedure acs_objects_context_id_in_tr (); + +-- show errors + +create function acs_objects_context_id_up_tr () returns opaque as ' +declare + pair record; +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; + else if 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 if; + + return new; + +end;' language 'plpgsql'; + +create trigger acs_objects_context_id_up_tr after update on acs_objects +for each row execute procedure acs_objects_context_id_up_tr (); + +-- show errors + +create function acs_objects_context_id_del_tr () returns opaque as ' +begin + delete from acs_object_context_index + where object_id = old.object_id; + + return new; + +end;' language 'plpgsql'; + +create trigger acs_objects_context_id_del_tr before delete on acs_objects +for each row execute procedure acs_objects_context_id_del_tr (); + +-- show errors + +---------------------- +-- ATTRIBUTE VALUES -- +---------------------- + +create sequence t_acs_attribute_value_id_seq; +create view acs_attribute_value_id_seq as +select nextval('t_acs_attribute_value_id_seq') as nextval; + +create table acs_attribute_values ( + object_id integer not null + constraint acs_attr_values_obj_id_fk + references acs_objects (object_id) on delete cascade, + attribute_id integer not null + constraint acs_attr_values_attr_id_fk + references acs_attributes (attribute_id), + attr_value text default '' not null, + 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 varchar(100) not null + constraint acs_static_a_v_obj_id_fk + references acs_object_types (object_type) on delete cascade, + attribute_id integer not null + constraint acs_static_a_v_attr_id_fk + references acs_attributes (attribute_id), + attr_value text default '' not null, + 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 +-- procedure initialize_attributes +create function acs_object__initialize_attributes (integer) +returns integer as ' +declare + initialize_attributes__object_id alias for $1; + 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; + + return 0; +end;' language 'plpgsql'; + + +-- function new +create function acs_object__new (integer,varchar,timestamp,integer,varchar,integer) +returns integer as ' +declare + new__object_id alias for $1; + new__object_type alias for $2; + new__creation_date alias for $3; + new__creation_user alias for $4; + new__creation_ip alias for $5; + new__context_id alias for $6; + v_object_id acs_objects.object_id%TYPE; +begin + if new__object_id is null then + select acs_object_id_seq.nextval + into v_object_id from dual; + else + v_object_id := new__object_id; + end if; + + insert into acs_objects + (object_id, object_type, context_id, + creation_date, creation_user, creation_ip) + values + (v_object_id, new__object_type, new__context_id, + new__creation_date, new__creation_user, coalesce(new__creation_ip,'''')); + + PERFORM acs_object__initialize_attributes(v_object_id); + + return v_object_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function acs_object__delete (integer) +returns integer as ' +declare + delete__object_id alias for $1; + obj_type record; +begin + + -- Delete dynamic/generic attributes + delete from acs_attribute_values where object_id = delete__object_id; + + -- select table_name, id_column + -- from acs_object_types + -- start with object_type = (select object_type + -- from acs_objects o + -- where o.object_id = delete__object_id) + -- connect by object_type = prior supertype + + for obj_type + in (select table_name, id_column + from acs_object_types o1, acs_object_types o2 + where o1.object_type = (select object_type + from acs_objects o + where o.object_id = delete__object_id) + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%') + order by tree_sortkey desc) + loop + -- Delete from the table. + execute ''delete from '' || quote_ident(obj_type.table_name) || + '' where '' || quote_ident(obj_type.id_column) || '' = '' || delete__object_id; + end loop; + + return 0; +end;' language 'plpgsql'; + + +-- function name +create function acs_object__name (integer) +returns varchar as ' +declare + name__object_id alias for $1; + object_name varchar(500); + v_object_id integer; + obj_type record; + obj record; +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. + -- + -- 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 + + for obj_type + in (select name_method + from acs_object_types o1, acs_object_types o2 + where o1.object_type = (select object_type + from acs_objects o + where o.object_id = name__object_id) + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%') + order by tree_sortkey desc) + loop + if obj_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 ''select '' || object_type.name_method || ''(:1) from dual'' + for obj in execute ''select '' || obj_type.name_method || ''('' || name_object_id || '') as object_name'' loop + object_name := obj.object_name; + exit; + end loop; + + exit; + end if; + end loop; + + return object_name; + +end;' language 'plpgsql'; + + +-- function default_name +create function acs_object__default_name (integer) +returns varchar as ' +declare + default_name__object_id alias for $1; + 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;' language 'plpgsql'; + + +-- procedure get_attribute_storage +create function acs_object__get_attribute_storage (integer,varchar) +returns text as ' +declare + object_id_in alias for $1; + attribute_name_in alias for $2; +-- these three are the out variables +-- v_column alias for $3; +-- v_table_name alias for $4; +-- v_key_sql alias for $5; + v_object_type acs_attributes.object_type%TYPE; + v_static acs_attributes.static_p%TYPE; + v_attr_id acs_attributes.attribute_id%TYPE; + v_storage acs_attributes.storage%TYPE; + v_attr_name acs_attributes.attribute_name%TYPE; + v_id_column varchar(200); + v_sql text; + v_return text; + v_rec record; +begin + -- 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) + + -- Determine the attribute parameters + select + a.attribute_id, a.static_p, a.storage, a.table_name, a.attribute_name, + a.object_type, a.column_name, t.id_column + into + v_attr_id, v_static, v_storage, v_table_name, v_attr_name, + v_object_type, v_column, v_id_column + from + acs_attributes a, + (select object_type, id_column + from acs_object_types o1, acs_object_types o2 + where o1.object_type = (select object_type + from acs_objects o + where o.object_id = object_id_in) + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%') + ) t + where + a.attribute_name = attribute_name_in + and + a.object_type = t.object_type; + + if NOT FOUND then + raise EXCEPTION ''%: %'', -20000, + ''No such attribute '' || v_object_type || ''::'' || + attribute_name_in || '' in acs_object.get_attribute_storage.''; + end if; + + -- 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; + if NOT FOUND then + raise EXCEPTION ''%: %'', -20000, + ''No data found for attribute '' || + v_object_type || ''::'' || attribute_name_in || + '' in acs_object.get_attribute_storage''; + end if; + else + raise EXCEPTION ''%: %'', -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; + if NOT FOUND then + raise EXCEPTION ''%: %'', -20000, ''No data found for attribute '' + || v_object_type || ''::'' || attribute_name_in || + '' in acs_object.get_attribute_storage''; + end if; + 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; + + return v_column || '','' || v_table_name || '','' || v_key_sql; + +end;' language 'plpgsql'; + + +create function acs_object__get_attr_storage_column(text) +returns text as ' +declare + v_vals alias for $1; + v_idx integer; +begin + v_idx := strpos(v_vals,'',''); + if v_idx = 0 then + raise exception ''invalid storage format: acs_object.get_attr_storage_column''; + end if; + + return substr(v_vals,1,v_idx - 1); + +end;' language 'plpgsql'; + +create function acs_object__get_attr_storage_table(text) +returns text as ' +declare + v_vals alias for $1; + v_idx integer; + v_tmp varchar; +begin + v_idx := strpos(v_vals,'',''); + if v_idx = 0 then + raise exception ''invalid storage format: acs_object.get_attr_storage_table''; + end if; + v_tmp := substr(v_vals,v_idx + 1); + v_idx := strpos(v_tmp,'',''); + if v_idx = 0 then + raise exception ''invalid storage format: acs_object.get_attr_storage_table''; + end if; + + return substr(v_tmp,1,v_idx - 1); + +end;' language 'plpgsql'; + +create function acs_object__get_attr_storage_sql(text) +returns text as ' +declare + v_vals alias for $1; + v_idx integer; + v_tmp varchar; +begin + v_idx := strpos(v_vals, '',''); + if v_idx = 0 then + raise exception ''invalid storage format: acs_object.get_attr_storage_sql''; + end if; + v_tmp := substr(v_vals, v_idx + 1); + v_idx := strpos(v_tmp, '',''); + if v_idx = 0 then + raise exception ''invalid storage format: acs_object.get_attr_storage_sql''; + end if; + + return substr(v_tmp, v_idx + 1); + +end;' language 'plpgsql'; + +-- function get_attribute +create function acs_object__get_attribute (integer,varchar) +returns varchar as ' +declare + object_id_in alias for $1; + attribute_name_in alias for $2; + v_table_name varchar(200); + v_column varchar(200); + v_key_sql text; + v_return text; + v_storage text; + v_rec record; +begin + + v_storage := acs_object__get_attribute_storage(object_id_in, attribute_name_in); + + v_column := acs_object__get_attr_storage_column(v_storage); + v_table_name := acs_object__get_attr_storage_table(v_storage); + v_key_sql := acs_object__get_attr_storage_sql(v_storage); + + for v_rec in execute ''select '' || quote_ident(v_column) || '' as return from '' || quote_ident(v_table_name) || '' where '' || quote_literal(v_key_sql) + LOOP + if not FOUND then + return null; + end if; + v_return := v_rec.return; + exit; + end loop; + + return v_return; + +end;' language 'plpgsql'; + + +-- procedure set_attribute +create function acs_object__set_attribute (integer,varchar,varchar) +returns integer as ' +declare + object_id_in alias for $1; + attribute_name_in alias for $2; + value_in alias for $3; + v_table_name varchar(200); + v_column varchar(200); + v_key_sql text; + v_return text; + v_storage text; +begin + + v_storage := acs_object__get_attribute_storage(object_id_in, attribute_name_in); + + v_column := acs_object__get_attr_storage_column(v_storage); + v_table_name := acs_object__get_attr_storage_table(v_storage); + v_key_sql := acs_object__get_attr_storage_sql(v_storage); + + execute ''update '' || quote_identifier(v_table_name) || '' set '' || quote_identifier(v_column) || '' = '' || quote_literal(value_in) || '' where '' || quote_literal(v_key_sql); + + return 0; +end;' language 'plpgsql'; + + +-- function check_context_index +create function acs_object__check_context_index (integer,integer,integer) +returns boolean as ' +declare + check_context_index__object_id alias for $1; + check_context_index__ancestor_id alias for $2; + check_context_index__n_generations alias for $3; + n_rows integer; + n_gens integer; +begin + -- Verify that this row exists in the index. + select case when count(*) = 0 then 0 else 1 end 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 + PERFORM 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 + PERFORM 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;' language 'plpgsql'; + + +-- function check_object_ancestors +create function acs_object__check_object_ancestors (integer,integer,integer) +returns boolean as ' +declare + check_object_ancestors__object_id alias for $1; + check_object_ancestors__ancestor_id alias for $2; + check_object_ancestors__n_generations alias for $3; + context_id acs_objects.context_id%TYPE; + security_inherit_p acs_objects.security_inherit_p%TYPE; + n_rows integer; + n_gens integer; + result boolean; +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 check_object_ancestors__ancestor_id = 0 then + if context_id is null then + result := ''t''; + else + -- This can be a constraint, can''''t it? + PERFORM 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 acs_object__check_context_index(check_object_ancestors__object_id, check_object_ancestors__ancestor_id, check_object_ancestors__n_generations) = ''f'' then + result := ''f''; + end if; + + if acs_object__check_object_ancestors(check_object_ancestors__object_id, context_id, + check_object_ancestors__n_generations + 1) = ''f'' then + result := ''f''; + end if; + end if; + + return result; + +end;' language 'plpgsql'; + + +-- function check_object_descendants +create function acs_object__check_object_descendants (integer,integer,integer) +returns boolean as ' +declare + object_id alias for $1; + descendant_id alias for $2; + n_generations alias for $3; + result boolean; + obj record; +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 acs_object__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 acs_object__check_object_descendants(object_id, obj.object_id, + n_generations + 1) = ''f'' then + result := ''f''; + end if; + end loop; + + return result; + +end;' language 'plpgsql'; + + +-- function check_path +create function acs_object__check_path (integer,integer) +returns boolean as ' +declare + check_path__object_id alias for $1; + check_path__ancestor_id alias for $2; + context_id acs_objects.context_id%TYPE; + security_inherit_p acs_objects.security_inherit_p%TYPE; +begin + if check_path__object_id = check_path__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 acs_object__check_path(context_id, check_path__ancestor_id); + +end;' language 'plpgsql'; + + +-- function check_representation +create function acs_object__check_representation (integer) +returns boolean as ' +declare + check_representation__object_id alias for $1; + result boolean; + check_representation__object_type acs_objects.object_type%TYPE; + n_rows integer; + t record; + row record; +begin + result := ''t''; + PERFORM acs_log__notice(''acs_object.check_representation'', + ''Running acs_object.check_representation on object_id = '' || + check_representation__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; + + PERFORM 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 + for row in execute ''select case when count(*) = 0 then 0 else 1 end as n_rows from '' || quote_identifier(t.table_name) || '' where '' || quote_identifier(t.id_column) || '' = '' || check_representation__object_id + LOOP + n_rows := row.n_rows; + exit; + end LOOP; + + if n_rows = 0 then + result := ''f''; + PERFORM acs_log__error(''acs_object.check_representation'', + ''Table '' || t.table_name || '' (primary storage for '' || + t.object_type || '') doesn''''t have a row for object '' || + check_representation__object_id || '' of type '' || object_type || ''.''); + end if; + end loop; + + PERFORM 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 acs_object__check_object_ancestors(check_representation__object_id, check_representation__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 acs_object__check_object_descendants(check_representation__object_id, check_representation__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 acs_object__check_path(row.object_id, row.ancestor_id) = ''f'' then + PERFORM 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; + + PERFORM acs_log__notice(''acs_object.check_representation'', + ''Done running acs_object.check_representation '' || + ''on object_id = '' || check_representation__object_id || ''.''); + + return result; + +end;' language 'plpgsql'; + + + +-- show errors + +------------------- +-- MISCELLANEOUS -- +------------------- + +create table general_objects ( + object_id integer not null + constraint general_objects_object_id_fk + references acs_objects (object_id) + constraint general_objects_pk + primary key, + on_which_table varchar(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/postgresql/acs-objects-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-objects-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-objects-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,29 @@ +-- +-- 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 acs-objects-drop.sql,v 1.5 2000/10/24 22:26:18 bquinn Exp +-- + +\t +drop table general_objects; +select drop_package('acs_object'); +drop table acs_static_attr_values; +drop table acs_attribute_values; +drop view acs_attribute_value_id_seq; +drop sequence t_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 view acs_objbect_id_seq; +drop sequence t_acs_object_id_seq; +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-permissions-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-permissions-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-permissions-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,426 @@ +-- +-- 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 acs-permissions-create.sql,v 1.10.2.2 2001/01/12 22:59:20 oumi 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 varchar(100) not null constraint acs_privileges_pk + primary key, + pretty_name varchar(100) default '' not null, + pretty_plural varchar(100) default '' not null +); + +create table acs_privilege_hierarchy ( + privilege varchar(100) not null constraint acs_priv_hier_priv_fk + references acs_privileges (privilege), + child_privilege varchar(100) not null constraint acs_priv_hier_child_priv_fk + references acs_privileges (privilege), + constraint acs_privilege_hierarchy_pk + primary key (privilege, child_privilege) +); + +create 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 +-- procedure create_privilege +create function acs_privilege__create_privilege (varchar,varchar,varchar) +returns integer as ' +declare + create_privilege__privilege alias for $1; + create_privilege__pretty_name alias for $2; + create_privilege__pretty_plural alias for $3; +begin + insert into acs_privileges + (privilege, pretty_name, pretty_plural) + values + (create_privilege__privilege, + coalesce(create_privilege__pretty_name,''''), + coalesce(create_privilege__pretty_plural,'''')); + + return 0; +end;' language 'plpgsql'; + + +-- procedure drop_privilege +create function acs_privilege__drop_privilege (varchar) +returns integer as ' +declare + drop_privilege__privilege alias for $1; +begin + delete from acs_privileges + where privilege = drop_privilege__privilege; + + return 0; +end;' language 'plpgsql'; + + +-- procedure add_child +create function acs_privilege__add_child (varchar,varchar) +returns integer as ' +declare + add_child__privilege alias for $1; + add_child__child_privilege alias for $2; +begin + insert into acs_privilege_hierarchy + (privilege, child_privilege) + values + (add_child__privilege, add_child__child_privilege); + + return 0; +end;' language 'plpgsql'; + + +-- procedure remove_child +create function acs_privilege__remove_child (varchar,varchar) +returns integer as ' +declare + remove_child__privilege alias for $1; + remove_child__child_privilege alias for $2; +begin + delete from acs_privilege_hierarchy + where privilege = remove_child__privilege + and child_privilege = remove_child__child_privilege; + + return 0; +end;' language 'plpgsql'; + + + +-- show errors + + +------------------------------------ +-- OPERATIONAL LEVEL: PERMISSIONS -- +------------------------------------ + +create table acs_permissions ( + object_id integer not null + constraint acs_permissions_on_what_id_fk + references acs_objects (object_id), + grantee_id integer not null + constraint acs_permissions_grantee_id_fk + references parties (party_id), + privilege varchar(100) 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 index acs_permissions_privilege_idx on acs_permissions (privilege); + +create 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 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 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 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 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 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 view all_object_party_privilege_map as +select 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 +-- procedure grant_permission +create function acs_permission__grant_permission (integer, integer, varchar) +returns integer as ' +declare + grant_permission__object_id alias for $1; + grant_permission__grantee_id alias for $2; + grant_permission__privilege alias for $3; +begin + insert into acs_permissions + (object_id, grantee_id, privilege) + values + (grant_permission__object_id, grant_permission__grantee_id, grant_permission__privilege); + + -- FIXME: find out what this means? + -- exception + -- when dup_val_on_index then + -- return; + return 0; +end;' language 'plpgsql'; + + +-- procedure revoke_permission +create function acs_permission__revoke_permission (integer, integer, varchar) +returns integer as ' +declare + revoke_permission__object_id alias for $1; + revoke_permission__grantee_id alias for $2; + revoke_permission__privilege alias for $3; +begin + delete from acs_permissions + where object_id = revoke_permission__object_id + and grantee_id = revoke_permission__grantee_id + and privilege = revoke_permission__privilege; + + return 0; +end;' language 'plpgsql'; + + +-- function permission_p +create function acs_permission__permission_p () +returns boolean as ' +declare + permission_p__object_id integer; + permission_p__party_id integer; + permission_p__privilege integer; + exists_p boolean; +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 case when count(*) = 0 then ''f'' else ''t'' end 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;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-permissions-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-permissions-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-permissions-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,25 @@ +-- +-- packages/acs-kernel/sql/acs-permissions-drop.sql +-- +-- @creation-date 2000-08-13 +-- +-- @author rhs@mit.edu +-- +-- @cvs-id acs-permissions-drop.sql,v 1.5 2000/10/24 22:26:19 bquinn 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; +\t +select drop_package('acs_permission'); +drop table acs_permissions; +--drop view acs_privilege_method_map; +--drop table acs_privilege_method_rules; +select drop_package('acs_privilege'); +\t +drop table acs_privilege_hierarchy; +drop table acs_privileges; +--drop table acs_methods; Index: openacs-4/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-relationships-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,603 @@ +-- +-- packages/acs-kernel/sql/acs-relationships-create.sql +-- +-- XXX Fill this in later. +-- +-- @creation-date 2000-08-13 +-- +-- @author rhs@mit.edu +-- +-- @cvs-id acs-relationships-create.sql,v 1.7.2.2 2001/01/12 23:03:26 mbryzek Exp +-- + +---------------------------------------------------------------- +-- KNOWLEDGE LEVEL: RELATIONSHIP TYPES AND RELATIONSHIP RULES -- +---------------------------------------------------------------- + +create table acs_rel_roles ( + role varchar(100) not null + constraint acs_rel_roles_pk primary key, + pretty_name varchar(100) not null, + pretty_plural varchar(100) not null +); + +create table acs_rel_types ( + rel_type varchar(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 varchar(100) not null + constraint acs_rel_types_obj_type_1_fk + references acs_object_types (object_type), + role_one varchar(100) 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 varchar(100) not null + constraint acs_rel_types_obj_type_2_fk + references acs_object_types (object_type), + role_two varchar(100) 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 index acs_rel_types_objtypeone_idx on acs_rel_types (object_type_one); +create index acs_rel_types_role_one_idx on acs_rel_types (role_one); +create index acs_rel_types_objtypetwo_idx on acs_rel_types (object_type_two); +create 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 +-- procedure create_role +create function acs_rel_type__create_role (varchar,varchar,varchar) +returns integer as ' +declare + create_role__role alias for $1; + create_role__pretty_name alias for $2; + create_role__pretty_plural alias for $3; +begin + insert into acs_rel_roles + (role, pretty_name, pretty_plural) + values + (create_role__role, coalesce(create_role__pretty_name,create_role__role), coalesce(create_role__pretty_plural,create_role__role)); + + return 0; +end;' language 'plpgsql'; + + +-- procedure drop_role +create function acs_rel_type__drop_role (varchar) +returns integer as ' +declare + drop_role__role alias for $1; +begin + delete from acs_rel_roles + where role = drop_role__role; + + return 0; +end;' language 'plpgsql'; + + +-- function role_pretty_name +create function acs_rel_type__role_pretty_name (varchar) +returns varchar as ' +declare + role_pretty_name__role alias for $1; + 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;' language 'plpgsql'; + + +-- function role_pretty_plural +create function acs_rel_type__role_pretty_plural (varchar) +returns varchar as ' +declare + role_pretty_plural__role alias for $1; + 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;' language 'plpgsql'; + + +-- procedure create_type +create function acs_rel_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer,varchar,varchar,integer,integer) +returns integer as ' +declare + create_type__rel_type alias for $1; + create_type__pretty_name alias for $2; + create_type__pretty_plural alias for $3; + create_type__table_name alias for $4; + create_type__id_column alias for $5; + create_type__package_name alias for $6; + create_type__object_type_one alias for $7; + create_type__role_one alias for $8; + + create_type__min_n_rels_one alias for $9; + create_type__max_n_rels_one alias for $10; + + create_type__object_type_two alias for $11; + create_type__role_two alias for $12; + + create_type__min_n_rels_two alias for $13; + create_type__max_n_rels_two alias for $14; + + type_extension_table acs_object_types.type_extension_table%TYPE default null; + supertype acs_object_types.supertype%TYPE default ''relationship''; + abstract_p acs_object_types.abstract_p%TYPE default ''f''; + name_method acs_object_types.name_method%TYPE default null; +begin + PERFORM acs_object_type__create_type( + create_type__rel_type, + create_type__pretty_name, + create_type__pretty_plural, + supertype, + create_type__table_name, + create_type__id_column, + create_type__package_name, + abstract_p, + type_extension_table, + 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); + + return 0; +end;' language 'plpgsql'; + + + +-- procedure create_type +create function acs_rel_type__create_type (varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer,varchar,integer,integer) +returns integer as ' +declare + create_type__rel_type alias for $1; + create_type__pretty_name alias for $2; + create_type__pretty_plural alias for $3; + create_type__supertype alias for $4; + create_type__table_name alias for $5; + create_type__id_column alias for $6; + create_type__package_name alias for $7; + create_type__type_extension_table alias for $8; + create_type__object_type_one alias for $9; + create_type__min_n_rels_one alias for $10; + create_type__max_n_rels_one alias for $11; + create_type__object_type_two alias for $12; + create_type__min_n_rels_two alias for $13; + create_type__max_n_rels_two alias for $14; + + abstract_p acs_object_types.abstract_p%TYPE default ''f''; + name_method acs_object_types.name_method%TYPE default null; + create_type__role_one acs_rel_types.role_one%TYPE default null; + create_type__role_two acs_rel_types.role_two%TYPE default null; +begin + + PERFORM acs_object_type__create_type( + create_type__rel_type, + create_type__pretty_name, + create_type__pretty_plural, + create_type__supertype, + create_type__table_name, + create_type__id_column, + create_type__package_name, + abstract_p, + create_type__type_extension_table, + 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); + + return 0; +end;' language 'plpgsql'; + + +-- procedure drop_type +create function acs_rel_type__drop_type (varchar,boolean) +returns integer as ' +declare + drop_type__rel_type alias for $1; + drop_type__cascade_p alias for $2; +begin + -- XXX do cascade_p + delete from acs_rel_types + where rel_type = drop_type__rel_type; + + PERFORM acs_object_type__drop_type(drop_type__rel_type, drop_type__cascade_p); + + return 0; +end;' language 'plpgsql'; + + + +-- show errors + select acs_rel_type__create_type ( + 'relationship', + 'Relationship', + 'Relationships', + 'acs_object', + 'acs_rels', + 'rel_id', + 'acs_rel', + 'acs_rel_types', + 'acs_object', + 0, + null::integer, + 'acs_object', + 0, + null::integer + ); + + +-- show errors + +-------------------------------------- +-- OPERATIONAL LEVEL: RELATIONSHIPS -- +-------------------------------------- + +create sequence t_acs_rel_id_seq; +create view acs_rel_id_seq as +select nextval('t_acs_rel_id_seq') as nextval; + +create table acs_rels ( + rel_id integer not null + constraint acs_rels_rel_id_fk + references acs_objects (object_id) + constraint acs_rels_pk primary key, + rel_type varchar(100) not null + constraint acs_rels_rel_type_fk + references acs_rel_types (rel_type), + object_id_one integer not null + constraint acs_object_rels_one_fk + references acs_objects (object_id), + object_id_two integer 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 function acs_rels_in_tr () returns opaque as ' +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; + + 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 + and t.tree_sortkey + like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = rt.object_type_one)) + and exists (select 1 + from acs_object_types t + where t.object_type = o2.object_type + and t.tree_sortkey + like (select o.tree_sortkey || '%' + from acs_object_types o + where o.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; + + if NOT 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 EXCEPTION ''%: %'', -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 if; + + return new; + +end;' language 'plpgsql'; + +create trigger acs_rels_in_tr before insert or update on acs_rels +for each row execute procedure acs_rels_in_tr (); + +-- 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, +-- x 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 +-- function new +create function acs_rel__new (integer,varchar,integer,integer,integer,integer,varchar) +returns integer as ' +declare + new__rel_id alias for $1; + new__rel_type alias for $2; + new__object_id_one alias for $3; + new__object_id_two alias for $4; + context_id alias for $5; + creation_user alias for $6; + creation_ip alias for $7; + 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 ( + new__rel_id, + new__rel_type, + now(), + creation_user, + creation_ip, + context_id + ); + + 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;' language 'plpgsql'; + + +-- procedure delete +create function acs_rel__delete (integer) +returns integer as ' +declare + rel_id alias for $1; +begin + PERFORM acs_object__delete(rel_id); + + return 0; +end;' language 'plpgsql'; + +----------- +-- 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 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 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/postgresql/acs-relationships-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/acs-relationships-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/acs-relationships-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,19 @@ +-- +-- packages/acs-kernel/sql/acs-relationships-drop.sql +-- +-- @creation-date 2000-08-13 +-- +-- @author rhs@mit.edu +-- +-- @cvs-id acs-relationships-drop.sql,v 1.5 2000/10/24 22:26:19 bquinn Exp +-- + +\t +select drop_package('acs_rel'); +select drop_package('acs_rel_type'); +\t +drop table acs_rels; +drop view acs_rel_id_seq; +drop sequence t_acs_rel_id_seq; +drop table acs_rel_types; +drop table acs_rel_roles; Index: openacs-4/packages/acs-kernel/sql/postgresql/apm-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/apm-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/apm-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,3023 @@ +-- +-- /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 apm-create.sql,v 1.21.2.5 2001/01/22 19:10:41 mayoff Exp + +----------------------------- +-- PACKAGE OBJECT -- +----------------------------- + +----------------------------- +-- Knowledge Level -- +----------------------------- + +create table apm_package_types ( + package_key varchar(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 varchar(100) + constraint apm_package_types_pretty_pl_un unique, + package_uri varchar(1500) + constraint apm_packages_types_p_uri_nn not null + constraint apm_packages_types_p_uri_un unique, + package_type varchar(300) + constraint apm_packages_pack_type_ck + check (package_type in ('apm_application', 'apm_service')), + spec_file_path varchar(1500), + spec_file_mtime integer, + singleton_p boolean default 'f' not null +); + +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. +'; + + +create function inline_0 () +returns integer as ' +begin +-- Create a new object type for packages. + PERFORM acs_object_type__create_type ( + ''apm_package'', + ''Package'', + ''Packages'', + ''acs_object'', + ''APM_PACKAGES'', + ''package_id'', + ''apm_package'', + ''f'', + ''apm_package_types'', + ''apm_package.name'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +create function inline_1 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin +-- Register the meta-data for APM-packages + attr_id := acs_attribute__create_attribute ( + ''apm_package'', + ''package_key'', + ''string'', + ''Package Key'', + ''Package Keys'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package'', + ''package_uri'', + ''string'', + ''Package URI'', + ''Package URIs'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package'', + ''spec_file_path'', + ''string'', + ''Specification File Path'', + ''Specification File Paths'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package'', + ''spec_file_mtime'', + ''number'', + ''Specification File Modified Time'', + ''Specification File Modified Times'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package'', + ''singleton_p'', + ''boolean'', + ''Singleton'', + ''Singletons'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_1 (); + +drop function inline_1 (); + + +-- show errors + +create table apm_packages ( + package_id integer constraint apm_packages_package_id_fk + references acs_objects(object_id) + constraint apm_packages_pack_id_pk primary key, + package_key varchar(100) constraint apm_packages_package_key_fk + references apm_package_types(package_key), + instance_name varchar(300) + constraint apm_packages_inst_name_nn not null, + enabled_p boolean default 'f' +); + +create 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 varchar(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 varchar(100) + constraint apm_package_vers_ver_name_nn not null, + version_uri varchar(1500) + constraint apm_package_vers_ver_uri_nn not null + constraint apm_package_vers_ver_uri_un unique, + summary varchar(3000) default '' not null, + description_format varchar(100) + constraint apm_package_vers_desc_for_ck + check (description_format in ('text/html', 'text/plain')), + description text default '' not null, + release_date timestamp, + vendor varchar(500) default '' not null, + vendor_uri varchar(1500) default '' not null, + enabled_p boolean default 'f' + constraint apm_package_vers_enabled_p_nn not null, + installed_p boolean default 'f' + constraint apm_package_vers_inst_p_nn not null, + tagged_p boolean default 'f' + constraint apm_package_vers_tagged_p_nn not null, + imported_p boolean default 'f' + constraint apm_package_vers_imp_p_nn not null, + data_model_loaded_p boolean default 'f' + constraint apm_package_vers_dml_p_nn not null, + cvs_import_results text default '' not null, + activation_date timestamp, + deactivation_date timestamp, + -- FIXME: use this as the blob_id + distribution_tarball integer, + distribution_uri varchar(1500) default '' not null, + distribution_date timestamp, + 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. + +create function inline_2 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + attr_id := acs_object_type__create_type ( + ''apm_package_version'', + ''Package Version'', + ''Package Versions'', + ''acs_object'', + ''APM_PACKAGE_VERSIONS'', + ''version_id'', + ''APM_PACKAGE_VERSION'', + ''f'', + null, + null + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''package_key'', + ''string'', + ''Package Key'', + ''Package Keys'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''version_name'', + ''string'', + ''Version Name'', + ''Version Names'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''version_uri'', + ''string'', + ''Version URI'', + ''Version URIs'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''summary'', + ''string'', + ''Summary'', + ''Summaries'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''description_format'', + ''string'', + ''Description Format'', + ''Description Formats'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''description'', + ''string'', + ''Description'', + ''Descriptions'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''vendor'', + ''string'', + ''Vendor'', + ''Vendors'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''vendor_uri'', + ''string'', + ''Vendor URI'', + ''Vendor URIs'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''enabled_p'', + ''string'', + ''Enabled'', + ''Enabled'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''activation_date'', + ''date'', + ''Activation Date'', + ''Activation Dates'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''deactivation_date'', + ''string'', + ''Deactivation Date'', + ''Deactivation Dates'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''distribution_uri'', + ''string'', + ''Distribution URI'', + ''Distribution URIs'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_package_version'', + ''distribution_date'', + ''date'', + ''Distribution Date'', + ''Distribution Dates'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_2 (); + +drop function inline_2 (); + + +-- show errors + +-- Who owns a version? +create table apm_package_owners ( + version_id integer 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 varchar(1500) default '' not null, + owner_name varchar(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 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, +-- FIXME: + 0 as 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 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 varchar(50) + constraint apm_package_file_types_pk primary key, + pretty_name varchar(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. +'; + +create function inline_3 () +returns integer as ' +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''); + + return 0; +end;' language 'plpgsql'; + +select inline_3 (); + +drop function inline_3 (); + + +-- 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 integer constraint apm_package_files_ver_id_fk references apm_package_versions + on delete cascade + constraint apm_package_files_ver_id_nn not null, + path varchar(1500) + constraint apm_package_files_path_nn not null, + file_type varchar(50) constraint apm_package_files_type_fk references apm_package_file_types, + constraint apm_package_files_un unique(version_id, path) +); + +create 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 view apm_file_info as + select f.*, p.package_key, 'packages/' || p.package_key || '/' || f.path as 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 integer constraint apm_parameters_fk + references acs_objects(object_id) + constraint apm_parameters_pk primary key, + package_key varchar(100) + constraint apm_pack_param_pack_key_nn not null + constraint apm_pack_param_type_fk + references apm_package_types (package_key), + parameter_name varchar(100) + constraint apm_pack_params_name_nn not null, + description varchar(2000) default '' not null, + section_name varchar(200) default '' not null, + datatype varchar(100) not null + constraint apm_parameter_datatype_ck + check(datatype in ('number', 'string')), + default_value text default '' not null, + 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 integer constraint apm_parameter_values_fk + references acs_objects(object_id) + constraint apm_parameter_values_pk primary key, + package_id integer constraint apm_pack_values_obj_id_fk + references apm_packages (package_id) on delete cascade, + parameter_id integer constraint apm_pack_values_parm_id_fk + references apm_parameters (parameter_id), + attr_value text default '' not null, + 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. + +create function inline_4 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + attr_id := acs_object_type__create_type ( + ''apm_parameter'', + ''Package Parameter'', + ''Package Parameters'', + ''acs_object'', + ''APM_PARAMETERS'', + ''parameter_id'', + ''apm_parameter'', + ''f'', + null, + null + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter'', + ''package_key'', + ''string'', + ''Package Key'', + ''Package Keys'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter'', + ''parameter_name'', + ''string'', + ''Parameter Name'', + ''Parameter Name'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter'', + ''datatype'', + ''string'', + ''Datatype'', + ''Datatypes'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter'', + ''default_value'', + ''string'', + ''Default Value'', + ''Default Values'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter'', + ''min_n_values'', + ''number'', + ''Minimum Number of Values'', + ''Minimum Numer of Values Settings'', + null, + null, + 1, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter'', + ''max_n_values'', + ''string'', + ''Maximum Number of Values'', + ''Maximum Number of Values Settings'', + null, + null, + 1, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_4 (); + +drop function inline_4 (); + + +-- show errors + + +create function inline_5 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + attr_id := acs_object_type__create_type ( + ''apm_parameter_value'', + ''APM Package Parameter Value'', + ''APM Package Parameter Values'', + ''acs_object'', + ''apm_parameter_values'', + ''value_id'', + ''apm_parameter_value'', + ''f'', + null, + null + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter_value'', + ''package_id'', + ''number'', + ''Package ID'', + ''Package IDs'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter_value'', + ''parameter_id'', + ''number'', + ''Parameter ID'', + ''Parameter IDs'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''apm_parameter_value'', + ''attr_value'', + ''string'', + ''Parameter Value'', + ''Parameter Values'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_5 (); + +drop function inline_5 (); + + +-- show errors + +create table apm_package_dependencies ( + dependency_id integer + constraint apm_package_deps_id_pk primary key, + version_id integer 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 varchar(20) + constraint apm_package_deps_type_nn not null + constraint apm_package_deps_type_ck check(dependency_type in ('provides','requires')), + service_uri varchar(1500) + constraint apm_package_deps_uri_nn not null, + service_version varchar(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. +'; + + +create function inline_6 () +returns integer as ' +declare + dummy integer; +begin +-- Create a new object type for applications. + dummy := acs_object_type__create_type ( + ''apm_application'', + ''Application'', + ''Applications'', + ''apm_package'', + ''apm_applications'', + ''application_id'', + ''apm_application'', + ''f'', + null, + null + ); + + return 0; +end;' language 'plpgsql'; + +select inline_6 (); + +drop function inline_6 (); + + +-- show errors + + +create function inline_7 () +returns integer as ' +declare + dummy integer; +begin +-- Create a new object type for services. + dummy := acs_object_type__create_type ( + ''apm_service'', + ''Service'', + ''Services'', + ''apm_package'', + ''apm_services'', + ''service_id'', + ''apm_service'', + ''f'', + null, + null + ); + + return 0; +end;' language 'plpgsql'; + +select inline_7 (); + +drop function inline_7 (); + + +-- 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 +-- procedure register_package +create function apm__register_package (varchar,varchar,varchar,varchar,varchar,boolean,varchar,integer) +returns integer as ' +declare + package_key alias for $1; + pretty_name alias for $2; + pretty_plural alias for $3; + package_uri alias for $4; + package_type alias for $5; + singleton_p alias for $6; + spec_file_path alias for $7; + spec_file_mtime alias for $8; +begin + PERFORM apm_package_type__create_type( + package_key, + pretty_name, + pretty_plural, + package_uri, + package_type, + singleton_p, + spec_file_path, + spec_file_mtime + ); + + return 0; +end;' language 'plpgsql'; + + +-- function update_package +create function apm__update_package (varchar,varchar,varchar,varchar,varchar,boolean,varchar,integer) +returns varchar as ' +declare + package_key alias for $1; + pretty_name alias for $2; + pretty_plural alias for $3; + package_uri alias for $4; + package_type alias for $5; + singleton_p alias for $6; + spec_file_path alias for $7; + spec_file_mtime alias for $8; +begin + + return apm_package_type__update_type( + package_key, + pretty_name, + pretty_plural, + package_uri, + package_type, + singleton_p, + spec_file_path, + spec_file_mtime + ); + +end;' language 'plpgsql'; + + +-- procedure unregister_package +create function apm__unregister_package (varchar,boolean) +returns integer as ' +declare + package_key alias for $1; + cascade_p alias for $2; +begin + PERFORM apm_package_type__drop_type( + package_key, + cascade_p + ); + + return 0; +end;' language 'plpgsql'; + + +-- function register_p +create function apm__register_p (varchar) +returns integer as ' +declare + register_p__package_key alias for $1; + v_register_p integer; +begin + select case when count(*) = 0 then 0 else 1 end into v_register_p + from apm_package_types + where package_key = register_p__package_key; + + return v_register_p; + +end;' language 'plpgsql'; + + +-- procedure register_application +create function apm__register_application (varchar,varchar,varchar,varchar,boolean,varchar,integer) +returns integer as ' +declare + package_key alias for $1; + pretty_name alias for $2; + pretty_plural alias for $3; + package_uri alias for $4; + singleton_p alias for $5; + spec_file_path alias for $6; + spec_file_mtime alias for $7; +begin + PERFORM apm__register_package( + package_key, + pretty_name, + pretty_plural, + package_uri, + ''apm_application'', + singleton_p, + spec_file_path, + spec_file_mtime + ); + + return 0; +end;' language 'plpgsql'; + + +-- procedure unregister_application +create function apm__unregister_application (varchar,boolean) +returns integer as ' +declare + package_key alias for $1; + cascade_p alias for $2; +begin + PERFORM apm__unregister_package ( + package_key, + cascade_p + ); + + return 0; +end;' language 'plpgsql'; + + +-- procedure register_service +create function apm__register_service (varchar,varchar,varchar,varchar,boolean,varchar,integer) +returns integer as ' +declare + package_key alias for $1; + pretty_name alias for $2; + pretty_plural alias for $3; + package_uri alias for $4; + singleton_p alias for $5; + spec_file_path alias for $6; + spec_file_mtime alias for $7; +begin + PERFORM apm__register_package( + package_key, + pretty_name, + pretty_plural, + package_uri, + ''apm_service'', + singleton_p, + spec_file_path, + spec_file_mtime + ); + + return 0; +end;' language 'plpgsql'; + + +-- procedure unregister_service +create function apm__unregister_service (varchar,boolean) +returns integer as ' +declare + package_key alias for $1; + cascade_p alias for $2; +begin + PERFORM apm__unregister_package ( + package_key, + cascade_p + ); + + return 0; +end;' language 'plpgsql'; + + +-- function register_parameter +create function apm__register_parameter (integer,varchar,varchar,varchar,varchar,varchar,varchar,integer,integer) +returns integer as ' +declare + register_parameter__parameter_id alias for $1; + register_parameter__package_key alias for $2; + register_parameter__parameter_name alias for $3; + register_parameter__description alias for $4; + register_parameter__datatype alias for $5; + register_parameter__default_value alias for $6; + register_parameter__section_name alias for $7; + register_parameter__min_n_values alias for $8; + register_parameter__max_n_values alias for $9; + + v_parameter_id apm_parameters.parameter_id%TYPE; + cur_val record; +begin + -- Create the new parameter. + v_parameter_id := acs_object__new( + register_parameter__parameter_id, + ''apm_parameter'', + now(), + null, + null, + null + ); + + 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, + coalesce(register_parameter__description,''''), register_parameter__package_key, + register_parameter__datatype, coalesce(register_parameter__default_value,''''), + coalesce(register_parameter__section_name,''''), register_parameter__min_n_values, + register_parameter__max_n_values); + + -- Propagate parameter to new instances. + for cur_val in select ap.package_id, p.parameter_id, p.default_value + from apm_parameters p left outer join apm_parameter_values v + using (parameter_id), apm_packages ap + where p.package_key = ap.package_key + and v.attr_value is null + and p.package_key = register_parameter__package_key + loop + PERFORM apm__set_value( + cur_val.parameter_id, + cur_val.package_id, + cur_val.default_value + ); + end loop; + + return v_parameter_id; + +end;' language 'plpgsql'; + + +-- function update_parameter +create function apm__update_parameter (integer,varchar,varchar,varchar,varchar,varchar,integer,integer) +returns varchar as ' +declare + update_parameter__parameter_id alias for $1; + update_parameter__parameter_name alias for $2; + update_parameter__description alias for $3; + update_parameter__datatype alias for $4; + update_parameter__default_value alias for $5; + update_parameter__section_name alias for $6; + update_parameter__min_n_values alias for $7; + update_parameter__max_n_values alias for $8; +begin + update apm_parameters + set parameter_name = coalesce(update_parameter__parameter_name, parameter_name), + default_value = coalesce(update_parameter__default_value, default_value), + datatype = coalesce(update_parameter__datatype, datatype), + description = coalesce(update_parameter__description, description), + section_name = coalesce(update_parameter__section_name, section_name), + min_n_values = coalesce(update_parameter__min_n_values, min_n_values), + max_n_values = coalesce(update_parameter__max_n_values, max_n_values) + where parameter_id = update_parameter__parameter_id; + + return parameter_id; + +end;' language 'plpgsql'; + + +-- function parameter_p +create function apm__parameter_p (varchar,varchar) +returns integer as ' +declare + parameter_p__package_key alias for $1; + parameter_p__parameter_name alias for $2; + v_parameter_p integer; +begin + select case when count(*) = 0 then 0 else 1 end 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;' language 'plpgsql'; + + +-- procedure unregister_parameter +create function apm__unregister_parameter (integer) +returns integer as ' +declare + unregister_parameter__parameter_id alias for $1; +begin + delete from apm_parameter_values + where parameter_id = unregister_parameter__parameter_id; + delete from apm_parameters + where parameter_id = unregister_parameter__parameter_id; + PERFORM acs_object__delete(parameter_id); + + return 0; +end;' language 'plpgsql'; + + +-- function id_for_name +create function apm__id_for_name (varchar,varchar) +returns integer as ' +declare + id_for_name__parameter_name alias for $1; + id_for_name__package_key alias for $2; + 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;' language 'plpgsql'; + + +-- function get_value +create function apm__get_value (integer,integer) +returns varchar as ' +declare + get_value__parameter_id alias for $1; + get_value__package_id alias for $2; + 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;' language 'plpgsql'; + + +-- function get_value +create function apm__get_value (integer,varchar) +returns varchar as ' +declare + get_value__package_id alias for $1; + get_value__parameter_name alias for $2; + 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( + v_parameter_id, + get_value__package_id + ); + +end;' language 'plpgsql'; + + +-- procedure set_value +create function apm__set_value (integer,integer,varchar) +returns integer as ' +declare + set_value__parameter_id alias for $1; + set_value__package_id alias for $2; + set_value__attr_value alias for $3; + 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 + if NOT FOUND + then + v_value_id := apm_parameter_value__new( + null, + set_value__package_id, + set_value__parameter_id, + set_value__attr_value + ); + end if; + + return 0; +end;' language 'plpgsql'; + + +-- procedure set_value +create function apm__set_value (integer,varchar,varchar) +returns integer as ' +declare + set_value__package_id alias for $1; + set_value__parameter_name alias for $2; + set_value__attr_value alias for $3; + 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); + + if NOT FOUND + then + raise EXCEPTION ''%: %'', -20000, ''The specified package '' + || set_value__package_id || '' does not exist in the system.''; + end if; + + PERFORM apm__set_value( + v_parameter_id, + set_value__package_id, + set_value__attr_value + ); + + return 0; +end;' language 'plpgsql'; + + + +-- show errors + +-- create or replace package body apm_package +-- procedure initialize_parameters +create function apm_package__initialize_parameters (integer,varchar) +returns integer as ' +declare + ip__package_id alias for $1; + ip__package_key alias for $2; + v_value_id apm_parameter_values.value_id%TYPE; + cur_val record; +begin + -- need to initialize all params for this type + for cur_val in select parameter_id, default_value + from apm_parameters + where package_key = ip__package_key + loop + v_value_id := apm_parameter_value__new( + null, + ip__package_id, + cur_val.parameter_id, + cur_val.default_value + ); + end loop; + + return 0; +end;' language 'plpgsql'; + + +-- function new +create function apm_package__new (integer,varchar,varchar,varchar,timestamp,integer,varchar,integer) +returns integer as ' +declare + new__package_id alias for $1; + new__instance_name alias for $2; + new__package_key alias for $3; + new__object_type alias for $4; + new__creation_date alias for $5; + new__creation_user alias for $6; + new__creation_ip alias for $7; + new__context_id alias for $8; + 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( + new__package_key + ); + v_num_instances := apm_package__num_instances( + 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 = new__package_key; + + return v_package_id; + else + v_package_id := acs_object__new( + new__package_id, + new__object_type, + new__creation_date, + new__creation_user, + new__creation_ip, + new__context_id + ); + if instance_name is null then + v_instance_name := new__package_key || '' '' || v_package_id; + else + v_instance_name := new__instance_name; + end if; + + select package_type into v_package_type + from apm_package_types + where package_key = new__package_key; + + insert into apm_packages + (package_id, package_key, instance_name) + values + (v_package_id, new__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; + + PERFORM apm_package__initialize_parameters( + v_package_id, + new__package_key + ); + + return v_package_id; + + end if; +end;' language 'plpgsql'; + +create function apm_package__delete (integer) returns integer as ' +declare + delete__package_id alias for $1; + cur_val record; +begin + -- Delete all parameters. + for cur_val in select value_id from apm_parameter_values + where package_id = delete__package_id loop + PERFORM apm_parameter_value__delete(cur_val.value_id); + end loop; + + delete from apm_applications where application_id = delete__package_id; + delete from apm_services where service_id = delete__package_id; + delete from apm_packages where package_id = delete__package_id; + -- Delete the site nodes for the objects. + for cur_val in select node_id from site_nodes + where object_id = delete__package_id loop + PERFORM site_node__delete(cur_val.node_id); + end loop; + -- Delete the object. + PERFORM acs_object__delete ( + delete__package_id + ); + + return 0; +end;' language 'plpgsql'; + +create function apm_package__singleton_p (varchar) returns integer as ' +declare + singleton_p__package_key alias for $1; + 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''; + + if NOT FOUND then + return 0; + else + return v_singleton_p; + end if; +end;' language 'plpgsql'; + +create function apm_package__num_instances (varchar) returns integer as ' +declare + num_instances__package_key alias for $1; + v_num_instances integer; +begin + select count(*) into v_num_instances + from apm_packages + where package_key = num_instances__package_key; + + -- exception + if NOT FOUND then + return 0; + else + return v_num_instances; + end if; + +end;' language 'plpgsql'; + +create function apm_package__name (integer) returns varchar as ' +declare + name__package_id alias for $1; + 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;' language 'plpgsql'; + +create function apm_package__enable (integer) returns integer as ' +declare + enable__package_id alias for $1; +begin + update apm_packages + set enabled_p = ''t'' + where package_id = enable__package_id; + + return 0; +end;' language 'plpgsql'; + +create function apm_package__disable (integer) returns integer as ' +declare + disable__package_id alias for $1; +begin + update apm_packages + set enabled_p = ''f'' + where package_id = disable__package_id; + + returns 0; +end;' language 'plpgsql'; + +create function apm_package__highest_version (varchar) returns integer as ' +declare + highest_version__package_key alias for $1; + 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; + if NOT FOUND then + return 0; + else + return v_version_id; + end if; +end;' language 'plpgsql'; + + +-- create or replace package body apm_package_version +create function apm_package_version__new (integer,varchar,varchar,varchar,varchar,varchar,varchar,timestamp,varchar,varchar,boolean,boolean) returns integer as ' +declare + apm_pkg_ver__version_id alias for $1; + apm_pkg_ver__package_key alias for $2; + apm_pkg_ver__version_name alias for $3; + apm_pkg_ver__version_uri alias for $4; + apm_pkg_ver__summary alias for $5; + apm_pkg_ver__description_format alias for $6; + apm_pkg_ver__description alias for $7; + apm_pkg_ver__release_date alias for $8; + apm_pkg_ver__vendor alias for $9; + apm_pkg_ver__vendor_uri alias for $10; + apm_pkg_ver__installed_p alias for $11; + apm_pkg_ver__data_model_loaded_p alias for $12; + v_version_id apm_package_versions.version_id%TYPE; +begin + if apm_pkg_ver__version_id is null then + select acs_object_id_seq.nextval + into v_version_id + from dual; + else + v_version_id := apm_pkg_ver__version_id; + end if; + + v_version_id := acs_object__new( + v_version_id, + ''apm_package_version'', + now(), + null, + null, + null + ); + + 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, apm_pkg_ver__package_key, apm_pkg_ver__version_name, + apm_pkg_ver__version_uri, coalesce(apm_pkg_ver__summary,''''), + apm_pkg_ver__description_format, coalesce(apm_pkg_ver__description,''''), + apm_pkg_ver__release_date, coalesce(apm_pkg_ver__vendor,''''), coalesce(apm_pkg_ver__vendor_uri,''''), + apm_pkg_ver__installed_p, apm_pkg_ver__data_model_loaded_p); + + return v_version_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function apm_package_version__delete (integer) +returns integer as ' +declare + delete_version_id alias for $1; +begin + delete from apm_package_owners + where version_id = delete__version_id; + + delete from apm_package_files + where version_id = delete__version_id; + + delete from apm_package_dependencies + where version_id = delete__version_id; + + delete from apm_package_versions + where version_id = delete__version_id; + + PERFORM acs_object__delete(delete__version_id); + + return 0; +end;' language 'plpgsql'; + + +-- procedure enable +create function apm_package_version__enable (integer) +returns integer as ' +declare + enable__version_id alias for $1; +begin + update apm_package_versions set enabled_p = ''t'' + where version_id = enable__version_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure disable +create function apm_package_version__disable (integer) +returns integer as ' +declare + disable_version_id alias for $1; +begin + update apm_package_versions + set enabled_p = ''f'' + where version_id = disable__version_id; + + return 0; +end;' language 'plpgsql'; + + +-- function copy +create function apm_package_version__copy (integer,integer,varchar,varchar) +returns integer as ' +declare + copy__version_id alias for $1; + copy__new_version_id alias for $2; + copy__new_version_name alias for $3; + copy__new_version_uri alias for $4; + v_version_id integer; +begin + v_version_id := acs_object__new( + new_version_id, + ''apm_package_version'', + now(), + null, + null, + null + ); + + 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;' language 'plpgsql'; + + +-- function edit +create function apm_package_version__edit (integer,integer,varchar,varchar,varchar,varchar,varchar,timestamp,varchar,varchar,char,char) +returns integer as ' +declare + edit__new_version_id alias for $1; + edit__version_id alias for $2; + edit__version_name alias for $3; + edit__version_uri alias for $4; + edit__summary alias for $5; + edit__description_format alias for $6; + edit__description alias for $7; + edit__release_date alias for $8; + edit__vendor alias for $9; + edit__vendor_uri alias for $10; + edit__installed_p alias for $11; + edit__data_model_loaded_p alias for $12; + v_version_id apm_package_versions.version_id%TYPE; + version_unchanged_p integer; +begin + -- Determine if version has changed. + select case when count(*) = 0 then 0 else 1 end 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 := apm_package_version__copy( + edit__version_id, + edit__new_version_id, + edit__version_name, + 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 = date_trunc(''days'',now()), + 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;' language 'plpgsql'; + + +-- function add_file +create function apm_package_version__add_file (integer,integer,varchar,varchar) +returns integer as ' +declare + add_file__file_id alias for $1; + add_file__version_id alias for $2; + add_file__path alias for $3; + add_file__file_type alias for $4; + 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; + + if NOT FOUND + then + if add_file__file_id is null then + select acs_object_id_seq.nextval into v_file_id from dual; + else + v_file_id := add_file__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); + end if; + + return v_file_id; + +end;' language 'plpgsql'; + + +-- procedure remove_file +create function apm_package_version__remove_file (integer,varchar) +returns integer as ' +declare + remove_file__version_id alias for $1; + remove_file__path alias for $2; +begin + delete from apm_package_files + where version_id = remove_file__version_id + and path = remove_file__path; + + return 0; +end;' language 'plpgsql'; + + +-- function add_interface +create function apm_package_version__add_interface (integer,integer,varchar,varchar) +returns integer as ' +declare + add_interface__interface_id alias for $1; + add_interface__version_id alias for $2; + add_interface__interface_uri alias for $3; + add_interface__interface_version alias for $4; + 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;' language 'plpgsql'; + + +-- procedure remove_interface +create function apm_package_version__remove_interface (integer) +returns integer as ' +declare + remove_interface__interface_id alias for $1; +begin + delete from apm_package_dependencies + where dependency_id = remove_interface__interface_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure remove_interface +create function apm_package_version__remove_interface (varchar,varchar,integer) +returns integer as ' +declare + remove_interface__interface_uri alias for $1; + remove_interface__interface_version alias for $2; + remove_interface__version_id alias for $3; + 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; + PERFORM apm_package_version__remove_interface(v_dep_id); + + return 0; +end;' language 'plpgsql'; + + +-- function add_dependency +create function apm_package_version__add_dependency (integer,integer,varchar,varchar) +returns integer as ' +declare + add_dependency__dependency_id alias for $1; + add_dependency__version_id alias for $2; + add_dependency__dependency_uri alias for $3; + add_dependency__dependency_version alias for $4; + 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;' language 'plpgsql'; + + +-- procedure remove_dependency +create function apm_package_version__remove_dependency (integer) +returns integer as ' +declare + remove_dependency__dependency_id alias for $1; +begin + delete from apm_package_dependencies + where dependency_id = remove_dependency__dependency_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure remove_dependency +create function apm_package_version__remove_dependency (varchar,varchar,integer) +returns integer as ' +declare + remove_dependency__dependency_uri alias for $1; + remove_dependency__dependency_version alias for $2; + remove_dependency__version_id alias for $3; + 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; + PERFORM apm_package_version__remove_dependency(v_dep_id); + + return 0; +end;' language 'plpgsql'; + + +-- function sortable_version_name +create function apm_package_version__sortable_version_name (varchar) +returns varchar as ' +declare + version_name alias for $1; + a_start integer; + a_end integer; + a_order varchar(1000); + a_char boolean; + a_seen_letter boolean default ''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.''; + else if a_char = ''a'' then + a_order := a_order || '' 1A.''; + else if a_char = ''b'' then + a_order := a_order || '' 2B.''; + end if; end if; 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;' language 'plpgsql'; + + +-- function version_name_greater +create function apm_package_version__version_name_greater (varchar,varchar) +returns integer as ' +declare + version_name_one alias for $1; + version_name_two alias for $2; +begin + a_order_a := apm_package_version__sortable_version_name(version_name_one); + a_order_b := apm_package_version__sortable_version_name(version_name_two); + if a_order_a < a_order_b then + return -1; + else if a_order_a > a_order_b then + return 1; + end if; end if; + + return 0; +end;' language 'plpgsql'; + +-- function upgrade_p +create function apm_package_version__upgrade_p (varchar,varchar,varchar) +returns integer as ' +declare + upgrade_p__path alias for $1; + upgrade_p__initial_version_name alias for $2; + upgrade_p__final_version_name alias for $3; + v_pos1 integer; + v_pos2 integer; + v_tmp apm_package_files.path%TYPE; + 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 := position(''.'' in v_path); + 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 apm_package_version__version_name_greater(upgrade_p__initial_version_name, v_version_from) <= 0 and + apm_package_version__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;' language 'plpgsql'; + + +-- procedure upgrade +create function apm_package_version__upgrade (integer) +returns integer as ' +declare + upgrade__version_id alias for $1; +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; + + return 0; +end;' language 'plpgsql'; + + + +-- show errors + +-- create or replace package body apm_package_type +-- procedure create_type +create function apm_package_type__create_type (varchar,varchar,varchar,varchar,varchar,boolean,varchar,integer) +returns integer as ' +declare + create_type__package_key alias for $1; + create_type__pretty_name alias for $2; + create_type__pretty_plural alias for $3; + create_type__package_uri alias for $4; + create_type__package_type alias for $5; + create_type__singleton_p alias for $6; + create_type__spec_file_path alias for $7; + create_type__spec_file_mtime alias for $8; +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 0; +end;' language 'plpgsql'; + + +-- function update_type +create function apm_package_type__update_type (varchar,varchar,varchar,varchar,varchar,boolean,varchar,integer) +returns varchar as ' +declare + update_type__package_key alias for $1; + update_type__pretty_name alias for $2; + update_type__pretty_plural alias for $3; + update_type__package_uri alias for $4; + update_type__package_type alias for $5; + update_type__singleton_p alias for $6; + update_type__spec_file_path alias for $7; + update_type__spec_file_mtime alias for $8; +begin + UPDATE apm_package_types SET + pretty_name = coalesce(update_type__pretty_name, pretty_name), + pretty_plural = coalesce(update_type__pretty_plural, pretty_plural), + package_uri = coalesce(update_type__package_uri, package_uri), + package_type = coalesce(update_type__package_type, package_type), + spec_file_path = coalesce(update_type__spec_file_path, spec_file_path), + spec_file_mtime = coalesce(update_type__spec_file_mtime, spec_file_mtime), + singleton_p = coalesce(update_type__singleton_p, singleton_p) + where package_key = update_type__package_key; + + return update_type__package_key; + +end;' language 'plpgsql'; + + +-- procedure drop_type +create function apm_package_type__drop_type (varchar,boolean) +returns integer as ' +declare + drop_type__package_key alias for $1; + drop_type__cascade_p alias for $2; + cur_val record; +begin + if drop_type__cascade_p = ''t'' then + for cur_val in select package_id + from apm_packages + where package_key = drop_type__package_key + loop + PERFORM apm_package__delete( + cur_val.package_id + ); + end loop; + -- Unregister all parameters. + for cur_val in select parameter_id from apm_parameters + where package_key = drop_type__package_key + loop + PERFORM apm__unregister_parameter(cur_val.parameter_id); + end loop; + + -- Unregister all versions + for cur_val in select version_id from apm_package_versions + where package_key = drop_type__package_key + loop + PERFORM apm_package_version__delete(cur_val.version_id); + end loop; + end if; + delete from apm_package_types + where package_key = drop_type__package_key; + + return 0; +end;' language 'plpgsql'; + + +-- function num_parameters +create function apm_package_type__num_parameters (varchar) +returns integer as ' +declare + num_parameters__package_key alias for $1; + v_count integer; +begin + select count(*) into v_count + from apm_parameters + where package_key = num_parameters__package_key; + + return v_count; + +end;' language 'plpgsql'; + + + + + +-- show errors + +-- create or replace package body apm_parameter_value +-- function new +create function apm_parameter_value__new (integer,integer,integer,varchar) +returns integer as ' +declare + new__value_id alias for $1; + new__package_id alias for $2; + new__parameter_id alias for $3; + new__attr_value alias for $4; + v_value_id apm_parameter_values.value_id%TYPE; +begin + v_value_id := acs_object__new( + new__value_id, + ''apm_parameter_value'', + now(), + null, + null, + null + ); + insert into apm_parameter_values + (value_id, package_id, parameter_id, attr_value) + values + (v_value_id, new__package_id, new__parameter_id, coalesce(new__attr_value,'''')); + + return v_value_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function apm_parameter_value__delete (integer) +returns integer as ' +declare + delete__value_id alias for $1; +begin + delete from apm_parameter_values + where value_id = delete__value_id; + PERFORM acs_object__delete(delete__value_id); + + return 0; +end;' language 'plpgsql'; + + +-- function new +create function apm_application__new (integer,varchar,varchar,varchar,timestamp,integer,varchar,integer) +returns integer as ' +declare + application_id alias for $1; + instance_name alias for $2; + package_key alias for $3; + object_type alias for $4; + creation_date alias for $5; + creation_user alias for $6; + creation_ip alias for $7; + context_id alias for $8; + v_application_id integer; +begin + v_application_id := apm_package__new ( + application_id, + instance_name, + package_key, + object_type, + creation_date, + creation_user, + creation_ip, + context_id + ); + + return v_application_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function apm_application__delete (integer) +returns integer as ' +declare + delete__application_id alias for $1; +begin + delete from apm_applications + where application_id = delete__application_id; + PERFORM apm_package__delete( + delete__application_id + ); + + return 0; +end;' language 'plpgsql'; + + + +-- show errors + +-- create or replace package body apm_service +-- function new +create function apm_service__new (integer,varchar,varchar,varchar,timestamp,integer,varchar,integer) +returns integer as ' +declare + service_id alias for $1; + instance_name alias for $2; + package_key alias for $3; + object_type alias for $4; + creation_date alias for $5; + creation_user alias for $6; + creation_ip alias for $7; + context_id alias for $8; + v_service_id integer; +begin + v_service_id := apm_package__new ( + service_id, + instance_name, + package_key, + object_type, + creation_date, + creation_user, + creation_ip, + context_id + ); + + return v_service_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function apm_service__delete (integer) +returns integer as ' +declare + delete__service_id alias for $1; +begin + delete from apm_services + where service_id = delete__service_id; + PERFORM apm_package__delete( + delete__service_id + ); + + return 0; +end;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/apm-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/apm-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/apm-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,65 @@ +-- Uninstall file for the data model created by 'apm-create.sql' +-- +-- @author Bryan Quinn (bquinn) +-- @creation-date Mon Sep 18 16:46:56 2000 +-- +-- apm-drop.sql,v 1.6 2000/10/24 22:26:19 bquinn Exp +-- +\t +select drop_package('apm_service'); +select drop_package('apm_application'); +select drop_package('apm_parameter_value'); +select drop_package('apm_package_type'); +select drop_package('apm_package_version'); +select drop_package('apm_package'); +select 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; +drop table apm_applications; +drop table apm_packages; +drop table apm_package_types; + +create function inline_0 () returns integer as ' +begin + PERFORM acs_object_type__drop_type ( + ''apm_package'', ''f'' + ); + + PERFORM acs_object_type__drop_type ( + ''apm_application'', ''f'' + ); + + PERFORM acs_object_type__drop_type ( + ''apm_service'', ''f'' + ); + + PERFORM acs_object_type__drop_type ( + ''apm_package_version'', ''f'' + ); + + PERFORM acs_object_type__drop_type ( + ''apm_parameter_value'', ''f'' + ); + + PERFORM acs_object_type__drop_type ( + ''apm_parameter'', ''f'' + ); + + return null; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/community-core-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/community-core-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/community-core-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,725 @@ +-- +-- 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 community-core-create.sql,v 1.11.2.2 2001/01/12 22:49:48 mbryzek 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 + +create function inline_0 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + -- + -- Party: the supertype of person and organization + -- + PERFORM acs_object_type__create_type ( + ''party'', + ''Party'', + ''Parties'', + ''acs_object'', + ''parties'', + ''party_id'', + ''party'', + ''f'', + null, + ''party.name'' + ); + + attr_id := acs_attribute__create_attribute ( + ''party'', + ''email'', + ''string'', + ''Email Address'', + ''Email Addresses'', + null, + null, + null, + 0, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''party'', + ''url'', + ''string'', + ''URL'', + ''URLs'', + null, + null, + null, + 0, + 1, + null, + ''type_specific'', + ''f'' + ); + + -- + -- Person: the supertype of user + -- + attr_id := acs_object_type__create_type ( + ''person'', + ''Person'', + ''People'', + ''party'', + ''persons'', + ''person_id'', + ''person'', + ''f'', + null, + ''person.name'' + ); + + attr_id := acs_attribute__create_attribute ( + ''person'', + ''first_names'', + ''string'', + ''First Names'', + ''First Names'', + null, + null, + null, + 0, + 1, + null, + ''type_specific'', + ''f'' + ); + + attr_id := acs_attribute__create_attribute ( + ''person'', + ''last_name'', + ''string'', + ''Last Name'', + ''Last Names'', + null, + null, + null, + 0, + 1, + null, + ''type_specific'', + ''f'' + ); + -- + -- User: people who have registered in the system + -- + attr_id := acs_object_type__create_type ( + ''user'', + ''User'', + ''Users'', + ''person'', + ''users'', + ''user_id'', + ''acs_user'', + ''f'', + null, + null + ); + + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +-- ****************************************************************** +-- * OPERATIONAL LEVEL +-- ****************************************************************** + +create table parties ( + party_id integer not null + constraint parties_party_id_fk references + acs_objects (object_id) + constraint parties_pk primary key, + email varchar(100) + constraint parties_email_un unique, + url varchar(200) default '' not null +); + +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 +-- function new +create function party__new (integer,varchar,timestamp,integer,varchar,varchar,varchar,integer) +returns integer as ' +declare + new__party_id alias for $1; + new__object_type alias for $2; + new__creation_date alias for $3; + new__creation_user alias for $4; + new__creation_ip alias for $5; + new__email alias for $6; + new__url alias for $7; + new__context_id alias for $8; + v_party_id parties.party_id%TYPE; +begin + v_party_id := + acs_object__new(new__party_id, new__object_type, new__creation_date, + new__creation_user, new__creation_ip, new__context_id); + + insert into parties + (party_id, email, url) + values + (v_party_id, lower(new__email), coalesce(new__url,'''')); + + return v_party_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function party__delete (integer) +returns integer as ' +declare + party_id alias for $1; +begin + PERFORM acs_object__delete(party_id); + + return 0; +end;' language 'plpgsql'; + + +-- function name +create function party__name (integer) +returns integer as ' +declare + party_id alias for $1; +begin + if party_id = -1 then + return ''The Public''; + else + return null; + end if; + +end;' language 'plpgsql'; + + + +-- show errors + +------------- +-- PERSONS -- +------------- + +create table persons ( + person_id integer not null + constraint persons_person_id_fk + references parties (party_id) + constraint persons_pk primary key, + first_names varchar(100) not null, + last_name varchar(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 +-- function new +create function person__new (integer,varchar,timestamp,integer,varchar,varchar,varchar,varchar,varchar,integer) +returns integer as ' +declare + new__person_id alias for $1; + new__object_type alias for $2; + new__creation_date alias for $3; + new__creation_user alias for $4; + new__creation_ip alias for $5; + new__email alias for $6; + new__url alias for $7; + new__first_names alias for $8; + new__last_name alias for $9; + new__context_id alias for $10; + v_person_id persons.person_id%TYPE; +begin + v_person_id := + party__new(new__person_id, new__object_type, + new__creation_date, new__creation_user, new__creation_ip, + new__email, new__url, new__context_id); + + insert into persons + (person_id, first_names, last_name) + values + (v_person_id, new__first_names, new__last_name); + + return v_person_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function person__delete (integer) +returns integer as ' +declare + delete__person_id alias for $1; +begin + delete from persons + where person_id = delete__person_id; + + PERFORM party__delete(delete__person_id); + + return 0; +end;' language 'plpgsql'; + + +-- function name +create function person__name (integer) +returns varchar as ' +declare + name__person_id alias for $1; + person_name varchar(200); +begin + select first_names || '' '' || last_name + into person_name + from persons + where person_id = name__person_id; + + return person_name; + +end;' language 'plpgsql'; + + + +-- show errors + +create table users ( + user_id integer not null + constraint users_user_id_fk + references persons (person_id) + constraint users_pk primary key, + password char(40), + salt char(40), + screen_name varchar(100) + constraint users_screen_name_un + unique, + priv_name integer default 0 not null, + priv_email integer default 5 not null, + email_verified_p boolean default 't', + email_bouncing_p boolean default 'f' not null, + no_alerts_until timestamp, + last_visit timestamp, + second_to_last_visit timestamp, + n_sessions integer default 1 not null, + password_question varchar(1000) default '' not null, + password_answer varchar(1000) default '' not null +); + +create table user_preferences ( + user_id integer constraint user_prefs_user_id_fk + references users (user_id) + constraint user_preferences_pk + primary key, + prefer_text_only_p boolean default 'f', + -- an ISO 639 language code (in lowercase) + language_preference char(2) default 'en', + dont_spam_me_p boolean default 'f', + email_type varchar(64) default '' not null +); + +create function inline_1 () +returns integer as ' +begin + + insert into acs_object_type_tables + (object_type, table_name, id_column) + values + (''user'', ''user_preferences'', ''user_id''); + return 0; +end;' language 'plpgsql'; + +select inline_1 (); + +drop function inline_1 (); + + +-- show errors + + +alter table acs_objects add + constraint acs_objects_creation_user_fk + foreign key (creation_user) references users(user_id); +alter table acs_objects add + 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 +-- function new +create function acs_user__new (integer,varchar,timestamp,integer,varchar,varchar,varchar,varchar,varchar,char,char,varchar,varchar,varchar,boolean,integer) +returns integer as ' +declare + new__user_id alias for $1; + new__object_type alias for $2; + new__creation_date alias for $3; + new__creation_user alias for $4; + new__creation_ip alias for $5; + new__email alias for $6; + new__url alias for $7; + new__first_names alias for $8; + new__last_name alias for $9; + new__password alias for $10; + new__salt alias for $11; + new__password_question alias for $12; + new__password_answer alias for $13; + new__screen_name alias for $14; + new__email_verified_p alias for $15; + new__context_id alias for $16; + v_user_id users.user_id%TYPE; +begin + v_user_id := + person__new(new__user_id, new__object_type, + new__creation_date, new__creation_user, new__creation_ip, + new__email, new__url, new__first_names, new__last_name, + new__context_id); + + insert into users + (user_id, password, salt, password_question, password_answer, screen_name, + email_verified_p) + values + (v_user_id, new__password, new__salt, coalesce(new__password_question,''''), + coalesce(new__password_answer,''''), new__screen_name, new__email_verified_p); + + insert into user_preferences + (user_id) + values + (v_user_id); + + return v_user_id; + +end;' language 'plpgsql'; + + +-- function receives_alerts_p +create function acs_user__receives_alerts_p (integer) +returns integer as ' +declare + receives_alerts_p__user_id alias for $1; + counter boolean; +begin + select case when count(*) = 0 then ''f'' else ''t'' end into counter + from users + where no_alerts_until >= now() + and user_id = receives_alerts_p__user_id; + + return counter; + +end;' language 'plpgsql'; + + +-- procedure approve_email +create function acs_user__approve_email (integer) +returns integer as ' +declare + approve_email__user_id alias for $1; +begin + update users + set email_verified_p = ''t'' + where user_id = approve_email__user_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure unapprove_email +create function acs_user__unapprove_email (integer) +returns integer as ' +declare + unapprove_email__user_id alias for $1; +begin + update users + set email_verified_p = ''f'' + where user_id = unapprove_email__user_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure delete +create function acs_user__delete (integer) +returns integer as ' +declare + delete__user_id alias for $1; +begin + delete from user_preferences + where user_id = delete__user_id; + + delete from users + where user_id = delete__user_id; + + PERFORM person__delete(delete__user_id); + + return 0; +end;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/community-core-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/community-core-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/community-core-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,27 @@ +-- +-- 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 community-core-drop.sql,v 1.5 2000/10/24 22:26:19 bquinn Exp +-- + +-- We need to drop the circular creation_user and modifying_user +-- references before we can drop the users table. +-- +\t +alter table acs_objects drop constraint acs_objects_creation_user_fk; +alter table acs_objects drop constraint acs_objects_modifying_user_fk; + +select drop_package('acs_user'); +drop table user_preferences; +drop table users; + +select drop_package('person'); +drop table persons; + +select drop_package('party'); +drop table parties; +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/groups-body-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/groups-body-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/groups-body-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,832 @@ +-- +-- packages/acs-kernel/sql/groups-body-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id groups-body-create.sql,v 1.1.4.1 2001/01/12 22:58:33 mbryzek Exp +-- + +-------------- +-- TRIGGERS -- +-------------- +-- a dummy trigger was defined in groups-create.sql +drop trigger membership_rels_in_tr on membership_rels; +drop function membership_rels_in_tr (); +create function membership_rels_in_tr () returns opaque as ' +declare + v_object_id_one acs_rels.object_id_one%TYPE; + v_object_id_two acs_rels.object_id_two%TYPE; + v_rel_type acs_rels.rel_type%TYPE; + v_error text; + map record; +begin + + -- First check if added this relation violated any relational constraints + v_error := rel_constraint__violation(new.rel_id); + if v_error is not null then + raise EXCEPTION ''%: %'', -20000,v_error; + end if; + + select object_id_one, object_id_two, rel_type + into v_object_id_one, v_object_id_two, v_rel_type + from acs_rels + where rel_id = new.rel_id; + + -- Insert a row for me in 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; + + return new; + +end;' language 'plpgsql'; + +create trigger membership_rels_in_tr after insert on membership_rels +for each row execute procedure membership_rels_in_tr (); + +-- show errors + +-- a dummy trigger was defined in groups-create.sql +drop trigger composition_rels_in_tr on composition_rels; +drop function composition_rels_in_tr(); +create function composition_rels_in_tr () returns opaque as ' +declare + v_object_id_one acs_rels.object_id_one%TYPE; + v_object_id_two acs_rels.object_id_two%TYPE; + v_rel_type acs_rels.rel_type%TYPE; + v_error text; + map record; +begin + + -- First check if added this relation violated any relational constraints + v_error := rel_constraint__violation(new.rel_id); + if v_error is not null then + raise EXCEPTION ''%: %'', -20000, v_error; + end if; + + select object_id_one, object_id_two, rel_type + into v_object_id_one, v_object_id_two, v_rel_type + from acs_rels + where rel_id = new.rel_id; + + -- Insert a row for me in group_element_index + insert into group_element_index + (group_id, element_id, rel_id, container_id, + rel_type, ancestor_rel_type) + values + (v_object_id_one, v_object_id_two, new.rel_id, v_object_id_one, + v_rel_type, ''composition_rel''); + + -- 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; + + return new; + +end;' language 'plpgsql'; + +create trigger composition_rels_in_tr after insert on composition_rels +for each row execute procedure composition_rels_in_tr (); + +-- show errors + +create function membership_rels_del_tr () returns opaque as ' +declare + v_error text; +begin + -- First check if removing this relation would violate any relational constraints + v_error := rel_constraint__violation_if_removed(old.rel_id); + if v_error is not null then + raise EXCEPTION ''%: %'', -20000, v_error; + end if; + + delete from group_element_index + where rel_id = old.rel_id; + + return new; + +end;' language 'plpgsql'; + +create trigger membership_rels_del_tr before delete on membership_rels +for each row execute procedure membership_rels_del_tr (); + +-- show errors + +-- +-- TO DO: See if this can be optimized now that the member and component +-- mapping tables have been combined +-- +create function composition_rels_del_tr () returns opaque as ' +declare + v_object_id_one acs_rels.object_id_one%TYPE; + v_object_id_two acs_rels.object_id_two%TYPE; + n_rows integer; + v_error text; + map record; +begin + -- First check if removing this relation would violate any relational constraints + v_error := rel_constraint__violation_if_removed(old.rel_id); + if v_error is not null then + raise EXCEPTION ''%: %'', -20000, v_error; + end if; + + select object_id_one, object_id_two into v_object_id_one, v_object_id_two + from acs_rels + where rel_id = old.rel_id; + + for map in (select * + from group_component_map + where rel_id = old.rel_id) loop + + delete from group_element_index + where rel_id = old.rel_id; + + select count(*) into n_rows + from group_component_map + where group_id = map.group_id + and component_id = map.component_id; + + if n_rows = 0 then + 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; + + return new; + +end;' language 'plpgsql'; + +create trigger composition_rels_del_tr before delete on composition_rels +for each row execute procedure composition_rels_del_tr (); + +-- show errors + + +-------------------- +-- PACKAGE BODIES -- +-------------------- + +-- create or replace package body composition_rel +-- function new +create function composition_rel__new (integer,varchar,integer,integer,integer,varchar) +returns integer as ' +declare + new__rel_id alias for $1; + rel_type alias for $2; + object_id_one alias for $3; + object_id_two alias for $4; + creation_user alias for $5; + creation_ip alias for $6; + v_rel_id integer; +begin + v_rel_id := acs_rel__new ( + new__rel_id, + rel_type, + object_id_one, + object_id_two, + object_id_one, + creation_user, + creation_ip + ); + + insert into composition_rels + (rel_id) + values + (v_rel_id); + + return v_rel_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function composition_rel__delete (integer) +returns integer as ' +declare + rel_id alias for $1; +begin + PERFORM acs_rel__delete(rel_id); + + return 0; +end;' language 'plpgsql'; + + +-- function check_path_exists_p +create function composition_rel__check_path_exists_p (integer,integer) +returns boolean as ' +declare + component_id alias for $1; + container_id alias for $2; + row record; +begin + if component_id = container_id then + return ''t''; + end if; + + for row in (select r.object_id_one as parent_id + from acs_rels r, composition_rels c + where r.rel_id = c.rel_id + and r.object_id_two = component_id) loop + if composition_rel__check_path_exists_p(row.parent_id, container_id) = ''t'' then + return ''t''; + end if; + end loop; + + return ''f''; + +end;' language 'plpgsql'; + + +-- function check_index +create function composition_rel__check_index (integer,integer) +returns boolean as ' +declare + check_index__component_id alias for $1; + check_index__container_id alias for $2; + result boolean; + n_rows integer; + dc record; + r1 record; + r2 record; +begin + result := ''t''; + + -- Loop through all the direct containers (DC) of COMPONENT_ID + -- that are also contained by CONTAINER_ID and verify that the + -- GROUP_COMPONENT_INDEX contains the (GROUP_ID, DC.REL_ID, + -- CONTAINER_ID) triple. + for dc in (select r.rel_id, r.object_id_one as container_id + from acs_rels r, composition_rels c + where r.rel_id = c.rel_id + and r.object_id_two = check_index__component_id) loop + + if composition_rel__check_path_exists_p(dc.container_id, + check_index__container_id) = ''t'' then + select case when count(*) = 0 then 0 else 1 end into n_rows + from group_component_index + where group_id = check_index__container_id + and component_id = check_index__component_id + and rel_id = dc.rel_id; + + if n_rows = 0 then + result := ''f''; + PERFORM acs_log__error(''composition_rel.check_representation'', + ''Row missing from group_component_index for ('' || + ''group_id = '' || check_index__container_id || '', '' || + ''component_id = '' || check_index__component_id || '', '' || + ''rel_id = '' || dc.rel_id || '')''); + end if; + + end if; + + end loop; + + -- Loop through all the containers of CONTAINER_ID. + for r1 in (select r.object_id_one as container_id + from acs_rels r, composition_rels c + where r.rel_id = c.rel_id + and r.object_id_two = check_index__container_id + union + select check_index__container_id as container_id + from dual) loop + -- Loop through all the components of COMPONENT_ID and make a + -- recursive call. + for r2 in (select r.object_id_two as component_id + from acs_rels r, composition_rels c + where r.rel_id = c.rel_id + and r.object_id_one = check_index__component_id + union + select check_index__component_id as component_id + from dual) loop + if (r1.container_id != check_index__container_id or + r2.component_id != check_index__component_id) and + composition_rel__check_index(r2.component_id, r1.container_id) = ''f'' then + result := ''f''; + end if; + end loop; + end loop; + + return result; + +end;' language 'plpgsql'; + + +-- function check_representation +create function composition_rel__check_representation (integer) +returns boolean as ' +declare + check_representation__rel_id alias for $1; + container_id groups.group_id%TYPE; + component_id groups.group_id%TYPE; + result boolean; + row record; +begin + result := ''t''; + + if acs_object__check_representation(check_representation__rel_id) = ''f'' then + result := ''f''; + end if; + + select object_id_one, object_id_two + into container_id, component_id + from acs_rels + where rel_id = check_representation__rel_id; + + -- First let''s check that the index has all the rows it should. + if composition_rel__check_index(component_id, container_id) = ''f'' then + result := ''f''; + end if; + + -- Now let''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 composition_rel__check_path_exists_p(row.component_id, row.group_id) = ''f'' then + result := ''f''; + PERFORM acs_log__error(''composition_rel.check_representation'', + ''Extraneous row in group_component_index: '' || + ''group_id = '' || row.group_id || '', '' || + ''component_id = '' || row.component_id || '', '' || + ''rel_id = '' || row.rel_id || '', '' || + ''container_id = '' || row.container_id || ''.''); + end if; + end loop; + + return result; + +end;' language 'plpgsql'; + + + +-- show errors + + + + +-- create or replace package body membership_rel +-- function new +create function membership_rel__new (integer,varchar,integer,integer,varchar,integer,varchar) +returns integer as ' +declare + new__rel_id alias for $1; + rel_type alias for $2; + object_id_one alias for $3; + object_id_two alias for $4; + new__member_state alias for $5; + creation_user alias for $6; + creation_ip alias for $7; + v_rel_id integer; +begin + v_rel_id := acs_rel__new ( + new__rel_id, + rel_type, + object_id_one, + object_id_two, + object_id_one, + creation_user, + creation_ip + ); + + insert into membership_rels + (rel_id, member_state) + values + (v_rel_id, new__member_state); + + return v_rel_id; + +end;' language 'plpgsql'; + + +-- procedure ban +create function membership_rel__ban (integer) +returns integer as ' +declare + ban__rel_id alias for $1; +begin + update membership_rels + set member_state = ''banned'' + where rel_id = ban__rel_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure approve +create function membership_rel__approve (integer) +returns integer as ' +declare + approve__rel_id alias for $1; +begin + update membership_rels + set member_state = ''approved'' + where rel_id = approve__rel_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure reject +create function membership_rel__reject (integer) +returns integer as ' +declare + reject__rel_id alias for $1; +begin + update membership_rels + set member_state = ''rejected'' + where rel_id = reject__rel_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure unapprove +create function membership_rel__unapprove (integer) +returns integer as ' +declare + unapprove__rel_id alias for $1; +begin + update membership_rels + set member_state = ''need approval'' + where rel_id = unapprove__rel_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure deleted +create function membership_rel__deleted (integer) +returns integer as ' +declare + deleted__rel_id alias for $1; +begin + update membership_rels + set member_state = ''deleted'' + where rel_id = deleted__rel_id; + + return 0; +end;' language 'plpgsql'; + + +-- procedure delete +create function membership_rel__delete (integer) +returns integer as ' +declare + rel_id alias for $1; +begin + PERFORM acs_rel__delete(rel_id); + + return 0; +end;' language 'plpgsql'; + + +-- function check_index +create function membership_rel__check_index (integer,integer,integer) +returns boolean as ' +declare + check_index__group_id alias for $1; + check_index__member_id alias for $2; + check_index__container_id alias for $3; + result boolean; + n_rows integer; + row record; +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''; + PERFORM acs_log__error(''membership_rel.check_representation'', + ''Row missing from group_member_index: '' || + ''group_id = '' || check_index__group_id || '', '' || + ''member_id = '' || check_index__member_id || '', '' || + ''container_id = '' || check_index__container_id || ''.''); + end if; + + for row in (select r.object_id_one as container_id + from acs_rels r, composition_rels c + where r.rel_id = c.rel_id + and r.object_id_two = check_index__group_id) loop + if membership_rel__check_index(row.container_id, check_index__member_id, check_index__container_id) = ''f'' then + result := ''f''; + end if; + end loop; + + return result; + +end;' language 'plpgsql'; + + +-- function check_representation +create function membership_rel__check_representation (integer) +returns boolean as ' +declare + check_representation__rel_id alias for $1; + group_id groups.group_id%TYPE; + member_id parties.party_id%TYPE; + result boolean; + row record; +begin + result := ''t''; + + if acs_object__check_representation(check_representation__rel_id) = ''f'' then + result := ''f''; + end if; + + select r.object_id_one, r.object_id_two + into group_id, member_id + from acs_rels r, membership_rels m + where r.rel_id = m.rel_id + and m.rel_id = check_representation__rel_id; + + if membership_rel__check_index(group_id, member_id, group_id) = ''f'' then + result := ''f''; + end if; + + for row in (select * + from group_member_index + where rel_id = check_representation__rel_id) loop + if composition_rel__check_path_exists_p(row.container_id, + row.group_id) = ''f'' then + result := ''f''; + PERFORM acs_log__error(''membership_rel.check_representation'', + ''Extra row in group_member_index: '' || + ''group_id = '' || row.group_id || '', '' || + ''member_id = '' || row.member_id || '', '' || + ''container_id = '' || row.container_id || ''.''); + end if; + end loop; + + return result; + +end;' language 'plpgsql'; + + + +-- show errors + + + +-- create or replace package body acs_group +-- function new +create function acs_group__new (integer,varchar,timestamp,integer,varchar,varchar,varchar,varchar,varchar,integer) +returns integer as ' +declare + new__group_id alias for $1; + new__object_type alias for $2; + new__creation_date alias for $3; + new__creation_user alias for $4; + new__creation_ip alias for $5; + new__email alias for $6; + new__url alias for $7; + new__group_name alias for $8; + new__join_policy alias for $9; + new__context_id alias for $10; + v_group_id groups.group_id%TYPE; + v_group_type_exists_p integer; + v_join_policy groups.join_policy%TYPE; +begin + v_group_id := + party__new(new__group_id, new__object_type, new__creation_date, + new__creation_user, new__creation_ip, new__email, + new__url, new__context_id); + + v_join_policy := new__join_policy; + + -- if join policy was not specified, select the default based on group type + if v_join_policy is null then + select count(*) into v_group_type_exists_p + from group_types + where group_type = new__object_type; + + if v_group_type_exists_p = 1 then + select default_join_policy into v_join_policy + from group_types + where group_type = new__object_type; + else + v_join_policy := ''open''; + end if; + end if; + + insert into groups + (group_id, group_name, join_policy) + values + (v_group_id, new__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;' language 'plpgsql'; + + +-- procedure delete +create function acs_group__delete (integer) +returns integer as ' +declare + delete__group_id alias for $1; + row record; +begin + + -- Delete all segments defined for this group + for row in (select segment_id + from rel_segments + where group_id = delete__group_id) loop + + PERFORM rel_segment__delete(row.segment_id); + + end loop; + + -- Delete all the relations of any type to this group + for row in (select r.rel_id, t.package_name + from acs_rels r, acs_object_types t + where r.rel_type = t.object_type + and (r.object_id_one = delete__group_id + or r.object_id_two = delete__group_id)) loop + execute ''perform '' || row.package_name || ''__delete('' || row.rel_id || '')''; + end loop; + + PERFORM party__delete(delete__group_id); + + return 0; +end;' language 'plpgsql'; + + +-- function name +create function acs_group__name (integer) +returns varchar as ' +declare + name__group_id alias for $1; + group_name varchar(200); +begin + select group_name + into group_name + from groups + where group_id = name__group_id; + + return group_name; + +end;' language 'plpgsql'; + + +-- function member_p +create function acs_group__member_p (integer) +returns boolean as ' +declare + party_id alias for $1; +begin + -- TO DO: implement this for real + return ''t''; + +end;' language 'plpgsql'; + + +-- function check_representation +create function acs_group__check_representation (integer) +returns boolean as ' +declare + group_id alias for $1; + result boolean; + c record; + m record; +begin + result := ''t''; + PERFORM acs_log__notice(''acs_group.check_representation'', + ''Running check_representation on group '' || group_id); + + if acs_object__check_representation(group_id) = ''f'' then + 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; + + PERFORM acs_log__notice(''acs_group.check_representation'', + ''Done running check_representation on group '' || group_id); + return result; + +end;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/groups-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/groups-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/groups-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,529 @@ +-- +-- packages/acs-kernel/sql/groups-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id groups-create.sql,v 1.16.2.3 2001/01/19 00:50:37 mbryzek 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 integer 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 integer constraint membership_rel_rel_id_fk + references acs_rels (rel_id) + constraint membership_rel_rel_id_pk + primary key, + -- null means waiting for admin approval + member_state varchar(20) constraint membership_rel_mem_ck + check (member_state in ('approved', 'needs approval', + 'banned', 'rejected', 'deleted')) +); + +create function inline_0 () +returns integer as ' +declare + attr_id acs_attributes.attribute_id%TYPE; +begin + -- + -- Group: a composite party + -- + attr_id := acs_object_type__create_type ( + ''group'', + ''Group'', + ''Groups'', + ''party'', + ''groups'', + ''group_id'', + ''acs_group'', + ''f'', + ''group_types'', + ''acs_group.name'' + ); + + attr_id := acs_attribute__create_attribute ( + ''group'', + ''group_name'', + ''string'', + ''Group name'', + ''Group names'', + null, + null, + null, + 1, + 1, + null, + ''type_specific'', + ''f'' + ); + + -- + -- Composition Relationship + -- + attr_id := acs_rel_type__create_role (''composite'', ''Composite'', ''Composites''); + attr_id := acs_rel_type__create_role (''component'', ''Component'', ''Components''); + + attr_id := acs_rel_type__create_type ( + ''composition_rel'', + ''Composition Relation'', + ''Composition Relationships'', + ''composition_rels'', + ''rel_id'', + ''composition_rel'', + ''group'', + ''composite'', + 0, + null, + ''group'', + ''component'', + 0, + null + ); + + + -- + -- Membership Relationship + -- + attr_id := acs_rel_type__create_role (''member'', ''Member'', ''Members''); + + attr_id := acs_rel_type__create_type ( + ''membership_rel'', + ''Membership Relation'', + ''Membership Relationships'', + ''membership_rels'', + ''rel_id'', + ''membership_rel'', + ''group'', + null, + 0, + null, + ''person'', + ''member'', + 0, + null + ); + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +create table group_types ( + group_type varchar(100) not null + constraint group_types_pk primary key + constraint group_types_obj_type_fk + references acs_object_types (object_type), + approval_policy varchar(30) not null, + default_join_policy varchar(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 integer not null + constraint groups_group_id_fk + references parties (party_id) + constraint groups_pk primary key, + group_name varchar(100) not null, + join_policy varchar(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 varchar(100) not null + constraint gtr_rel_type_fk + references acs_rel_types (rel_type) + on delete cascade, + group_type varchar(100) 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 varchar(100) not null + constraint group_rels_rel_type_fk + references acs_rel_types (rel_type) + on delete cascade, + group_id integer 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" + +-- oumi@arsdigita.com - Jan 04, 2001 - +-- Combined group_member_index and group_element_index into one table. This +-- allows for simpler queries about party aggregation, especially for +-- relational segments (see rel-segments-create.sql). + +create table group_element_index ( + group_id integer not null + constraint group_element_index_grp_id_fk + references groups (group_id), + element_id integer not null + constraint group_element_index_elem_id_fk + references parties (party_id), + rel_id integer not null + constraint group_element_index_rel_id_fk + references acs_rels (rel_id), + container_id integer not null + constraint group_element_index_cont_id_fk + references groups (group_id), + rel_type varchar(100) not null + constraint group_elem_index_rel_type_fk + references acs_rel_types (rel_type), + ancestor_rel_type varchar(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) +); + +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 view group_element_map +as select group_id, element_id, rel_id, container_id, + rel_type, ancestor_rel_type + from group_element_index; + +create 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 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 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 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 view group_component_index as select * from group_component_map; +create view group_member_index as select * from group_member_map; + + +--------------- +-- FUNCTIONS -- +--------------- +-- drop function group_contains_p (integer, integer, integer); +create function group_contains_p (integer, integer, integer) +returns boolean as ' +declare + group_contains_p__group_id alias for $1; + group_contains_p__component_id alias for $2; + group_contains_p__rel_id alias for $3; + map record; +begin + if group_contains_p__group_id = group_contains_p__component_id then + return ''t''; + else + if group_contains_p__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_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_contains_p__group_id, map.group_id) = ''t'' then + return ''t''; + end if; + end loop; + end if; + return ''f''; + end if; +end;' language 'plpgsql'; + + + +-- 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 function membership_rels_in_tr () returns opaque as ' +declare +begin + raise EXCEPTION ''%: %'', -20000,''Insert to membership rels not yet supported''; + + return new; + +end;' language 'plpgsql'; + +create trigger membership_rels_in_tr after insert on membership_rels +for each row execute procedure membership_rels_in_tr (); + +-- show errors + + +create function composition_rels_in_tr () returns opaque as ' +declare +begin + raise EXCEPTION ''%: %'', -20000,''Insert to membership rels not yet supported''; + + return new; + +end;' language 'plpgsql'; + +create trigger composition_rels_in_tr after insert on composition_rels +for each row execute procedure composition_rels_in_tr(); + +-- 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/postgresql/groups-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/groups-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/groups-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,27 @@ +- +-- packages/acs-kernel/sql/groups-drop.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-08-22 +-- @cvs-id groups-drop.sql,v 1.5.2.1 2001/01/12 23:01:01 mbryzek Exp +-- +\t +select drop_package('acs_group'); +drop function group_contains_p(integer,integer,integer); +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; +select drop_package('composition_rel'); +select drop_package('membership_rel'); +drop table composition_rels; +drop table membership_rels; +drop table group_types; +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/journal-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/journal-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/journal-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,158 @@ +-- Data model to keep a journal of all actions on objects. +-- +-- +-- @author Lars Pind (lars@pinds.com) +-- @creation-date 2000-22-18 +-- @cvs-id journal-create.sql,v 1.7.2.1 2000/12/08 00:38:24 yon 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 function inline_0 () +returns integer as ' +begin + PERFORM acs_object_type__create_type ( + ''journal_entry'', + ''Journal Entry'', + ''Journal Entries'', + ''acs_object'', + ''journal_entries'', + ''journal_id'', + ''journal_entry'', + ''f'', + null, + null + ); + + -- XXX fill in all the attributes in later. + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +create table journal_entries ( + journal_id integer 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 varchar(100) default '' not null, + action_pretty text default '' not null, + msg text default '' not null +); + +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 +-- function new +create function journal_entry__new (integer,integer,varchar,varchar,timestamp,integer,varchar,varchar) +returns integer as ' +declare + new__journal_id alias for $1; + new__object_id alias for $2; + new__action alias for $3; + new__action_pretty alias for $4; + new__creation_date alias for $5; + new__creation_user alias for $6; + new__creation_ip alias for $7; + new__msg alias for $8; + v_journal_id journal_entries.journal_id%TYPE; +begin + v_journal_id := acs_object__new ( + new__journal_id, + ''journal_entry'', + new__creation_date, + new__creation_user, + new__creation_ip, + new__object_id + ); + + insert into journal_entries ( + journal_id, object_id, action, action_pretty, msg + ) values ( + v_journal_id, new__object_id, coalesce(new__action,''''), + coalesce(new__action_pretty,''''), coalesce(new__msg,'''') + ); + + return v_journal_id; + +end;' language 'plpgsql'; + + +-- procedure delete +create function journal_entry__delete (integer) +returns integer as ' +declare + delete__journal_id alias for $1; +begin + delete from journal_entries where journal_id = delete__journal_id; + PERFORM acs_object__delete(delete__journal_id); + + return 0; +end;' language 'plpgsql'; + + +-- procedure delete_for_object +create function journal_entry__delete_for_object (integer) +returns integer as ' +declare + delete_for_object__object_id alias for $1; + journal_rec record; +begin + for journal_rec in select journal_id + from journal_entries + where object_id = delete_for_object__object_id + LOOP + PERFORM journal_entry__delete(journal_rec.journal_id); + end loop; + + return 0; +end;' language 'plpgsql'; + + + +-- show errors + Index: openacs-4/packages/acs-kernel/sql/postgresql/journal-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/journal-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/journal-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,24 @@ +-- +-- 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 journal-drop.sql,v 1.5 2000/10/24 22:26:20 bquinn Exp +-- + +\t +create function inline_0 () returns integer as ' +begin + PERFORM acs_object_type__drop_type( + ''journal_entry'', ''f'' + ); + return null; +end;' language 'plpgsql'; + +select inline_0 (); +drop function inline_0 (); +select drop_package('journal_entry'); +\t +drop table journal_entries; Index: openacs-4/packages/acs-kernel/sql/postgresql/load-data1.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/load-data1.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/load-data1.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,34 @@ + + + +insert into acs_object_types (object_type,supertype) + values + ('acs_object', null); +insert into acs_object_types (object_type,supertype) + values + ('relationship', 'acs_object'); +insert into acs_object_types (object_type,supertype) + values + ('party', 'acs_object'); +insert into acs_object_types (object_type,supertype) + values + ('person', 'party'); +insert into acs_object_types (object_type,supertype) + values + ('user', 'person'); +insert into acs_object_types (object_type,supertype) + values + ('group', 'party'); +insert into acs_object_types (object_type,supertype) + values + ('membership_rel', 'acs_object'); +insert into acs_object_types (object_type,supertype) + values + ('composition_rel', 'acs_object'); +insert into acs_object_types (object_type,supertype) + values + ('journal_entry', 'acs_object'); +insert into acs_object_types (object_type,supertype) + values + ('site_node', 'acs_object'); + 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 -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/postgresql.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,373 @@ +create function instr(varchar,char,integer,integer) returns integer as ' +declare + str alias for $1; + pat alias for $2; + dir alias for $3; + cnt alias for $4; + v_len integer; + v_i integer; + v_c char; + v_cnt integer; + v_inc integer; +begin + v_len := length(str); + v_cnt := 0; + + if dir < 0 then + v_inc := \-1; + v_i := v_len; + else + v_inc := 1; + v_i := 1; + end if; + + while v_i > 0 and v_i <= v_len LOOP + v_c := substr(str,v_i,1); + if v_c::char = pat::char then + v_cnt := v_cnt + 1; + if v_cnt = cnt then + return v_i; + end if; + end if; + v_i := v_i + v_inc; + end loop; + + return 0; + +end;' language 'plpgsql'; + + +create function instr(varchar,char,integer) returns integer as ' +declare + str alias for $1; + pat alias for $2; + dir alias for $3; +begin + return instr(str,pat,dir,1); +end;' language 'plpgsql'; + + +create function get_func_drop_command (varchar) returns varchar as ' +declare + fname alias for $1; + nargs integer default 0; + v_pos integer; + v_funcdef text; + v_args varchar; + v_one_arg varchar; + v_one_type varchar; + v_nargs integer; +begin + v_funcdef := ''drop function '' || fname || ''(''; + + select proargtypes, pronargs + into v_args, v_nargs + from pg_proc + where proname = fname::name; + + v_pos := position('' '' in v_args); + + while nargs < v_nargs loop + nargs := nargs + 1; + if nargs = v_nargs then + v_one_arg := v_args; + v_args := ''''; + else + v_one_arg := substr(v_args, 1, v_pos \- 1); + v_args := substr(v_args, v_pos + 1); + v_pos := position('' '' in v_args); + end if; + select case when nargs = 1 + then typname + else '','' || typname + end into v_one_type + from pg_type + where oid = v_one_arg; + v_funcdef := v_funcdef || v_one_type; + end loop; + v_funcdef := v_funcdef || '')''; + + return v_funcdef; + +end;' language 'plpgsql'; + +create function drop_package (varchar) returns varchar as ' +declare + package_name alias for $1; + v_rec record; + v_drop_cmd varchar; + v_pkg_name varchar; +begin + raise NOTICE ''DROP PACKAGE: %'', package_name; + v_pkg_name := package_name || ''\\\\_\\\\_'' || ''%''; + + for v_rec in select proname + from pg_proc + where proname like v_pkg_name + order by proname + LOOP + raise NOTICE ''DROPPING FUNCTION: %'', v_rec.proname; + v_drop_cmd := get_func_drop_command (v_rec.proname); + EXECUTE v_drop_cmd; + end loop; + + if NOT FOUND then + raise EXCEPTION ''PACKAGE: % NOT FOUND'', package_name; + else + raise NOTICE ''PACKAGE: %: DROPPED'', package_name; + end if; + + return null; + +end;' language 'plpgsql'; + + +-- tree query support, m-vgID method. + +CREATE TABLE tree_encodings ( + deci int primary key, + code char(1) +); + +create index tree_encode_idx on tree_encodings(code); + + +copy tree_encodings from stdin using delimiters '/' ; +0/0 +1/1 +2/2 +3/3 +4/4 +5/5 +6/6 +7/7 +8/8 +9/9 +10/: +11/; +12/A +13/B +14/C +15/D +16/E +17/F +18/G +19/H +20/I +21/J +22/K +23/L +24/M +25/N +26/O +27/P +28/Q +29/R +30/S +31/T +32/U +33/V +34/W +35/X +36/Y +37/Z +38/a +39/b +40/c +41/d +42/e +43/f +44/g +45/h +46/i +47/j +48/k +49/l +50/m +51/n +52/o +53/p +54/q +55/r +56/s +57/t +58/u +59/v +60/w +61/x +62/y +63/z +64/� +65/� +66/� +67/� +68/� +69/� +70/� +71/� +72/� +73/� +74/� +75/� +76/� +77/� +78/� +79/� +80/� +81/� +82/� +83/� +84/� +85/� +86/� +87/� +88/� +89/� +90/� +91/� +92/� +93/� +94/� +95/� +96/� +97/� +98/� +99/� +100/� +101/� +102/� +103/� +104/� +105/� +106/� +107/� +108/� +109/� +110/� +111/� +112/� +113/� +114/� +115/� +116/� +117/� +118/� +119/� +120/� +121/� +122/� +123/� +124/� +125/� +126/� +127/� +128/� +129/� +130/� +131/� +132/� +133/� +134/� +135/� +136/� +137/� +138/� +139/� +140/� +141/� +142/� +143/� +144/� +145/� +146/� +147/� +148/� +149/� +150/� +151/� +152/� +153/� +154/� +155/� +156/� +157/� +158/� +\. + +create function tree_default_encoding_base() returns integer as ' +begin + return 159; +end;' language 'plpgsql'; + +create function tree_next_key(varchar) returns varchar as ' +declare + skey alias for $1; + pos integer; + stop boolean default ''f''; + carry boolean default ''t''; + nkey varchar default ''''; + base integer; + ch char(1); +begin + base := tree_default_encoding_base(); + + if skey is null then + + return ''00''; + + else + pos := length(skey); + LOOP + ch := substr(skey,pos,1); + if carry = ''t'' then + select code::varchar || nkey, + case when code = ''0'' + then ''t'' + else ''f'' + end into nkey, carry + from tree_encodings + where deci = (select (deci + 1) % base + from tree_encodings + where code = ch); + else + nkey := ch::varchar || nkey; + end if; + pos := pos - 1; + select case when substr(skey,pos - 1,1) = ''/'' + then ''t'' + else ''f'' + end into stop; + + exit when stop = ''t''; + + END LOOP; + if carry = ''t'' then + nkey := ''0'' || nkey; + end if; + end if; + + select code::varchar || nkey into nkey + from tree_encodings + where deci = length(nkey) - 1; + + return nkey; + +end;' language 'plpgsql'; + + +create function tree_level(varchar) returns integer as ' +declare + inkey alias for $1; + cnt integer default 0; +begin + for i in 1..length(inkey) LOOP + if substr(inkey,i,1) = ''/'' then + cnt := cnt + 1; + end if; + end LOOP; + + return cnt; + +end;' language 'plpgsql'; + + Index: openacs-4/packages/acs-kernel/sql/postgresql/rel-constraints-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/rel-constraints-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/rel-constraints-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,661 @@ +-- +-- /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 rel-constraints-create.sql,v 1.1.4.8 2001/01/23 17:03:58 oumi 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". +-- + +create function inline_0 () +returns integer as ' +begin + PERFORM acs_object_type__create_type ( + ''rel_constraint'', + ''Relational Constraint'', + ''Relational Constraints'', + ''acs_object'', + ''rel_constraints'', + ''constraint_id'', + ''rel_constraint'', + ''f'', + null, + null + ); + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- 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 integer 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 integer 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 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; +*/ + +create 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 left outer join rel_segment_party_map rspm + on (rspm.segment_id = constrained_rels.required_rel_segment and + rspm.party_id = constrained_rels.container_id) +where 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 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; +*/ + +create 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 left outer join rel_segment_party_map rspm + on (rspm.segment_id = constrained_rels.required_rel_segment and + rspm.party_id = constrained_rels.party_id) +where 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_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 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 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 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 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; + + + + +create 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 right outer join + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type + from acs_object_types + where tree_sortkey like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = 'composition_rel') + or tree_sortkey like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = 'membership_rel')) comp_or_member_rel_types + ) group_rel_type_combos on (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)), parties +where 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 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; + + + +create 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 + right outer join + (select groups.group_id, comp_or_member_rel_types.rel_type + from groups, + (select object_type as rel_type + from acs_object_types + where tree_sortkey like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = 'composition_rel') + or tree_sortkey like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = 'membership_rel')) comp_or_member_rel_types + ) group_rel_type_combos on + (rc_all_constraints.group_id = group_rel_type_combos.group_id and + rc_all_constraints.rel_type = group_rel_type_combos.rel_type) +where 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 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 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 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/postgresql/rel-constraints-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/rel-constraints-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/rel-constraints-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,23 @@ +-- +-- /packages/acs-kernel/sql/rel-constraints-drop.sql +-- +-- @author Oumi Mehrotra +-- @creation-date 2000-11-22 +-- @cvs-id rel-constraints-drop.sql,v 1.1.4.1 2001/01/12 22:58:51 mbryzek Exp +\t +create function inline_0 () returns integer as ' +begin + PERFORM acs_rel_type__drop_type(''rel_constraint''); + return null; +end;' language 'plpgsql'; +select inline_0 (); +drop function inline_0 (); + +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; +select drop_package('rel_constraint'); +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-body-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-body-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-body-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,158 @@ +-- +-- packages/acs-kernel/sql/rel-segments-create.sql +-- +-- @author Oumi Mehrotra oumi@arsdigita.com +-- @creation-date 2000-11-22 +-- @cvs-id rel-segments-body-create.sql,v 1.1.4.1 2001/01/12 22:58:33 mbryzek 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 +-- function new +create function rel_segment__new (integer,varchar,timestamp,integer,varchar,varchar,varchar,varchar,integer,varchar,integer) +returns integer as ' +declare + new__segment_id alias for $1; + object_type alias for $2; + creation_date alias for $3; + creation_user alias for $4; + creation_ip alias for $5; + email alias for $6; + url alias for $7; + new__segment_name alias for $8; + new__group_id alias for $9; + new__rel_type alias for $10; + context_id alias for $11; + v_segment_id rel_segments.segment_id%TYPE; +begin + v_segment_id := + party__new(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;' language 'plpgsql'; + + +-- procedure delete +create function rel_segment__delete (integer) +returns integer as ' +declare + delete__segment_id alias for $1; + row record; +begin + + -- remove all constraints on this segment + for row in (select constraint_id + from rel_constraints + where rel_segment = delete__segment_id) loop + + PERFORM rel_constraint__delete(row.constraint_id); + + end loop; + + PERFORM party__delete(delete__segment_id); + + return 0; +end;' language 'plpgsql'; + + +-- function get +create function rel_segment__get (integer,varchar) +returns integer as ' +declare + get__group_id alias for $1; + get__rel_type alias for $2; + 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;' language 'plpgsql'; + + +-- function get_or_new +create function rel_segment__get_or_new (integer,varchar,varchar) +returns integer as ' +declare + get_or_new__group_id alias for $1; + get_or_new__rel_type alias for $2; + segment_name alias for $3; + v_segment_id rel_segments.segment_id%TYPE; + v_segment_name rel_segments.segment_name%TYPE; +begin + + v_segment_id := rel_segment__get(get_or_new__group_id,get_or_new__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 ( + null, + ''rel_segment'', + now(), + null, + null, + null, + null, + v_segment_name, + get_or_new__group_id, + get_or_new__rel_type, + get_or_new__group_id + ); + + end if; + + return v_segment_id; + + +end;' language 'plpgsql'; + + +-- function name +create function rel_segment__name (integer) +returns varchar as ' +declare + name__segment_id alias for $1; + segment_name varchar(200); +begin + select segment_name + into segment_name + from rel_segments + where segment_id = name__segment_id; + + return segment_name; + +end;' language 'plpgsql'; + + + +-- show errors + Index: openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,327 @@ +-- +-- packages/acs-kernel/sql/rel-segments-create.sql +-- +-- @author Oumi Mehrotra oumi@arsdigita.com +-- @creation-date 2000-11-22 +-- @cvs-id rel-segments-create.sql,v 1.1.4.3 2001/01/16 18:54:05 oumi 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". +-- + +create function inline_0 () +returns integer as ' +begin + -- + -- Relational Segment: a dynamically derived set of parties, defined + -- in terms of a particular type of membership or + -- composition to a particular group. + -- + PERFORM acs_object_type__create_type ( + ''rel_segment'', + ''Relational Party Segment'', + ''Relational Party Segments'', + ''party'', + ''rel_segments'', + ''segment_id'', + ''rel_segment'', + ''f'', + ''rel_segment'', + ''rel_segment.name'' + ); + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- 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 integer not null + constraint rel_segments_segment_id_fk + references parties (party_id) + constraint rel_segments_pk primary key, + segment_name varchar(230) not null, + group_id integer not null + constraint rel_segments_group_id_fk + references groups (group_id), + rel_type varchar(100) 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 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 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 o1, acs_object_types o2 + where o1.object_type = gem.rel_type + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%')); + +create view rel_segment_distinct_party_map +as select distinct segment_id, party_id, ancestor_rel_type + from rel_segment_party_map; + +create 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'; + + +-- Need to find out what this optimizer hint does? DCW, 2001-03-13. +-- create 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 view rel_seg_approved_member_map +as select 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 o1, acs_object_types o2 + where o1.object_type = gem.rel_type + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%')) + and mr.rel_id = gem.rel_id and mr.member_state = 'approved'; + +create 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 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 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 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 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); + +create 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 o1, acs_object_types o2 + where o1.object_type = acs_rel_types.rel_type + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%')); + Index: openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/rel-segments-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,32 @@ +-- +-- packages/acs-kernel/sql/rel-segments-drop.sql +-- +-- @author oumi@arsdigita.com +-- @creation-date 2000-11-22 +-- @cvs-id rel-segments-drop.sql,v 1.1.4.1 2001/01/12 22:58:51 mbryzek Exp +\t +create function inline_0 () +declare + r record; +begin + for r in (select segment_id from rel_segments) loop + PERFORM rel_segment__delete(r.segment_id); + end loop; + + PERFORM acs_object_type__drop_type(''rel_segment''); + return null; +end;' language 'plpgsql'; +select inline_0 (); + +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; +select drop_package('rel_segment'); +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/security-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/security-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/security-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,51 @@ +-- +-- /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 security-create.sql,v 1.16.2.4 2001/01/12 22:58:16 mbryzek Exp + +create table sec_session_properties ( + session_id integer + constraint sec_session_prop_session_id_nn + not null, + module varchar(50) + constraint sec_session_prop_module_nn + not null, + property_name varchar(50) + constraint sec_session_prop_prop_name_nn + not null, + property_value text default '' not null, + -- transmitted only across secure connections? + secure_p boolean, + last_hit integer + constraint sec_session_date_nn + not null, + primary key(session_id, module, property_name) +); + +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 timestamp +); + +create sequence t_sec_security_token_id_seq cache 100; +create view sec_security_token_id_seq as +select nextval('t_sec_security_token_id_seq') as nextval; + +-- 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 t_sec_id_seq cache 100 increment 100; +create view sec_id_seq as +select nextval('t_sec_id_seq') as nextval; Index: openacs-4/packages/acs-kernel/sql/postgresql/security-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/security-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/security-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,17 @@ +-- +-- /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 security-drop.sql,v 1.9.2.1 2000/12/07 15:02:15 richardl Exp +-- + +drop view sec_id_seq; +drop sequence t_sec_id_seq; +drop view sec_security_token_id_seq; +drop sequence t_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/postgresql/site-nodes-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/site-nodes-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/site-nodes-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,284 @@ +-- +-- packages/acs-kernel/sql/site-nodes-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-09-05 +-- @cvs-id site-nodes-create.sql,v 1.6.2.2 2001/01/12 22:53:32 dennis Exp +-- + +create function inline_0 () +returns integer as ' +declare + dummy integer; +begin + PERFORM acs_object_type__create_type ( + ''site_node'', + ''Site Node'', + ''Site Nodes'', + ''acs_object'', + ''site_nodes'', + ''node_id'', + ''site_node'', + ''f'', + null, + null + ); + + return 0; +end;' language 'plpgsql'; + +select inline_0 (); + +drop function inline_0 (); + + +-- show errors + +-- This table allows urls to be mapped to a node_ids. + +create table site_nodes ( + node_id integer constraint site_nodes_node_id_fk + references acs_objects (object_id) + constraint site_nodes_node_id_pk + primary key, + parent_id integer constraint site_nodes_parent_id_fk + references site_nodes (node_id), + name varchar(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 boolean not null, + -- Should urls that are logical children of this node be + -- mapped to this node? + pattern_p boolean default 'f' not null, + object_id integer 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 +-- function new +create function site_node__new (integer,integer,varchar,integer,boolean,boolean,integer,varchar) +returns integer as ' +declare + new__node_id alias for $1; + new__parent_id alias for $2; + new__name alias for $3; + new__object_id alias for $4; + new__directory_p alias for $5; + new__pattern_p alias for $6; + new__creation_user alias for $7; + new__creation_ip alias for $8; + v_node_id site_nodes.node_id%TYPE; + v_directory_p site_nodes.directory_p%TYPE; +begin + if new__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 EXCEPTION ''%: %'', + -20000, + ''Node '' || new__parent_id || '' is not a directory''; + end if; + end if; + + v_node_id := acs_object__new ( + new__node_id, + ''site_node'', + now(), + new__creation_user, + new__creation_ip, + null + ); + + 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;' language 'plpgsql'; + + +-- procedure delete +create function site_node__delete (integer) +returns integer as ' +declare + delete__node_id alias for $1; +begin + delete from site_nodes + where node_id = delete__node_id; + + PERFORM acs_object__delete(delete__node_id); + + return 0; +end;' language 'plpgsql'; + + +-- function find_pattern +create function site_node__find_pattern (integer) +returns integer as ' +declare + find_pattern__node_id alias for $1; + 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; + raise exception ''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 find_pattern__node_id; + else + return site_node__find_pattern(v_parent_id); + end if; + +end;' language 'plpgsql'; + + +-- function node_id +create function site_node__node_id (varchar,integer) +returns integer as ' +declare + node_id__url alias for $1; + node_id__parent_id alias for $2; + v_pos integer; + v_first site_nodes.name%TYPE; + v_rest text; + v_node_id integer; + v_pattern_p site_nodes.pattern_p%TYPE; + v_url text; + v_directory_p site_nodes.directory_p%TYPE; + v_trailing_slash_p boolean; +begin + v_url := node_id__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 coalesce(parent_id, 3.14) = coalesce(node_id__parent_id, 3.14) + and coalesce(name, chr(10)) = coalesce(v_first, chr(10)); + if NOT FOUND then + return site_node__find_pattern(node_id__parent_id); + end if; + + if v_rest is null then + if v_trailing_slash_p = ''t'' and v_directory_p = ''f'' then + return site_node__find_pattern(node_id__parent_id); + else + return v_node_id; + end if; + else + return site_node__node_id(v_rest, v_node_id); + end if; + + +end;' language 'plpgsql'; + + +-- function url +create function site_node__url (integer) +returns varchar as ' +declare + url__node_id alias for $1; + v_parent_id site_nodes.node_id%TYPE; + v_name site_nodes.name%TYPE; + v_directory_p site_nodes.directory_p%TYPE; +begin + if url__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 site_node__url(v_parent_id) || v_name || ''/''; + else + return site_node__url(v_parent_id) || v_name; + end if; + +end;' language 'plpgsql'; + + + +-- show errors Index: openacs-4/packages/acs-kernel/sql/postgresql/site-nodes-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/site-nodes-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/site-nodes-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,20 @@ +-- +-- packages/acs-kernel/sql/site-nodes-drop.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-09-06 +-- @cvs-id site-nodes-drop.sql,v 1.5 2000/10/24 22:26:20 bquinn Exp +-- + +\t +select drop_package('site_node'); +drop table site_nodes; + +create function inline_0 () returns integer as ' +begin + PERFORM acs_object_type__drop_type (''site_node''); + returns null; +end;' language 'plpgsql'; +select inline_0 (); +drop function inline_0 (); +\t Index: openacs-4/packages/acs-kernel/sql/postgresql/tst.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/Attic/tst.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/tst.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,78 @@ + + + +select count(*) +where exists (select 1 + from acs_object_types t + where t.object_type = 'user' + connect by prior t.object_type = t.supertype + start with t.supertype = 'party'); + + +select count(*) +where exists (select 1 + from acs_object_types t + where t.object_type = 'user' + and sortkey like (select sortkey || '%' + from acs_object_types + where object_type = 'party')); + + +select object_type + from acs_object_types o1, acs_object_types o2 + where o1.object_type = (select object_type + from acs_objects o + where o.object_id = object_id_in) + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%') + order by tree_sortkey desc + +; + 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 + and t.tree_sortkey + like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = rt.object_type_one)) + and exists (select 1 + from acs_object_types t + where t.object_type = o2.object_type + and t.tree_sortkey + like (select o.tree_sortkey || '%' + from acs_object_types o + where o.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; + +select object_type + from acs_object_types o1, acs_object_types o2 + where o1.object_type = acs_rel_types.rel_type + and o2.tree_sortkey <= o1.tree_sortkey + and o1.tree_sortkey like (o2.tree_sortkey || '%') + order by tree_sortkey desc + + +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 + +select object_type as rel_type + from acs_object_types + where tree_sortkey like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = 'composition_rel') + or tree_sortkey like (select o.tree_sortkey || '%' + from acs_object_types o + where o.object_type = 'membership_rel'); + +start with object_type = 'membership_rel' + or object_type = 'composition_rel' + connect by supertype = prior object_type Index: openacs-4/packages/acs-kernel/sql/postgresql/utilities-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/utilities-create.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/utilities-create.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,109 @@ +-- +-- /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 utilities-create.sql,v 1.3 2000/11/02 17:55:51 yon 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 +-- function multiple_nextval +create function util__multiple_nextval (varchar,integer) +returns varchar as ' +declare + v_sequence_name alias for $1; + v_count alias for $2; + a_sequence_values text default ''''; + v_rec record; +begin + for counter in 1..v_count loop + for v_rec in EXECUTE ''select '' || quote_identifier(v_sequence_name) ''.nextval as a_seq_val'' + LOOP + a_sequence_values := a_sequence_values || '''','''' || v_rec.a_seq_val; + exit; + end loop; + end loop; + + return substr(a_sequence_values, 2); + +end;' language 'plpgsql'; + + -- 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[]'; + +create function RAWTOHEX(text) returns text as ' +declare + arg alias for $1; +begin + raise exception ''not implemented yet: depends on java code in acs classic''; + return ''''; +end;' language 'plpgsql'; + + +create function util__computehash_raw(text) returns text as ' +declare + arg alias for $1; +begin + raise exception ''not implemented yet: depends on java code in acs classic''; + return ''''; +end;' language 'plpgsql'; + + + -- The hashing function can be changed to MD5 by using computeMD5. + +create function util__computehash (varchar) returns varchar as ' +declare + v_value alias for $1; + v_hashed char(40); +begin + select RAWTOHEX(util__computehash_raw(v_value)) into v_hashed; + + return v_hashed; +end;' language 'plpgsql'; + + +create function util__logical_negation (boolean) returns boolean as ' +declare + true_or_false alias for $1; +begin + IF true_or_false is null THEN + return null; + ELSE IF true_or_false = ''f'' THEN + return ''t''; + ELSE + return ''f''; + END IF; END IF; +END;' language 'plpgsql'; + + Index: openacs-4/packages/acs-kernel/sql/postgresql/utilities-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/sql/postgresql/utilities-drop.sql,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-kernel/sql/postgresql/utilities-drop.sql 14 Mar 2001 04:39:10 -0000 1.1 @@ -0,0 +1,12 @@ +-- +-- /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 utilities-drop.sql,v 1.2 2000/09/19 07:23:29 ron Exp +-- +\t +select drop_package('util'); +\t