Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-db.xml 30 Mar 2003 20:31:47 -0000 1.1.2.1 @@ -0,0 +1,283 @@ + + Setting Up Database Objects + + + by Joel Aufrecht + + + + Code the data model + We create all database objects with scripts in the + samplenote/sql/ directory. All + database scripts are database-specific and are thus in either + the samplenote/sql/oracle or + samplenote/sql/postgresql. + Packages can support Oracle, PostgreSQL, or both. + The first file is + samplenote-create.sql. The + package manager requires a file with the name + packagekey-create.sql, + which it will run automatically when the package in installed. + This file should create all tables and views. + + Our package is going to store all of its information in + one table. It takes more than just a CREATE + TABLE command, however, because we want to + integrate our table with the OpenACS system. By making each + record in our table an OpenACS object, we gain access to the + permissions system as well as some metadata. The downside is + that our table creation code must include several functions and + stored procedures and is fairly complicated even for a simple + table. A listing is provided below for you to cut and paste. + Comments are located within the source code, with each comment + preceeding the relevant code. + + First, create the necessary subdirectories and add them + cvs as you go. + [service0@yourserver samplenote]$ mkdir sql +[service0@yourserver samplenote]$ cvs add sql +Directory /cvsroot/service0/packages/samplenote/sql added to the repository +[service0@yourserver samplenote]$ cd sql/ +[service0@yourserver sql]$ mkdir postgresql +[service0@yourserver sql]$ cvs add postgresql +Directory /cvsroot/service0/packages/samplenote/sql/postgresql added to the repository +[service0@yourserver sql]$ cd postgresql/ +[service0@yourserver postgresql]$ emacs samplenote-create.sql + Paste this into the file and save and close. +
+ Database Creation Script + -- +-- packages/samplenote/sql/postgresql/samplenote-create.sql +-- +-- @author rhs@mit.edu +-- @creation-date 2000-10-22 +-- @cvs-id $Id: tutorial-db.xml,v 1.1.2.1 2003/03/30 20:31:47 joela Exp $ +-- +-- + +/* We create a temporary function 'inline_0' which we use to +create an ACS Object Type. Each record in our package is a +'samplenote', and each samplenote will be an ACS Object. By making +our records ACS objects, we gain access to the permissions model and +other meta-functions. Each 'samplenote' record will have a matching +record in acs_objects. In general, you should make a table an ACS +Object Type if you expect to apply permissions directly at that level. */ + +create function inline_0 () +returns integer as ' +begin + PERFORM acs_object_type__create_type ( + ''samplenote'', -- object_type + ''Sample Note'', -- pretty_name + ''Sample Notes'', -- pretty_plural + ''acs_object'', -- supertype + ''samplenote'', -- table_name + ''note_id'', -- id_column + null, -- package_name + ''f'', -- abstract_p + null, -- type_extension_table + ''samplenote__name'' -- name_method + ); + return 0; +end;' language 'plpgsql'; +select inline_0 (); +drop function inline_0 (); + +/* We create the table. Each constraint is named to make it easier to +identify during debugging. The note_id is identical to the object +id.*/ + +create table samplenote ( + note_id integer constraint samplenote_fk + references acs_objects(object_id) + constraint samplenote_pk + primary key, + title varchar(255) + constraint samplenote_title_nn + not null, + body varchar(1024) +); + +/* Since each record is also an Object, we make a creation function +that will create an object and then use the object id to create a +record in our table. The function also takes several optional input +variables. Creation date will default to now; creation user should be +the user id that will own the object; creation ip is optional; context +id should usually be the package id, which will be explained later.*/ + +create function samplenote__new (varchar,varchar,timestamp,integer,varchar,integer) +returns integer as ' +declare + p_title alias for $1; + p_body alias for $2; + p_creation_date alias for $3; + p_creation_user alias for $4; + p_creation_ip alias for $5; + p_context_id alias for $6; + v_samplenote_id int; +begin + v_samplenote_id := acs_object__new ( + null, + ''samplenote'', + p_creation_date, + p_creation_user, + p_creation_ip, + p_context_id + ); + insert into samplenote + (note_id, title, body) + values + (v_samplenote_id, p_title, p_body); + PERFORM acs_permission__grant_permission( + v_samplenote_id, + p_owner_id, + ''admin'' + ); + return v_samplenote_id; +end;' language 'plpgsql'; + +/* The __delete function deletes a record and all related overhead. */ + +create function samplenote__delete (integer) +returns integer as ' +declare + p_samplenote_id alias for $1; +begin + delete from acs_permissions + where object_id = p_samplenote_id; + delete from samplenote + where note_id = p_samplenote_id; + raise NOTICE ''Deleting samplenote...''; + PERFORM acs_object__delete(p_samplenote_id); + return 0; +end;' language 'plpgsql'; + +/* When we created the acs object type above, we specified a +'name_method'. This is the name of a function that will return the +name of the object. This is a convention ensuring that all objects +can be identified. Now we have to build that function. In this case, +we'll return a field called title as the name. */ + +create function samplenote__name (integer) +returns varchar as ' +declare + p_samplenote_id alias for $1; + v_samplenote_name samplenote.title%TYPE; +begin + select title into v_samplenote_name + from samplenote + where samplenote_id = p_samplenote_id; + return v_samplenote_name; +end; +' language 'plpgsql'; + +
+ Create a database file to drop everything if the package + is uninstalled. + [service0@yourserver postgresql]$ emacs samplenote-drop.sql +
+ Database deletion script + -- packages/samplenote/sql/samplenote-drop.sql +-- drop script +-- + +/* This script removes from the database everything associated with +our table. */ + +--drop functions +drop function samplenote__new (varchar,varchar,timestamp,integer,varchar,integer); +drop function samplenote__delete (integer); +drop function samplenote__name (integer); + +--drop permissions +delete from acs_permissions where object_id in (select note_id from samplenote); + +--drop objects +create function inline_0 () +returns integer as ' +declare + object_rec record; +begin + for object_rec in select object_id from acs_objects where object_type=''samplenote'' + loop + perform acs_object__delete( object_rec.object_id ); + end loop; + return 0; +end;' language 'plpgsql'; + +select inline_0(); +drop function inline_0(); + +--drop table +drop table samplenote; + +--drop type +select acs_object_type__drop_type( + 'samplenote', + 't' + ); +
+ Add the database files to cvs. + [service0@yourserver postgresql]$ cvs add *.sql +cvs add: scheduling file `samplenote-create.sql' for addition +cvs add: scheduling file `samplenote-drop.sql' for addition +cvs add: use 'cvs commit' to add these files permanently +[service0@yourserver samplenote]$ cvs commit -m "new database files" +cvs commit: Examining . +cvs commit: Examining sql +cvs commit: Examining sql/postgresql +cvs commit: Examining www +cvs commit: Examining www/doc +cvs commit: Examining www/doc/xml +RCS file: /cvsroot/service0/packages/samplenote/sql/postgresql/samplenote-create.sql,v +done +(many lines omitted) +done +[service0@yourserver samplenote]$ + Now run the create script manually to add your tables and functions. + [service0@yourserver samplenote]$ cd sql/postgresql/ +[service0@yourserver postgresql]$ psql -f samplenote-create.sql +CREATE + inline_0 +---------- + 0 +(1 row) + +DROP +psql:samplenote-create.sql:51: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'samplenote_pk' for table 'samplenote' +psql:samplenote-create.sql:51: NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +CREATE +CREATE +CREATE +CREATE +[service0@yourserver postgresql]$ + If there are errors, use them to debug the sql file and try again. Once you get the same output as shown above, test the drop script: + [service0@yourserver postgresql]$ psql -f samplenote-drop.sql +DROP +DROP +DROP +DELETE 0 +CREATE + inline_0 +---------- + 0 +(1 row) + +DROP +psql:samplenote-drop.sql:33: NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "acs_objects" +psql:samplenote-drop.sql:33: NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "acs_objects" +DROP + acs_object_type__drop_type +---------------------------- + 0 +(1 row) + +[service0@yourserver postgresql]$ + Once both scripts are working without errors, run the create script one last time and proceed. +
+
+