-- -- file-storage.sql -- -- created June 1999 by aure@arsdigita.com and dh@arsdigita.com -- -- modified January 2000 by randyg@arsdigita.com -- All permissions are now taken care of by the general-permissions module -- (general-permissions.sql). Permissions are per version. create sequence fs_file_id_seq; create table fs_files ( file_id integer primary key, file_title varchar(500) not null, -- sort_key and depth help us with displaying contents quickly sort_key integer not null, depth integer not null, folder_p char(1) default 'f' check (folder_p in ('t','f')), -- the group_id and public_p are used solely for display purposes -- if there is a group_id then we display this file under the group folder group_id integer references user_groups(group_id), -- if public_p is 't' we show the file in the public folder public_p char(1) default 'f' check (public_p in ('t','f')), -- if group_id is null and public_p <> 't' -- the folder or document is in the users' tree owner_id integer not null references users(user_id), deleted_p char(1) default 'f' check (deleted_p in ('t','f')), -- parent_id is null for top level items parent_id integer references fs_files(file_id) ); create function fs_files_tr() returns opaque as ' begin if new.parent_id = '''' then new.parent_id := null; end if; if new.group_id = '''' then new.group_id = null; end if; return new; end; ' language 'plpgsql'; create trigger fs_files_tr before insert or update on fs_files for each row execute procedure fs_files_tr(); -- need two indices to support CONNECT BY create index fs_files_idx1 on fs_files(file_id, parent_id); create index fs_files_idx2 on fs_files(parent_id, file_id); -- folders are also stored in fs_versions so that general_permissions can be -- wrapped around the folders as well. This way, is someone ever wants to -- put permissions on folders the functionality will already be in place. create sequence fs_version_id_seq; create table fs_versions ( version_id integer primary key, -- this is a version of the file key defined by file_key file_id integer not null references fs_files, -- this is where the actual content is stored -- POSTGRES: not sure what to do here! -- version_content blob, lob integer references lobs, -- description can be keywords, version notes, etc. version_description varchar(500), creation_date datetime not null, author_id integer not null references users(user_id), -- file name including extension but not path client_file_name varchar(500), file_type varchar(100), -- this is a MIME type (e.g., image/jpeg) file_extension varchar(50), -- e.g., "jpg" -- this value is null for the most recent version or equal to the id -- of the version that supersedes this one superseded_by_id integer references fs_versions(version_id), -- can be useful when deciding whether to present all of something n_bytes integer, -- added so we can store URLs url varchar(200) ); create trigger fs_versions_trigger before delete or update or insert on fs_versions for each row execute procedure on_lob_ref(); -- we'll often be asking "show me all the versions of file #4" create index fs_versions_by_file on fs_versions(file_id); create view fs_versions_latest as select * from fs_versions fs where fs.superseded_by_id is null; create function fs_node_is_child(integer,integer) returns char as ' declare start alias for $1; id alias for $2; pid integer; begin if id = start then return ''t''; end if; select into pid parent_id from fs_files where file_id = id; if pid is null then return ''f''; else if id = start then return ''t''; else return fs_node_is_child(start,pid); end if; end if; end; ' language 'plpgsql'; -- drop function fs_gen_key(integer); create function fs_gen_key(integer) returns varchar as ' declare id alias for $1; str varchar; len integer; begin str := ''0000000000'' || text(id); len := char_length(str); return substr(str,len - 9); end; ' language 'plpgsql'; -- drop function fs_connect_by(integer); create function fs_connect_by(integer) returns text as ' declare id alias for $1; pid integer; BEGIN select into pid parent_id from fs_files where id = file_id; IF pid is null THEN return fs_gen_key(id); ELSE return fs_connect_by(pid) || ''/'' || fs_gen_key(id); END IF; END; ' language 'plpgsql'; -- drop function fs_level_gen(integer,integer); create function fs_level_gen(integer,integer) returns integer as ' declare id alias for $1; cnt alias for $2; pid integer; BEGIN select into pid parent_id from fs_files where file_id = id; IF pid is null THEN return cnt; ELSE return fs_level_gen(pid,cnt+1); END IF; END; ' language 'plpgsql'; -- lets create an easy way to walk the tree so that we can join the connect by -- with the permissions tables --DRB: PG doesn't have connect by -- create view fs_files_tree -- as -- select -- file_id, -- file_title, -- sort_key, -- depth, -- folder_p, -- owner_id, -- deleted_p, -- group_id, -- public_p, -- parent_id, -- fs_level_gen(file_id,1) as the_level -- from fs_files -- order by fs_connect_by(file_id); -- connect by prior fs_files.file_id = parent_id -- start with parent_id is null; -- if you have Intermedia installed (Oracle 8i only + additional -- sysadmin/dbadmin nightmares) -- create index fs_versions_content_idx -- on fs_versions (version_content) -- indextype is ctxsys.context; -- Seed the general_permission_types table with data for -- administering permissions on this module (markc@arsdigita.com) -- insert into general_permission_types ( table_name, permission_type ) values ( 'FS_VERSIONS', 'read' ); insert into general_permission_types ( table_name, permission_type ) values ( 'FS_VERSIONS', 'write' ); insert into general_permission_types ( table_name, permission_type ) values ( 'FS_VERSIONS', 'comment' ); insert into general_permission_types ( table_name, permission_type ) values ( 'FS_VERSIONS', 'owner' );